From ed8c97278961b7a44c312910276acb549abd3ccc Mon Sep 17 00:00:00 2001 From: Vincent Garnier Date: Mon, 1 Apr 2024 11:31:18 +0200 Subject: [PATCH] work on 4.0 --- rector.php | 36 ++++++---- src/Eloquent/DefaultOrderScope.php | 18 ++--- src/Eloquent/JoinRelBuilder.php | 12 ++-- src/Eloquent/Mixins/JoinRelMixin.php | 7 +- src/Eloquent/Mixins/WhereHasInMixin.php | 6 +- src/Eloquent/SoftDeletes.php | 7 +- src/ServiceProvider.php | 91 ++++++++++++++++++++++++- src/macros.php | 82 ---------------------- 8 files changed, 130 insertions(+), 129 deletions(-) delete mode 100644 src/macros.php diff --git a/rector.php b/rector.php index 8bf3f81..822771c 100644 --- a/rector.php +++ b/rector.php @@ -1,11 +1,13 @@ [__DIR__.'/src/Eloquent/Mixins'], + RemoveExtraParametersRector::class => [__DIR__.'/src/Eloquent/Mixins'], ]); - // $rectorConfig->rules([ - // EloquentWhereRelationTypeHintingParameterRector::class, - // EloquentWhereTypeHintClosureParameterRector::class, - // OptionalToNullsafeOperatorRector::class, - // RemoveDumpDataDeadCodeRector::class, - // ]); + $rectorConfig->rules([ + EloquentWhereRelationTypeHintingParameterRector::class, + EloquentWhereTypeHintClosureParameterRector::class, + OptionalToNullsafeOperatorRector::class, + RemoveDumpDataDeadCodeRector::class, + ]); $rectorConfig->sets([ - // LaravelSetList::LARAVEL_FACADE_ALIASES_TO_FULL_NAMES, + LaravelSetList::LARAVEL_FACADE_ALIASES_TO_FULL_NAMES, SetList::PHP_82, - // SetList::DEAD_CODE, - // SetList::CODE_QUALITY, - // SetList::CODING_STYLE, - // //SetList::NAMING, - // SetList::TYPE_DECLARATION, - // //SetList::PRIVATIZATION, - // SetList::EARLY_RETURN, - // SetList::INSTANCEOF, + SetList::DEAD_CODE, + SetList::CODE_QUALITY, + SetList::CODING_STYLE, + //SetList::NAMING, + SetList::TYPE_DECLARATION, + //SetList::PRIVATIZATION, + SetList::EARLY_RETURN, + SetList::INSTANCEOF, ]); }; diff --git a/src/Eloquent/DefaultOrderScope.php b/src/Eloquent/DefaultOrderScope.php index d594c58..27e10f4 100644 --- a/src/Eloquent/DefaultOrderScope.php +++ b/src/Eloquent/DefaultOrderScope.php @@ -9,10 +9,7 @@ class DefaultOrderScope implements Scope { - /** - * @var array - */ - protected $orders; + protected array $orders; /** * Constructor. @@ -24,10 +21,8 @@ public function __construct(array $orders) /** * Apply default "order by" clauses on query. - * - * @return void */ - public function apply(Builder $builder, Model $model) + public function apply(Builder $builder, Model $model): void { if ($builder->getQuery()->orders) { return; @@ -36,22 +31,17 @@ public function apply(Builder $builder, Model $model) foreach ($this->orders as $column => $option) { if (\is_int($column)) { $builder->orderBy($model->getTable().'.'.$option); - } elseif ($option === 'asc' || $option === 'desc') { $builder->orderBy($model->getTable().'.'.$column, $option); - } elseif ($option === 'natural' || $option === 'natural_asc') { $builder->orderByNatural($model->getTable().'.'.$column); - } elseif ($option === 'natural_desc') { $builder->orderByNatural($model->getTable().'.'.$column, 'desc'); - } elseif ($option === 'raw') { $builder->orderByRaw($column); - - } else { - throw new DefaultOrderException('Option "'.$option.'" not supported.'); } + + throw new DefaultOrderException('Option "'.$option.'" not supported.'); } } } diff --git a/src/Eloquent/JoinRelBuilder.php b/src/Eloquent/JoinRelBuilder.php index 12210b0..b4fe2e2 100644 --- a/src/Eloquent/JoinRelBuilder.php +++ b/src/Eloquent/JoinRelBuilder.php @@ -37,9 +37,8 @@ public function __construct(Model $model) * @param Closure|null $callback * @param string $type * @param bool $withTrashed - * @return void */ - public function apply(Builder $query, $relationName, $alias = null, $callback = null, $type = 'inner', $withTrashed = false) + public function apply(Builder $query, $relationName, $alias = null, $callback = null, $type = 'inner', $withTrashed = false): void { if (str_contains($relationName, '.')) { [$parentAlias, $relationName] = explode('.', $relationName); @@ -73,7 +72,7 @@ public function apply(Builder $query, $relationName, $alias = null, $callback = $relation->getRelated()->setTable($alias); $relation->getParent()->setTable($parentAlias); - $condition = function ($join) use ($relation, $callback, $withTrashed) { + $condition = function ($join) use ($relation, $callback, $withTrashed): void { $this->addCondition($join, $relation, $callback, $withTrashed); }; @@ -127,15 +126,12 @@ protected function addCondition(JoinClause $join, Relation $relation, $callback, /** * Adds extra "where" criteria to join clause. - * - * @param string $alias - * @return void */ - protected function addExtraCriteria(JoinClause $join, array $wheres, $alias) + protected function addExtraCriteria(JoinClause $join, array $wheres, string $alias): void { foreach ($wheres as $where) { if ($where['type'] === 'Nested') { - $join->where(function ($join) use ($where, $alias) { + $join->where(function (JoinClause $join) use ($where, $alias): void { $this->addExtraCriteria($join, $where['query']->wheres, $alias); }); } else { diff --git a/src/Eloquent/Mixins/JoinRelMixin.php b/src/Eloquent/Mixins/JoinRelMixin.php index 3dc6632..08bb58c 100644 --- a/src/Eloquent/Mixins/JoinRelMixin.php +++ b/src/Eloquent/Mixins/JoinRelMixin.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Builder; use WeakMap; +/** @mixin Builder */ class JoinRelMixin { /** @@ -17,7 +18,7 @@ class JoinRelMixin */ public function alias() { - return function ($alias) { + return function (string $alias): Builder { $this->model->setTable($alias); return $this->from((new $this->model())->getTable().' as '.$alias); @@ -30,11 +31,13 @@ public function alias() * @param string $relationName * @param string|null $alias * @param Closure|null $callback + * @param string $type + * @param bool $withTrashed * @return Builder */ public function joinRel() { - return function ($relationName, $alias = null, $callback = null, $type = 'inner', $withTrashed = false) { + return function (string $relationName, ?string $alias = null, ?string $callback = null, string $type = 'inner', bool $withTrashed = false): Builder { global $_joinRelBuildersWeakMap; if (! isset($_joinRelBuildersWeakMap)) { diff --git a/src/Eloquent/Mixins/WhereHasInMixin.php b/src/Eloquent/Mixins/WhereHasInMixin.php index a8d311e..e5ab267 100644 --- a/src/Eloquent/Mixins/WhereHasInMixin.php +++ b/src/Eloquent/Mixins/WhereHasInMixin.php @@ -4,12 +4,14 @@ use Axn\Illuminate\Database\Eloquent\Exceptions\WhereHasInException; use Closure; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasOneOrMany; use Illuminate\Database\Eloquent\Relations\Relation; +/** @mixin Builder */ class WhereHasInMixin { /** @@ -23,13 +25,13 @@ class WhereHasInMixin */ public function whereHasIn() { - return function ($relationName, ?Closure $callback = null, $boolean = 'and', $not = false) { + return function ($relationName, ?Closure $callback = null, $boolean = 'and', $not = false): Builder { $relation = Relation::noConstraints(fn () => $this->model->{$relationName}()); $relationSubQuery = $relation->getQuery(); - if ($callback !== null) { + if ($callback instanceof Closure) { $callback($relationSubQuery); } diff --git a/src/Eloquent/SoftDeletes.php b/src/Eloquent/SoftDeletes.php index f5b1679..d381358 100644 --- a/src/Eloquent/SoftDeletes.php +++ b/src/Eloquent/SoftDeletes.php @@ -14,9 +14,8 @@ trait SoftDeletes * (these records will be retrieved even if they are trashed). * * @param int|array[int] $exceptId - * @return void */ - public function scopeWithoutTrashedExcept(Builder $query, $exceptId = null) + public function scopeWithoutTrashedExcept(Builder $query, $exceptId = null): void { // Replaced : // $query->where(function ($query) use ($exceptId) { @@ -25,10 +24,10 @@ public function scopeWithoutTrashedExcept(Builder $query, $exceptId = null) // // If we do not do that, the builder loses his scopes... - $query->where(function () use ($query, $exceptId) { + $query->where(function () use ($query, $exceptId): void { $query ->withoutTrashed() - ->when($exceptId, function ($query, $exceptId) { + ->when($exceptId, function ($query, $exceptId): void { if (\is_array($exceptId)) { $query->orWhereIn($this->getQualifiedKeyName(), $exceptId); } else { diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index ef32c1a..2271fde 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -2,12 +2,99 @@ namespace Axn\Illuminate\Database; +use Axn\Illuminate\Database\Eloquent\Mixins\JoinRelMixin; +use Axn\Illuminate\Database\Eloquent\Mixins\WhereHasInMixin; +use Illuminate\Database\Eloquent\Builder as EloquentBuilder; +use Illuminate\Database\Query\Builder as QueryBuilder; +use Illuminate\Support\Arr; use Illuminate\Support\ServiceProvider as BaseServiceProvider; +use Illuminate\Support\Str; class ServiceProvider extends BaseServiceProvider { - public function boot() + public function boot(): void { - require __DIR__.'/macros.php'; + $this->extendsQueryBuilder(); + $this->extendsEloquentBuilder(); + } + + private function extendsQueryBuilder(): void + { + /** + * Natural sorting. + * + * @see http://kumaresan-drupal.blogspot.fr/2012/09/natural-sorting-in-mysql-or.html + * + * @param string $column + * @param string $direction + * @return QueryBuilder + */ + QueryBuilder::macro( + 'orderByNatural', + function ($column, $direction = 'asc') { + $column = $this->grammar->wrap($column); + $direction = strtolower($direction) === 'asc' ? 'asc' : 'desc'; + + return $this->orderByRaw( + $column.' + 0 <> 0 '.($direction === 'asc' ? 'desc' : 'asc').', ' + .sprintf('%s + 0 %s, ', $column, $direction) + .sprintf('length(%s) %s, ', $column, $direction) + .sprintf('%s %s', $column, $direction) + ); + } + ); + + /** + * Natural sorting, descendant. + * + * @param string $column + * @return QueryBuilder + */ + QueryBuilder::macro( + 'orderByNaturalDesc', + fn ($column) => $this->orderByNatural($column, 'desc') + ); + } + + private function extendsEloquentBuilder(): void + { + /** + * Searching models using a where like query. + * + * @see https://freek.dev/1182-searching-models-using-a-where-like-query-in-laravel + * + * @param string|array $attributes + * @param string $searchTerm + * @return EloquentBuilder + */ + EloquentBuilder::macro( + 'whereLike', + function ($attributes, $searchTerm) { + $searchTerm = str_replace(' ', '%', $searchTerm); + + $this->where(function (EloquentBuilder $query) use ($attributes, $searchTerm): void { + foreach (Arr::wrap($attributes) as $attribute) { + if (Str::contains($attribute, '.')) { + [$relationName, $relationAttribute] = explode('.', $attribute); + + $query->orWhereHas($relationName, function (EloquentBuilder $query) use ($relationAttribute, $searchTerm): void { + $query->where($relationAttribute, 'like', '%'.$searchTerm.'%'); + }); + } else { + $query->orWhere($attribute, 'like', '%'.$searchTerm.'%'); + } + } + }); + + return $this; + } + ); + + // Registering macros using mixin classes + // https://liamhammett.com/laravel-mixins-KEzjmLrx + + EloquentBuilder::mixin(new JoinRelMixin()); + + EloquentBuilder::mixin(new WhereHasInMixin()); } } diff --git a/src/macros.php b/src/macros.php deleted file mode 100644 index f9df1b7..0000000 --- a/src/macros.php +++ /dev/null @@ -1,82 +0,0 @@ -grammar->wrap($column); - $direction = strtolower($direction) === 'asc' ? 'asc' : 'desc'; - - return $this->orderByRaw( - "$column + 0 <> 0 ".($direction === 'asc' ? 'desc' : 'asc').', ' - ."$column + 0 $direction, " - ."length($column) $direction, " - ."$column $direction" - ); - } -); - -/** - * Natural sorting, descendant. - * - * @param string $column - * @return \Illuminate\Database\Query\Builder - */ -QueryBuilder::macro( - 'orderByNaturalDesc', - fn ($column) => $this->orderByNatural($column, 'desc') -); - -/** - * Searching models using a where like query. - * - * @see https://freek.dev/1182-searching-models-using-a-where-like-query-in-laravel - * - * @param string|array $attributes - * @param string $searchTerm - * @return \Illuminate\Database\Query\Builder - */ -EloquentBuilder::macro( - 'whereLike', - function ($attributes, $searchTerm) { - $searchTerm = str_replace(' ', '%', $searchTerm); - - $this->where(function (EloquentBuilder $query) use ($attributes, $searchTerm) { - foreach (Arr::wrap($attributes) as $attribute) { - if (Str::contains($attribute, '.')) { - [$relationName, $relationAttribute] = explode('.', $attribute); - - $query->orWhereHas($relationName, function (EloquentBuilder $query) use ($relationAttribute, $searchTerm) { - $query->where($relationAttribute, 'like', "%{$searchTerm}%"); - }); - } else { - $query->orWhere($attribute, 'like', "%{$searchTerm}%"); - } - } - }); - - return $this; - } -); - -// Registering macros using mixin classes -// https://liamhammett.com/laravel-mixins-KEzjmLrx - -EloquentBuilder::mixin(new JoinRelMixin()); - -EloquentBuilder::mixin(new WhereHasInMixin());