diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 00000000..9979744a --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,26 @@ +name: PHPStan + +on: + push: + paths: + - '**.php' + - 'phpstan.neon.dist' + +jobs: + phpstan: + name: phpstan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + + - name: Install composer dependencies + uses: ramsey/composer-install@v2 + + - name: Run PHPStan + run: ./vendor/bin/phpstan --error-format=github diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 088ac821..6978a60f 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -25,6 +25,7 @@ jobs: testbench: 9.* carbon: ^2.63 - laravel: 10.* + php: 8.0 testbench: 8.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} @@ -52,8 +53,6 @@ jobs: --health-retries 5 steps: - - - name: Checkout code uses: actions/checkout@v4 diff --git a/composer.json b/composer.json index b8fc724a..3167ab0b 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,10 @@ "require-dev": { "ext-json": "*", "mockery/mockery": "^1.4", + "nunomaduro/larastan": "^2.0", "orchestra/testbench": "^7.0|^8.0", + "phpunit/phpunit": "^9.6.11", + "rector/rector": "^0.18.10", "pestphp/pest": "^2.0", "spatie/invade": "^2.0", "spatie/laravel-ray": "^1.28" @@ -47,7 +50,9 @@ }, "scripts": { "test": "vendor/bin/pest", - "test-coverage": "phpunit --coverage-html coverage" + "test-coverage": "phpunit --coverage-html coverage", + "analyse": "vendor/bin/phpstan analyse --ansi --memory-limit=4G", + "baseline": "vendor/bin/phpstan analyse --generate-baseline --memory-limit=4G" }, "config": { "sort-packages": true, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 00000000..85249926 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,36 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$keys of method Illuminate\\\\Support\\\\Collection\\\\:\\:except\\(\\) expects array\\\\|Illuminate\\\\Support\\\\Enumerable\\<\\(int\\|string\\), int\\>\\|string, int\\<\\-1, max\\> given\\.$#" + count: 1 + path: src/Filters/FiltersExact.php + + - + message: "#^Call to an undefined method ReflectionType\\:\\:getName\\(\\)\\.$#" + count: 2 + path: src/Filters/FiltersScope.php + + - + message: "#^Call to an undefined method ReflectionType\\:\\:isBuiltin\\(\\)\\.$#" + count: 1 + path: src/Filters/FiltersScope.php + + - + message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\\\:\\:onlyTrashed\\(\\)\\.$#" + count: 1 + path: src/Filters/FiltersTrashed.php + + - + message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\\\:\\:withTrashed\\(\\)\\.$#" + count: 1 + path: src/Filters/FiltersTrashed.php + + - + message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\\\:\\:withoutTrashed\\(\\)\\.$#" + count: 1 + path: src/Filters/FiltersTrashed.php + + - + message: "#^PHPDoc tag @return with type Spatie\\\\QueryBuilder\\\\QueryBuilder is not subtype of native type static\\(Spatie\\\\QueryBuilder\\\\QueryBuilder\\)\\.$#" + count: 2 + path: src/QueryBuilder.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..c590d9e3 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,28 @@ +includes: + - ./vendor/nunomaduro/larastan/extension.neon + - phpstan-baseline.neon + +parameters: + + paths: + - src/ + - config/ + - database/ + + # Level 9 is the highest level + level: 5 + + checkModelProperties: true + checkOctaneCompatibility: true + checkMissingIterableValueType: false + reportUnmatchedIgnoredErrors: false + noUnnecessaryCollectionCall: true + checkNullables: true + checkGenericClassInNonGenericObjectType: false + treatPhpDocTypesAsCertain: false + + ignoreErrors: + - '#Unsafe usage of new static#' + - '#PHPDoc tag @var#' + +# excludePaths: diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..afb0ea81 --- /dev/null +++ b/rector.php @@ -0,0 +1,30 @@ +paths([ + __DIR__ . '/config', + __DIR__ . '/src', + __DIR__ . '/tests', + ]); + + // register a single rule + //$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); + + // define sets of rules + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_80 + ]); + + $rectorConfig->skip([ + ClosureToArrowFunctionRector::class, + NullCoalescingOperatorRector::class, + ]); +}; diff --git a/src/AllowedFilter.php b/src/AllowedFilter.php index 7c0ac0cd..7383ea89 100644 --- a/src/AllowedFilter.php +++ b/src/AllowedFilter.php @@ -14,39 +14,30 @@ class AllowedFilter { - /** @var Filter */ - protected $filterClass; + protected string $internalName; - /** @var string */ - protected $name; + protected Filter $filterClass; - /** @var string */ - protected $internalName; - - /** @var \Illuminate\Support\Collection */ - protected $ignored; + protected Collection $ignored; /** @var mixed */ protected $default; - /** @var bool */ - protected $hasDefault = false; - - /** @var bool */ - protected $nullable = false; - - public function __construct(string $name, Filter $filterClass, ?string $internalName = null) - { - $this->name = $name; + protected bool $hasDefault = false; - $this->filterClass = $filterClass; + protected bool $nullable = false; + public function __construct( + protected string $name, + protected Filter $filterClass, + ?string $internalName = null + ) { $this->ignored = Collection::make(); $this->internalName = $internalName ?? $name; } - public function filter(QueryBuilder $query, $value) + public function filter(QueryBuilder $query, $value): void { $valueToFilter = $this->resolveValueForFiltering($value); diff --git a/src/AllowedInclude.php b/src/AllowedInclude.php index cce9b06b..df07303a 100644 --- a/src/AllowedInclude.php +++ b/src/AllowedInclude.php @@ -13,19 +13,13 @@ class AllowedInclude { - /** @var string */ - protected $name; + protected string $internalName; - /** @var IncludeInterface */ - protected $includeClass; - - /** @var string|null */ - protected $internalName; - - public function __construct(string $name, IncludeInterface $includeClass, ?string $internalName = null) - { - $this->name = $name; - $this->includeClass = $includeClass; + public function __construct( + protected string $name, + protected IncludeInterface $includeClass, + ?string $internalName = null + ) { $this->internalName = $internalName ?? $this->name; } diff --git a/src/AllowedSort.php b/src/AllowedSort.php index 816c3c3f..a94f71e7 100644 --- a/src/AllowedSort.php +++ b/src/AllowedSort.php @@ -10,24 +10,14 @@ class AllowedSort { - /** @var \Spatie\QueryBuilder\Sorts\Sort */ - protected $sortClass; + protected string $defaultDirection; - /** @var string */ - protected $name; + protected string $internalName; - /** @var string */ - protected $defaultDirection; - - /** @var string */ - protected $internalName; - - public function __construct(string $name, Sort $sortClass, ?string $internalName = null) + public function __construct(protected string $name, protected Sort $sortClass, ?string $internalName = null) { $this->name = ltrim($name, '-'); - $this->sortClass = $sortClass; - $this->defaultDirection = static::parseSortDirection($name); $this->internalName = $internalName ?? $this->name; @@ -35,7 +25,7 @@ public function __construct(string $name, Sort $sortClass, ?string $internalName public static function parseSortDirection(string $name): string { - return strpos($name, '-') === 0 ? SortDirection::DESCENDING : SortDirection::ASCENDING; + return str_starts_with($name, '-') ? SortDirection::DESCENDING : SortDirection::ASCENDING; } public function sort(QueryBuilder $query, ?bool $descending = null): void @@ -75,7 +65,7 @@ public function getInternalName(): string return $this->internalName; } - public function defaultDirection(string $defaultDirection) + public function defaultDirection(string $defaultDirection): static { if (! in_array($defaultDirection, [ SortDirection::ASCENDING, diff --git a/src/Concerns/AddsFieldsToQuery.php b/src/Concerns/AddsFieldsToQuery.php index 71b26f58..120c000e 100644 --- a/src/Concerns/AddsFieldsToQuery.php +++ b/src/Concerns/AddsFieldsToQuery.php @@ -32,7 +32,7 @@ public function allowedFields($fields): static return $this; } - protected function addRequestedModelFieldsToQuery() + protected function addRequestedModelFieldsToQuery(): void { $modelTableName = $this->getModel()->getTable(); @@ -72,7 +72,7 @@ public function getRequestedFieldsForRelatedTable(string $relation): array return $fields; } - protected function ensureAllFieldsExist() + protected function ensureAllFieldsExist(): void { $modelTable = $this->getModel()->getTable(); diff --git a/src/Concerns/AddsIncludesToQuery.php b/src/Concerns/AddsIncludesToQuery.php index 11f4c554..1dee0ca5 100644 --- a/src/Concerns/AddsIncludesToQuery.php +++ b/src/Concerns/AddsIncludesToQuery.php @@ -52,12 +52,12 @@ public function allowedIncludes($includes): static return $this; } - protected function addIncludesToQuery(Collection $includes) + protected function addIncludesToQuery(Collection $includes): void { $includes->each(function ($include) { $include = $this->findInclude($include); - $include->include($this); + $include?->include($this); }); } @@ -69,7 +69,7 @@ protected function findInclude(string $include): ?AllowedInclude }); } - protected function ensureAllIncludesExist() + protected function ensureAllIncludesExist(): void { if (config('query-builder.disable_invalid_includes_query_exception', false)) { return; @@ -77,7 +77,7 @@ protected function ensureAllIncludesExist() $includes = $this->request->includes(); - $allowedIncludeNames = $this->allowedIncludes->map(function (AllowedInclude $allowedInclude) { + $allowedIncludeNames = $this->allowedIncludes?->map(function (AllowedInclude $allowedInclude) { return $allowedInclude->getName(); }); diff --git a/src/Concerns/FiltersQuery.php b/src/Concerns/FiltersQuery.php index 58183421..9e932c23 100644 --- a/src/Concerns/FiltersQuery.php +++ b/src/Concerns/FiltersQuery.php @@ -2,13 +2,13 @@ namespace Spatie\QueryBuilder\Concerns; +use Illuminate\Support\Collection; use Spatie\QueryBuilder\AllowedFilter; use Spatie\QueryBuilder\Exceptions\InvalidFilterQuery; trait FiltersQuery { - /** @var \Illuminate\Support\Collection */ - protected $allowedFilters; + protected Collection $allowedFilters; public function allowedFilters($filters): static { @@ -29,7 +29,7 @@ public function allowedFilters($filters): static return $this; } - protected function addFiltersToQuery() + protected function addFiltersToQuery(): void { $this->allowedFilters->each(function (AllowedFilter $filter) { if ($this->isFilterRequested($filter)) { @@ -41,8 +41,6 @@ protected function addFiltersToQuery() if ($filter->hasDefault()) { $filter->filter($this, $filter->getDefault()); - - return; } }); } @@ -60,7 +58,7 @@ protected function isFilterRequested(AllowedFilter $allowedFilter): bool return $this->request->filters()->has($allowedFilter->getName()); } - protected function ensureAllFiltersExist() + protected function ensureAllFiltersExist(): void { if (config('query-builder.disable_invalid_filter_query_exception', false)) { return; diff --git a/src/Concerns/SortsQuery.php b/src/Concerns/SortsQuery.php index b3b68b04..d56ebbea 100644 --- a/src/Concerns/SortsQuery.php +++ b/src/Concerns/SortsQuery.php @@ -2,13 +2,13 @@ namespace Spatie\QueryBuilder\Concerns; +use Illuminate\Support\Collection; use Spatie\QueryBuilder\AllowedSort; use Spatie\QueryBuilder\Exceptions\InvalidSortQuery; trait SortsQuery { - /** @var \Illuminate\Support\Collection */ - protected $allowedSorts; + protected Collection $allowedSorts; public function allowedSorts($sorts): static { @@ -71,7 +71,7 @@ public function defaultSorts($sorts): static return $this; } - protected function addRequestedSortsToQuery() + protected function addRequestedSortsToQuery(): void { $this->request->sorts() ->each(function (string $property) { diff --git a/src/Exceptions/InvalidAppendQuery.php b/src/Exceptions/InvalidAppendQuery.php index 04082953..6a512644 100644 --- a/src/Exceptions/InvalidAppendQuery.php +++ b/src/Exceptions/InvalidAppendQuery.php @@ -7,17 +7,10 @@ class InvalidAppendQuery extends InvalidQuery { - /** @var \Illuminate\Support\Collection */ - public $appendsNotAllowed; - - /** @var \Illuminate\Support\Collection */ - public $allowedAppends; - - public function __construct(Collection $appendsNotAllowed, Collection $allowedAppends) - { - $this->appendsNotAllowed = $appendsNotAllowed; - $this->allowedAppends = $allowedAppends; - + public function __construct( + public Collection $appendsNotAllowed, + public Collection $allowedAppends + ) { $appendsNotAllowed = $appendsNotAllowed->implode(', '); $allowedAppends = $allowedAppends->implode(', '); $message = "Requested append(s) `{$appendsNotAllowed}` are not allowed. Allowed append(s) are `{$allowedAppends}`."; @@ -25,7 +18,7 @@ public function __construct(Collection $appendsNotAllowed, Collection $allowedAp parent::__construct(Response::HTTP_BAD_REQUEST, $message); } - public static function appendsNotAllowed(Collection $appendsNotAllowed, Collection $allowedAppends) + public static function appendsNotAllowed(Collection $appendsNotAllowed, Collection $allowedAppends): static { return new static(...func_get_args()); } diff --git a/src/Exceptions/InvalidFieldQuery.php b/src/Exceptions/InvalidFieldQuery.php index bc89d6cc..77d22866 100644 --- a/src/Exceptions/InvalidFieldQuery.php +++ b/src/Exceptions/InvalidFieldQuery.php @@ -7,17 +7,10 @@ class InvalidFieldQuery extends InvalidQuery { - /** @var \Illuminate\Support\Collection */ - public $unknownFields; - - /** @var \Illuminate\Support\Collection */ - public $allowedFields; - - public function __construct(Collection $unknownFields, Collection $allowedFields) - { - $this->unknownFields = $unknownFields; - $this->allowedFields = $allowedFields; - + public function __construct( + public Collection $unknownFields, + public Collection $allowedFields + ) { $unknownFields = $unknownFields->implode(', '); $allowedFields = $allowedFields->implode(', '); $message = "Requested field(s) `{$unknownFields}` are not allowed. Allowed field(s) are `{$allowedFields}`."; @@ -25,7 +18,7 @@ public function __construct(Collection $unknownFields, Collection $allowedFields parent::__construct(Response::HTTP_BAD_REQUEST, $message); } - public static function fieldsNotAllowed(Collection $unknownFields, Collection $allowedFields) + public static function fieldsNotAllowed(Collection $unknownFields, Collection $allowedFields): static { return new static(...func_get_args()); } diff --git a/src/Exceptions/InvalidFilterQuery.php b/src/Exceptions/InvalidFilterQuery.php index 8e6c8766..9281bd8f 100644 --- a/src/Exceptions/InvalidFilterQuery.php +++ b/src/Exceptions/InvalidFilterQuery.php @@ -7,17 +7,10 @@ class InvalidFilterQuery extends InvalidQuery { - /** @var \Illuminate\Support\Collection */ - public $unknownFilters; - - /** @var \Illuminate\Support\Collection */ - public $allowedFilters; - - public function __construct(Collection $unknownFilters, Collection $allowedFilters) - { - $this->unknownFilters = $unknownFilters; - $this->allowedFilters = $allowedFilters; - + public function __construct( + public Collection $unknownFilters, + public Collection $allowedFilters + ) { $unknownFilters = $this->unknownFilters->implode(', '); $allowedFilters = $this->allowedFilters->implode(', '); $message = "Requested filter(s) `{$unknownFilters}` are not allowed. Allowed filter(s) are `{$allowedFilters}`."; @@ -25,7 +18,7 @@ public function __construct(Collection $unknownFilters, Collection $allowedFilte parent::__construct(Response::HTTP_BAD_REQUEST, $message); } - public static function filtersNotAllowed(Collection $unknownFilters, Collection $allowedFilters) + public static function filtersNotAllowed(Collection $unknownFilters, Collection $allowedFilters): static { return new static(...func_get_args()); } diff --git a/src/Exceptions/InvalidFilterValue.php b/src/Exceptions/InvalidFilterValue.php index 473568a6..a01d636e 100644 --- a/src/Exceptions/InvalidFilterValue.php +++ b/src/Exceptions/InvalidFilterValue.php @@ -6,7 +6,7 @@ class InvalidFilterValue extends Exception { - public static function make($value) + public static function make($value): static { return new static("Filter value `{$value}` is invalid."); } diff --git a/src/Exceptions/InvalidIncludeQuery.php b/src/Exceptions/InvalidIncludeQuery.php index c214ae21..4540e8f1 100644 --- a/src/Exceptions/InvalidIncludeQuery.php +++ b/src/Exceptions/InvalidIncludeQuery.php @@ -7,17 +7,10 @@ class InvalidIncludeQuery extends InvalidQuery { - /** @var \Illuminate\Support\Collection */ - public $unknownIncludes; - - /** @var \Illuminate\Support\Collection */ - public $allowedIncludes; - - public function __construct(Collection $unknownIncludes, Collection $allowedIncludes) - { - $this->unknownIncludes = $unknownIncludes; - $this->allowedIncludes = $allowedIncludes; - + public function __construct( + public Collection $unknownIncludes, + public Collection $allowedIncludes + ) { $unknownIncludes = $unknownIncludes->implode(', '); $message = "Requested include(s) `{$unknownIncludes}` are not allowed. "; @@ -32,7 +25,7 @@ public function __construct(Collection $unknownIncludes, Collection $allowedIncl parent::__construct(Response::HTTP_BAD_REQUEST, $message); } - public static function includesNotAllowed(Collection $unknownIncludes, Collection $allowedIncludes) + public static function includesNotAllowed(Collection $unknownIncludes, Collection $allowedIncludes): static { return new static(...func_get_args()); } diff --git a/src/Exceptions/InvalidSortQuery.php b/src/Exceptions/InvalidSortQuery.php index ae4219ed..dc952961 100644 --- a/src/Exceptions/InvalidSortQuery.php +++ b/src/Exceptions/InvalidSortQuery.php @@ -7,25 +7,19 @@ class InvalidSortQuery extends InvalidQuery { - /** @var \Illuminate\Support\Collection */ - public $unknownSorts; - - /** @var \Illuminate\Support\Collection */ - public $allowedSorts; - - public function __construct(Collection $unknownSorts, Collection $allowedSorts) - { - $this->unknownSorts = $unknownSorts; - $this->allowedSorts = $allowedSorts; - + public function __construct( + public Collection $unknownSorts, + public Collection $allowedSorts + ) { $allowedSorts = $allowedSorts->implode(', '); $unknownSorts = $unknownSorts->implode(', '); + $message = "Requested sort(s) `{$unknownSorts}` is not allowed. Allowed sort(s) are `{$allowedSorts}`."; parent::__construct(Response::HTTP_BAD_REQUEST, $message); } - public static function sortsNotAllowed(Collection $unknownSorts, Collection $allowedSorts) + public static function sortsNotAllowed(Collection $unknownSorts, Collection $allowedSorts): static { return new static(...func_get_args()); } diff --git a/src/Exceptions/InvalidSubject.php b/src/Exceptions/InvalidSubject.php deleted file mode 100644 index 3a4130a1..00000000 --- a/src/Exceptions/InvalidSubject.php +++ /dev/null @@ -1,20 +0,0 @@ -addRelationConstraint = $addRelationConstraint; } /** {@inheritdoc} */ @@ -62,7 +58,7 @@ protected function isRelationProperty(Builder $query, string $property): bool return is_a($query->getModel()->{$firstRelationship}(), Relation::class); } - protected function withRelationConstraint(Builder $query, $value, string $property) + protected function withRelationConstraint(Builder $query, mixed $value, string $property): void { [$relation, $property] = collect(explode('.', $property)) ->pipe(function (Collection $parts) { diff --git a/src/Filters/FiltersPartial.php b/src/Filters/FiltersPartial.php index 21953ac5..49b3a3ec 100644 --- a/src/Filters/FiltersPartial.php +++ b/src/Filters/FiltersPartial.php @@ -48,7 +48,8 @@ protected function getDatabaseDriver(Builder $query): string return $query->getConnection()->getDriverName(); } - protected function getWhereRawParameters($value, string $property, string $driver): array + + protected function getWhereRawParameters(mixed $value, string $property, string $driver): array { $value = mb_strtolower((string) $value, 'UTF8'); diff --git a/src/Filters/FiltersScope.php b/src/Filters/FiltersScope.php index 382dbd09..c2793dcc 100644 --- a/src/Filters/FiltersScope.php +++ b/src/Filters/FiltersScope.php @@ -49,7 +49,7 @@ protected function resolveParameters(Builder $query, $values, string $scope): ar $parameters = (new ReflectionObject($query->getModel())) ->getMethod('scope' . ucfirst($scope)) ->getParameters(); - } catch (ReflectionException $e) { + } catch (ReflectionException) { return $values; } @@ -58,7 +58,8 @@ protected function resolveParameters(Builder $query, $values, string $scope): ar continue; } - $model = $this->getClass($parameter)->newInstance(); + /** @var TModelClass $model */ + $model = $this->getClass($parameter)?->newInstance(); $index = $parameter->getPosition() - 1; $value = $values[$index]; diff --git a/src/Includes/IncludeInterface.php b/src/Includes/IncludeInterface.php index 4590621a..cca4d6dc 100644 --- a/src/Includes/IncludeInterface.php +++ b/src/Includes/IncludeInterface.php @@ -10,10 +10,9 @@ interface IncludeInterface { /** - * @param \Illuminate\Database\Eloquent\Builder $query - * @param string $include - * - * @return mixed - */ + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return mixed + */ public function __invoke(Builder $query, string $include); } diff --git a/src/Includes/IncludedCallback.php b/src/Includes/IncludedCallback.php index 51e683f6..23af8e86 100644 --- a/src/Includes/IncludedCallback.php +++ b/src/Includes/IncludedCallback.php @@ -7,11 +7,8 @@ class IncludedCallback implements IncludeInterface { - protected Closure $callback; - - public function __construct(Closure $callback) + public function __construct(protected Closure $callback) { - $this->callback = $callback; } public function __invoke(Builder $query, string $relation) diff --git a/src/Includes/IncludedRelationship.php b/src/Includes/IncludedRelationship.php index 4ea74491..0df9e279 100644 --- a/src/Includes/IncludedRelationship.php +++ b/src/Includes/IncludedRelationship.php @@ -16,7 +16,7 @@ public function __invoke(Builder $query, string $relationship) $relatedTables = collect(explode('.', $relationship)); $withs = $relatedTables - ->mapWithKeys(function ($table, $key) use ($query, $relatedTables) { + ->mapWithKeys(function ($table, $key) use ($relatedTables) { $fullRelationName = $relatedTables->slice(0, $key + 1)->implode('.'); if ($this->getRequestedFieldsForRelatedTable) { diff --git a/src/QueryBuilder.php b/src/QueryBuilder.php index 93e9a702..80366e85 100755 --- a/src/QueryBuilder.php +++ b/src/QueryBuilder.php @@ -12,7 +12,6 @@ use Spatie\QueryBuilder\Concerns\AddsIncludesToQuery; use Spatie\QueryBuilder\Concerns\FiltersQuery; use Spatie\QueryBuilder\Concerns\SortsQuery; -use Spatie\QueryBuilder\Exceptions\InvalidSubject; /** * @mixin EloquentBuilder @@ -25,46 +24,15 @@ class QueryBuilder implements ArrayAccess use AddsFieldsToQuery; use ForwardsCalls; - /** @var \Spatie\QueryBuilder\QueryBuilderRequest */ - protected $request; + protected QueryBuilderRequest $request; - /** @var \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation */ - protected $subject; - - /** - * @param \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation $subject - * @param null|\Illuminate\Http\Request $request - */ - public function __construct($subject, ?Request $request = null) - { - $this->initializeSubject($subject) - ->initializeRequest($request ?? app(Request::class)); - } - - /** - * @param \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation $subject - * - * @return $this - */ - protected function initializeSubject($subject): static - { - throw_unless( - $subject instanceof EloquentBuilder || $subject instanceof Relation, - InvalidSubject::make($subject) - ); - - $this->subject = $subject; - - return $this; - } - - protected function initializeRequest(?Request $request = null): static - { + public function __construct( + protected EloquentBuilder|Relation $subject, + ?Request $request = null + ) { $this->request = $request ? QueryBuilderRequest::fromRequest($request) : app(QueryBuilderRequest::class); - - return $this; } public function getEloquentBuilder(): EloquentBuilder @@ -73,26 +41,18 @@ public function getEloquentBuilder(): EloquentBuilder return $this->subject; } - if ($this->subject instanceof Relation) { - return $this->subject->getQuery(); - } - - throw InvalidSubject::make($this->subject); + return $this->subject->getQuery(); } - public function getSubject() + public function getSubject(): Relation|EloquentBuilder { return $this->subject; } - /** - * @param EloquentBuilder|Relation|string $subject - * @param Request|null $request - * - * @return static - */ - public static function for($subject, ?Request $request = null): static - { + public static function for( + EloquentBuilder|Relation|string $subject, + ?Request $request = null + ): static { if (is_subclass_of($subject, Model::class)) { $subject = $subject::query(); } @@ -115,7 +75,7 @@ public function __call($name, $arguments) return $result; } - public function clone() + public function clone(): static { return clone $this; } diff --git a/src/QueryBuilderRequest.php b/src/QueryBuilderRequest.php index 2f4d999f..e2f30e14 100644 --- a/src/QueryBuilderRequest.php +++ b/src/QueryBuilderRequest.php @@ -8,15 +8,15 @@ class QueryBuilderRequest extends Request { - private static $includesArrayValueDelimiter = ','; + protected static string $includesArrayValueDelimiter = ','; - private static $appendsArrayValueDelimiter = ','; + protected static string $appendsArrayValueDelimiter = ','; - private static $fieldsArrayValueDelimiter = ','; + protected static string $fieldsArrayValueDelimiter = ','; - private static $sortsArrayValueDelimiter = ','; + protected static string $sortsArrayValueDelimiter = ','; - private static $filterArrayValueDelimiter = ','; + protected static string $filterArrayValueDelimiter = ','; public static function setArrayValueDelimiter(string $delimiter): void { @@ -123,12 +123,8 @@ public function filters(): Collection }); } - /** - * @param $value - * - * @return array|bool|null - */ - protected function getFilterValue($value) + /** @return array|float|int|string|bool|null */ + protected function getFilterValue(mixed $value): mixed { if (empty($value)) { return $value; diff --git a/src/QueryBuilderServiceProvider.php b/src/QueryBuilderServiceProvider.php index c7e7b199..da8b9313 100644 --- a/src/QueryBuilderServiceProvider.php +++ b/src/QueryBuilderServiceProvider.php @@ -14,14 +14,14 @@ public function configurePackage(Package $package): void ->hasConfigFile(); } - public function registeringPackage() + public function registeringPackage(): void { $this->app->bind(QueryBuilderRequest::class, function ($app) { return QueryBuilderRequest::fromRequest($app['request']); }); } - public function provides() + public function provides(): array { return [ QueryBuilderRequest::class, diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index f926fd71..3584dca6 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -2,8 +2,6 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; -use PHPUnit\Util\Test; -use Spatie\QueryBuilder\Exceptions\InvalidSubject; use Spatie\QueryBuilder\QueryBuilder; use Spatie\QueryBuilder\QueryBuilderRequest; use Spatie\QueryBuilder\Sorts\Sort; @@ -70,17 +68,13 @@ }); it('can not be given a string that is not a class name', function () { - $this->expectException(InvalidSubject::class); - - $this->expectExceptionMessage('Subject type `string` is invalid.'); + $this->expectException(TypeError::class); QueryBuilder::for('not a class name'); }); it('can not be given an object that is neither relation nor eloquent builder', function () { - $this->expectException(InvalidSubject::class); - - $this->expectExceptionMessage(sprintf('Subject class `%s` is invalid.', self::class)); + $this->expectException(TypeError::class); QueryBuilder::for($this); });