From c9f086fc59b657fb6bccc6dc8561f62b9d6b1066 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Fri, 4 Sep 2026 16:55:38 -0700 Subject: [PATCH] Move element query param application logic to static methods --- src/Element/Queries/AddressQuery.php | 163 +++++++++++++++--- .../Queries/Concerns/Asset/QueriesAlt.php | 35 ++-- .../Concerns/Asset/QueriesAssetLocation.php | 97 +++++++---- .../Concerns/Asset/QueriesAssetProperties.php | 69 +++++--- .../Queries/Concerns/Asset/QueriesSizes.php | 40 +++-- .../Queries/Concerns/Entry/QueriesAuthors.php | 38 ++-- .../Concerns/Entry/QueriesEntryDates.php | 51 ++++-- .../Concerns/Entry/QueriesEntryTypes.php | 16 +- .../Queries/Concerns/Entry/QueriesRef.php | 59 ++++--- .../Concerns/Entry/QueriesSections.php | 27 ++- .../Queries/Concerns/QueriesFields.php | 136 +++++++++++---- .../Concerns/QueriesRelatedElements.php | 88 +++++----- .../Queries/Concerns/QueriesStatuses.php | 25 +-- .../Concerns/User/QueriesAffiliatedSite.php | 16 +- .../Concerns/User/QueriesAssetUploaders.php | 28 +-- .../Queries/Concerns/User/QueriesAuthors.php | 48 ++++-- .../User/QueriesRolesAndPermissions.php | 50 +++--- .../Concerns/User/QueriesUserGroups.php | 78 +++++---- .../Concerns/User/QueriesUserProperties.php | 36 ++-- 19 files changed, 725 insertions(+), 375 deletions(-) diff --git a/src/Element/Queries/AddressQuery.php b/src/Element/Queries/AddressQuery.php index 87fb6013e9f..10887705551 100644 --- a/src/Element/Queries/AddressQuery.php +++ b/src/Element/Queries/AddressQuery.php @@ -12,6 +12,7 @@ use CraftCms\Cms\Element\Queries\Exceptions\QueryAbortedException; use CraftCms\Cms\FieldLayout\FieldLayout; use CraftCms\Cms\Support\Arr; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Collection; use Override; @@ -366,31 +367,149 @@ public function __construct(array $config = []) $addressQuery->whereIn('addresses.primaryOwnerId', Arr::wrap($addressQuery->primaryOwnerId ?? $addressQuery->ownerId)); } - foreach ([ - 'countryCode', - 'administrativeArea', - 'locality', - 'dependentLocality', - 'postalCode', - 'sortingCode', - 'organization', - 'organizationTaxId', - 'addressLine1', - 'addressLine2', - 'addressLine3', - 'lastName', - 'firstName', - 'fullName', - ] as $property) { - if (! $addressQuery->$property) { - continue; - } - - $addressQuery->whereParam("addresses.$property", $addressQuery->$property); - } + static::applyCountryCode($addressQuery, $addressQuery->countryCode); + static::applyAdministrativeArea($addressQuery, $addressQuery->administrativeArea); + static::applyLocality($addressQuery, $addressQuery->locality); + static::applyDependentLocality($addressQuery, $addressQuery->dependentLocality); + static::applyPostalCode($addressQuery, $addressQuery->postalCode); + static::applySortingCode($addressQuery, $addressQuery->sortingCode); + static::applyOrganization($addressQuery, $addressQuery->organization); + static::applyOrganizationTaxId($addressQuery, $addressQuery->organizationTaxId); + static::applyAddressLine1($addressQuery, $addressQuery->addressLine1); + static::applyAddressLine2($addressQuery, $addressQuery->addressLine2); + static::applyAddressLine3($addressQuery, $addressQuery->addressLine3); + static::applyLastName($addressQuery, $addressQuery->lastName); + static::applyFirstName($addressQuery, $addressQuery->firstName); + static::applyFullName($addressQuery, $addressQuery->fullName); }); } + public static function applyCountryCode(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.countryCode', $value); + } + + public static function applyAdministrativeArea(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.administrativeArea', $value); + } + + public static function applyLocality(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.locality', $value); + } + + public static function applyDependentLocality(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.dependentLocality', $value); + } + + public static function applyPostalCode(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.postalCode', $value); + } + + public static function applySortingCode(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.sortingCode', $value); + } + + public static function applyOrganization(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.organization', $value); + } + + public static function applyOrganizationTaxId(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.organizationTaxId', $value); + } + + public static function applyAddressLine1(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.addressLine1', $value); + } + + public static function applyAddressLine2(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.addressLine2', $value); + } + + public static function applyAddressLine3(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.addressLine3', $value); + } + + public static function applyLastName(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.lastName', $value); + } + + public static function applyFirstName(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.firstName', $value); + } + + public static function applyFullName(Builder $query, array|string|null $value): void + { + if (! $value) { + return; + } + + $query->whereParam('addresses.fullName', $value); + } + /** * Narrows the query results based on the country the addresses belong to. * diff --git a/src/Element/Queries/Concerns/Asset/QueriesAlt.php b/src/Element/Queries/Concerns/Asset/QueriesAlt.php index 1d9ff76b51b..60870db20b0 100644 --- a/src/Element/Queries/Concerns/Asset/QueriesAlt.php +++ b/src/Element/Queries/Concerns/Asset/QueriesAlt.php @@ -22,24 +22,29 @@ trait QueriesAlt protected function initQueriesAlt(): void { $this->beforeQuery(function (AssetQuery $assetQuery) { - if ($assetQuery->hasAlt === null) { - return; - } - - if ($this->hasAlt) { - $assetQuery->where(function (Builder $query) { - $query->where('assets_sites.alt', '!=', '') - ->whereNotNull('assets_sites.alt'); - }); - } else { - $assetQuery->where(function (Builder $query) { - $query->where('assets_sites.alt', '=', '') - ->orWhereNull('assets_sites.alt'); - }); - } + static::applyHasAlt($assetQuery, $assetQuery->hasAlt); }); } + public static function applyHasAlt(Builder $query, ?bool $value): void + { + if ($value === null) { + return; + } + + if ($value) { + $query->where(function (Builder $query) { + $query->where('assets_sites.alt', '!=', '') + ->whereNotNull('assets_sites.alt'); + }); + } else { + $query->where(function (Builder $query) { + $query->where('assets_sites.alt', '=', '') + ->orWhereNull('assets_sites.alt'); + }); + } + } + /** * Narrows the query results based on whether the assets have alternative text. * diff --git a/src/Element/Queries/Concerns/Asset/QueriesAssetLocation.php b/src/Element/Queries/Concerns/Asset/QueriesAssetLocation.php index 7b2a942c5d9..46fb735eb33 100644 --- a/src/Element/Queries/Concerns/Asset/QueriesAssetLocation.php +++ b/src/Element/Queries/Concerns/Asset/QueriesAssetLocation.php @@ -75,50 +75,71 @@ protected function initQueriesAssetLocation(): void $assetQuery->join(new Alias(Table::VOLUMEFOLDERS, 'volumeFolders'), 'volumeFolders.id', '=', 'assets.folderId'); - if ($assetQuery->volumeId) { - if ($assetQuery->volumeId === ':empty:') { - $assetQuery->whereNull('assets.volumeId'); - } else { - $assetQuery->whereIn('assets.volumeId', Arr::wrap($this->volumeId)); - } - } + static::applyVolumeId($assetQuery, $assetQuery->volumeId); + static::applyFolderId($assetQuery, $assetQuery->folderId); + static::applyFolderPath($assetQuery, $assetQuery->folderPath); + }); + } - if ($assetQuery->folderId) { - // [X] => X, so includeSubfolders works with GraphQL - // (see https://github.com/craftcms/cms/issues/17023) - if (is_array($assetQuery->folderId) && count($assetQuery->folderId) === 1 && Arr::isNumeric($assetQuery->folderId)) { - $assetQuery->folderId = reset($assetQuery->folderId); - } - - $assetQuery->where(function (Builder $query) use ($assetQuery) { - $query->whereNumericParam('assets.folderId', $assetQuery->folderId) - ->when( - is_numeric($assetQuery->folderId) && $assetQuery->includeSubfolders, - function (Builder $query) use ($assetQuery) { - $descendants = Folders::getAllDescendantFolders(Folders::getFolderById($assetQuery->folderId)); - - $query->orWhereIn('assets.folderId', array_keys($descendants)); - } - ); - }); - } + public static function applyVolumeId(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + if ($value === ':empty:') { + $query->whereNull('assets.volumeId'); + } else { + $query->whereIn('assets.volumeId', Arr::wrap($value)); + } + } + + public static function applyFolderId(Builder $query, mixed $value): void + { + assert($query instanceof AssetQuery); + + if (! $value) { + return; + } + + // [X] => X, so includeSubfolders works with GraphQL + // (see https://github.com/craftcms/cms/issues/17023) + if (is_array($value) && count($value) === 1 && Arr::isNumeric($value)) { + $value = reset($value); + } - if ($assetQuery->folderPath) { - $folderPath = Arr::wrap($assetQuery->folderPath); + $query->where(function (Builder $q) use ($query, $value) { + $q->whereNumericParam('assets.folderId', $value) + ->when( + is_numeric($value) && $query->includeSubfolders, + function (Builder $q) use ($value) { + $descendants = Folders::getAllDescendantFolders(Folders::getFolderById($value)); - foreach ($folderPath as &$path) { - if ( - is_string($path) && - ! str_ends_with($path, '/') && - Query::escapeParam($path) === $path - ) { - $path .= '/'; + $q->orWhereIn('assets.folderId', array_keys($descendants)); } - } + ); + }); + } + + public static function applyFolderPath(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $folderPath = Arr::wrap($value); - $assetQuery->whereParam('volumeFolders.path', $folderPath); + foreach ($folderPath as &$path) { + if ( + is_string($path) && + ! str_ends_with($path, '/') && + Query::escapeParam($path) === $path + ) { + $path .= '/'; } - }); + } + + $query->whereParam('volumeFolders.path', $folderPath); } /** diff --git a/src/Element/Queries/Concerns/Asset/QueriesAssetProperties.php b/src/Element/Queries/Concerns/Asset/QueriesAssetProperties.php index cd2096794f8..5de7f86a16c 100644 --- a/src/Element/Queries/Concerns/Asset/QueriesAssetProperties.php +++ b/src/Element/Queries/Concerns/Asset/QueriesAssetProperties.php @@ -83,38 +83,63 @@ trait QueriesAssetProperties protected function initQueriesAssetProperties(): void { $this->beforeQuery(function (AssetQuery $assetQuery) { - if ($assetQuery->uploaderId) { - $assetQuery->whereIn('uploaderId', Arr::wrap($assetQuery->uploaderId)); - } + static::applyUploaderId($assetQuery, $assetQuery->uploaderId); + static::applyFilename($assetQuery, $assetQuery->filename); + static::applyKind($assetQuery, $assetQuery->kind); + static::applyDateModified($assetQuery, $assetQuery->dateModified); + }); + } - if ($assetQuery->filename) { - $assetQuery->whereParam('assets.filename', $assetQuery->filename); - } + public static function applyUploaderId(Builder $query, ?int $value): void + { + if (! $value) { + return; + } - if ($assetQuery->kind) { - $assetQuery->where(function (Builder $query) use ($assetQuery) { - $query->whereParam('assets.kind', $assetQuery->kind); + $query->whereIn('uploaderId', Arr::wrap($value)); + } - $kinds = AssetsHelper::getFileKinds(); + public static function applyFilename(Builder $query, mixed $value): void + { + if (! $value) { + return; + } - foreach ((array) $assetQuery->kind as $kind) { - if (! isset($kinds[$kind])) { - continue; - } + $query->whereParam('assets.filename', $value); + } - foreach ($kinds[$kind]['extensions'] as $extension) { - $query->orWhereLike('assets.filename', "%.$extension"); - } - } - }); - } + public static function applyKind(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->where(function (Builder $query) use ($value) { + $query->whereParam('assets.kind', $value); + + $kinds = AssetsHelper::getFileKinds(); + + foreach ((array) $value as $kind) { + if (! isset($kinds[$kind])) { + continue; + } - if ($assetQuery->dateModified) { - $assetQuery->whereDateParam('assets.dateModified', $assetQuery->dateModified); + foreach ($kinds[$kind]['extensions'] as $extension) { + $query->orWhereLike('assets.filename', "%.$extension"); + } } }); } + public static function applyDateModified(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('assets.dateModified', $value); + } + /** * Narrows the query results based on the user the assets were uploaded by, per the user’s IDs. * diff --git a/src/Element/Queries/Concerns/Asset/QueriesSizes.php b/src/Element/Queries/Concerns/Asset/QueriesSizes.php index dea3bb49a52..1832edbf8b0 100644 --- a/src/Element/Queries/Concerns/Asset/QueriesSizes.php +++ b/src/Element/Queries/Concerns/Asset/QueriesSizes.php @@ -6,6 +6,7 @@ use CraftCms\Cms\Element\Queries\AssetQuery; use CraftCms\Cms\Support\Query; +use Illuminate\Database\Query\Builder; /** * @internal @@ -66,18 +67,37 @@ trait QueriesSizes protected function initQueriesSizes(): void { $this->beforeQuery(function (AssetQuery $assetQuery) { - if ($assetQuery->width) { - $assetQuery->whereNumericParam('assets.width', $assetQuery->width); - } + static::applyWidth($assetQuery, $assetQuery->width); + static::applyHeight($assetQuery, $assetQuery->height); + static::applySize($assetQuery, $assetQuery->size); + }); + } + + public static function applyWidth(Builder $query, mixed $value): void + { + if (! $value) { + return; + } - if ($assetQuery->height) { - $assetQuery->whereNumericParam('assets.height', $assetQuery->height); - } + $query->whereNumericParam('assets.width', $value); + } - if ($assetQuery->size) { - $assetQuery->whereNumericParam('assets.size', $assetQuery->size, '=', Query::TYPE_BIGINT); - } - }); + public static function applyHeight(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereNumericParam('assets.height', $value); + } + + public static function applySize(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereNumericParam('assets.size', $value, '=', Query::TYPE_BIGINT); } /** diff --git a/src/Element/Queries/Concerns/Entry/QueriesAuthors.php b/src/Element/Queries/Concerns/Entry/QueriesAuthors.php index cc457ca6e38..9838a22b5c1 100644 --- a/src/Element/Queries/Concerns/Entry/QueriesAuthors.php +++ b/src/Element/Queries/Concerns/Entry/QueriesAuthors.php @@ -9,10 +9,10 @@ use CraftCms\Cms\Edition; use CraftCms\Cms\Element\Queries\EntryQuery; use CraftCms\Cms\Element\Queries\Exceptions\QueryAbortedException; -use CraftCms\Cms\Entry\Elements\Entry; use CraftCms\Cms\Support\Facades\UserGroups; use CraftCms\Cms\Support\Query; use CraftCms\Cms\User\Data\UserGroup; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; use Tpetry\QueryExpressions\Language\Alias; @@ -52,7 +52,7 @@ trait QueriesAuthors protected function initQueriesAuthors(): void { $this->beforeQuery(function (EntryQuery $query) { - if ($this->authorGroupId === []) { + if ($query->authorGroupId === []) { throw new QueryAbortedException; } @@ -60,27 +60,26 @@ protected function initQueriesAuthors(): void return; } - $this->applyAuthorId($query); - $this->applyAuthorGroupId($query); + static::applyAuthorId($query, $query->authorId); + static::applyAuthorGroupId($query, $query->authorGroupId); }); } - /** @param EntryQuery $query */ - private function applyAuthorId(EntryQuery $query): void + public static function applyAuthorId(Builder $query, mixed $value): void { - if (is_null($query->authorId)) { + if (is_null($value)) { return; } // Checking multiple authors? if ( - is_array($query->authorId) && - is_string(reset($query->authorId)) && - strtolower(reset($query->authorId)) === 'and' + is_array($value) && + is_string(reset($value)) && + strtolower(reset($value)) === 'and' ) { - $authorIdChecks = array_slice($query->authorId, 1); + $authorIdChecks = array_slice($value, 1); } else { - $authorIdChecks = [$query->authorId]; + $authorIdChecks = [$value]; } foreach ($authorIdChecks as $authorIdCheck) { @@ -106,22 +105,21 @@ private function applyAuthorId(EntryQuery $query): void } } - /** @param EntryQuery $query */ - private function applyAuthorGroupId(EntryQuery $query): void + public static function applyAuthorGroupId(Builder $query, mixed $value): void { - if (is_null($query->authorGroupId)) { + if (is_null($value)) { return; } // Checking multiple groups? if ( - is_array($this->authorGroupId) && - is_string(reset($this->authorGroupId)) && - strtolower(reset($this->authorGroupId)) === 'and' + is_array($value) && + is_string(reset($value)) && + strtolower(reset($value)) === 'and' ) { - $groupIdChecks = array_slice($this->authorGroupId, 1); + $groupIdChecks = array_slice($value, 1); } else { - $groupIdChecks = [$this->authorGroupId]; + $groupIdChecks = [$value]; } foreach ($groupIdChecks as $i => $groupIdCheck) { diff --git a/src/Element/Queries/Concerns/Entry/QueriesEntryDates.php b/src/Element/Queries/Concerns/Entry/QueriesEntryDates.php index 427706b8b3f..397bc91683e 100644 --- a/src/Element/Queries/Concerns/Entry/QueriesEntryDates.php +++ b/src/Element/Queries/Concerns/Entry/QueriesEntryDates.php @@ -5,6 +5,7 @@ namespace CraftCms\Cms\Element\Queries\Concerns\Entry; use CraftCms\Cms\Element\Queries\EntryQuery; +use Illuminate\Database\Query\Builder; /** * @internal @@ -82,22 +83,52 @@ protected function initQueriesEntryDates(): void { $this->beforeQuery(function (EntryQuery $query) { if ($query->postDate) { - $query->whereDateParam('entries.postDate', $query->postDate); + static::applyPostDate($query, $query->postDate); } else { - if ($query->before) { - $query->whereDateParam('entries.postDate', $query->before, '<'); - } - if ($query->after) { - $query->whereDateParam('entries.postDate', $query->after, '>='); - } + static::applyBefore($query, $query->before); + static::applyAfter($query, $query->after); } - if ($query->expiryDate) { - $query->whereDateParam('entries.expiryDate', $query->expiryDate); - } + static::applyExpiryDate($query, $query->expiryDate); }); } + public static function applyPostDate(Builder $query, mixed $value): void + { + if (is_null($value)) { + return; + } + + $query->whereDateParam('entries.postDate', $value); + } + + public static function applyBefore(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('entries.postDate', $value, '<'); + } + + public static function applyAfter(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('entries.postDate', $value, '>='); + } + + public static function applyExpiryDate(Builder $query, mixed $value): void + { + if (is_null($value)) { + return; + } + + $query->whereDateParam('entries.expiryDate', $value); + } + /** * Narrows the query results based on the entries’ post dates. * diff --git a/src/Element/Queries/Concerns/Entry/QueriesEntryTypes.php b/src/Element/Queries/Concerns/Entry/QueriesEntryTypes.php index e61d4ff4ff6..372ab02f699 100644 --- a/src/Element/Queries/Concerns/Entry/QueriesEntryTypes.php +++ b/src/Element/Queries/Concerns/Entry/QueriesEntryTypes.php @@ -12,6 +12,7 @@ use CraftCms\Cms\Support\Arr; use CraftCms\Cms\Support\Facades\EntryTypes; use CraftCms\Cms\Support\Query; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; /** @@ -51,14 +52,19 @@ protected function initQueriesEntryTypes(): void throw new QueryAbortedException; } - if (! $entryQuery->typeId) { - return; - } - - $entryQuery->whereIn('entries.typeId', $entryQuery->typeId); + static::applyTypeId($entryQuery, $entryQuery->typeId); }); } + public static function applyTypeId(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereIn('entries.typeId', $value); + } + /** * Narrows the query results based on the entries’ entry types. * diff --git a/src/Element/Queries/Concerns/Entry/QueriesRef.php b/src/Element/Queries/Concerns/Entry/QueriesRef.php index 420ba8f2574..34150016d4b 100644 --- a/src/Element/Queries/Concerns/Entry/QueriesRef.php +++ b/src/Element/Queries/Concerns/Entry/QueriesRef.php @@ -26,43 +26,48 @@ trait QueriesRef protected function initQueriesRef(): void { $this->beforeQuery(function (EntryQuery $query) { - if (is_null($query->ref)) { - return; - } - - $refs = $query->ref; - if (! is_array($refs)) { - $refs = is_string($refs) ? str($refs)->explode(',') : [$refs]; - } + static::applyRef($query, $query->ref); + }); + } - $joinSections = false; - $query->where(function (Builder $query) use (&$joinSections, $refs) { - foreach ($refs as $ref) { - $parts = array_filter(explode('/', (string) $ref), static fn (string $part) => $part !== ''); + public static function applyRef(Builder $query, mixed $value): void + { + if (is_null($value)) { + return; + } - if (empty($parts)) { - continue; - } + $refs = $value; + if (! is_array($refs)) { + $refs = is_string($refs) ? str($refs)->explode(',') : [$refs]; + } - if (count($parts) === 1) { - $query->orWhereParam('elements_sites.slug', $parts[0]); + $joinSections = false; + $query->where(function (Builder $q) use (&$joinSections, $refs) { + foreach ($refs as $ref) { + $parts = array_filter(explode('/', (string) $ref), static fn (string $part) => $part !== ''); - continue; - } + if (empty($parts)) { + continue; + } - $query->where(function (Builder $query) use ($parts) { - $query->whereParam('sections.handle', $parts[0]) - ->whereParam('elements_sites.slug', $parts[1]); - }); + if (count($parts) === 1) { + $q->orWhereParam('elements_sites.slug', $parts[0]); - $joinSections = true; + continue; } - }); - if ($joinSections) { - $this->join(new Alias(Table::SECTIONS, 'sections'), 'sections.id', '=', 'entries.sectionId'); + $q->where(function (Builder $q) use ($parts) { + $q->whereParam('sections.handle', $parts[0]) + ->whereParam('elements_sites.slug', $parts[1]); + }); + + $joinSections = true; } }); + + if ($joinSections) { + $query->join(new Alias(Table::SECTIONS, 'sections'), 'sections.id', '=', 'entries.sectionId'); + } } /** diff --git a/src/Element/Queries/Concerns/Entry/QueriesSections.php b/src/Element/Queries/Concerns/Entry/QueriesSections.php index 96f7afd7a01..bd79f0c4213 100644 --- a/src/Element/Queries/Concerns/Entry/QueriesSections.php +++ b/src/Element/Queries/Concerns/Entry/QueriesSections.php @@ -13,6 +13,7 @@ use CraftCms\Cms\Support\Arr; use CraftCms\Cms\Support\Facades\Sections; use CraftCms\Cms\Support\Query; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; /** @@ -50,7 +51,7 @@ protected function initQueriesSections(): void throw new QueryAbortedException; } - $this->applySectionIdParam($entryQuery); + static::applySectionId($entryQuery, $entryQuery->sectionId); }); } @@ -160,29 +161,27 @@ public function sectionId(mixed $value): static return $this; } - /** - * Applies the 'sectionId' param to the query being prepared. - */ - /** @param EntryQuery $entryQuery */ - private function applySectionIdParam(EntryQuery $entryQuery): void + public static function applySectionId(Builder $query, mixed $value): void { - if (! $entryQuery->sectionId) { + assert($query instanceof EntryQuery); + + if (! $value) { return; } - $entryQuery->whereIn('entries.sectionId', $entryQuery->sectionId); + $query->whereIn('entries.sectionId', $value); // Should we set the structureId param? if ( - $entryQuery->withStructure && - ! isset($entryQuery->structureId) && - count($entryQuery->sectionId) === 1 + $query->withStructure && + ! isset($query->structureId) && + count($value) === 1 ) { - $section = Sections::getSectionById(reset($entryQuery->sectionId)); + $section = Sections::getSectionById(reset($value)); if ($section && $section->type === SectionType::Structure) { - $entryQuery->structureId = $section->structureId; + $query->structureId = $section->structureId; } else { - $entryQuery->withStructure = false; + $query->withStructure = false; } } } diff --git a/src/Element/Queries/Concerns/QueriesFields.php b/src/Element/Queries/Concerns/QueriesFields.php index 933d343f502..1292309e030 100644 --- a/src/Element/Queries/Concerns/QueriesFields.php +++ b/src/Element/Queries/Concerns/QueriesFields.php @@ -8,6 +8,7 @@ use CraftCms\Cms\Element\Queries\ElementQuery; use CraftCms\Cms\Element\Queries\Exceptions\QueryAbortedException; use CraftCms\Cms\Support\Query; +use Illuminate\Database\Query\Builder; use Tpetry\QueryExpressions\Language\Alias; /** @@ -92,55 +93,122 @@ protected function initQueriesFields(): void if (! is_null($elementQuery->id)) { throw_if(empty($elementQuery->id), QueryAbortedException::class); - $elementQuery->whereNumericParam('elements.id', $elementQuery->id); + static::applyId($elementQuery, $elementQuery->id); } if (! is_null($elementQuery->uid)) { throw_if(empty($elementQuery->uid), QueryAbortedException::class); - $elementQuery->whereParam('elements.uid', $elementQuery->uid); + static::applyUid($elementQuery, $elementQuery->uid); } - if ($elementQuery->siteSettingsId) { - $elementQuery->whereNumericParam('elements_sites.id', $elementQuery->siteSettingsId); - } + static::applySiteSettingsId($elementQuery, $elementQuery->siteSettingsId); + static::applyTrashed($elementQuery, $elementQuery->trashed); + static::applyDateCreated($elementQuery, $elementQuery->dateCreated); + static::applyDateUpdated($elementQuery, $elementQuery->dateUpdated); + static::applyTitle($elementQuery, $elementQuery->title); + static::applySlug($elementQuery, $elementQuery->slug); + static::applyUri($elementQuery, $elementQuery->uri); + static::applyInBulkOp($elementQuery, $elementQuery->inBulkOp); + }); + } - match ($elementQuery->trashed) { - true => $elementQuery->whereNotNull('elements.dateDeleted'), - false => $elementQuery->whereNull('elements.dateDeleted'), - default => null, - }; + public static function applyId(Builder $query, mixed $value): void + { + if (is_null($value)) { + return; + } - if ($elementQuery->dateCreated) { - $elementQuery->whereDateParam('elements.dateCreated', $elementQuery->dateCreated); - } + $query->whereNumericParam('elements.id', $value); + } - if ($elementQuery->dateUpdated) { - $elementQuery->whereDateParam('elements.dateUpdated', $elementQuery->dateUpdated); - } + public static function applyUid(Builder $query, mixed $value): void + { + if (is_null($value)) { + return; + } - if (isset($elementQuery->title) && $elementQuery->title !== '' && $elementQuery->elementType::hasTitles()) { - if (is_string($elementQuery->title)) { - $elementQuery->title = Query::escapeCommas($elementQuery->title); - } + $query->whereParam('elements.uid', $value); + } - $elementQuery->whereParam('elements_sites.title', $elementQuery->title, caseInsensitive: true); - } + public static function applySiteSettingsId(Builder $query, mixed $value): void + { + if (! $value) { + return; + } - if ($elementQuery->slug) { - $elementQuery->whereParam('elements_sites.slug', $elementQuery->slug); - } + $query->whereNumericParam('elements_sites.id', $value); + } - if ($elementQuery->uri) { - $elementQuery->whereParam('elements_sites.uri', $elementQuery->uri, caseInsensitive: true); - } + public static function applyTrashed(Builder $query, ?bool $value): void + { + match ($value) { + true => $query->whereNotNull('elements.dateDeleted'), + false => $query->whereNull('elements.dateDeleted'), + default => null, + }; + } - if ($elementQuery->inBulkOp) { - $elementQuery - ->join(new Alias(Table::ELEMENTS_BULKOPS, 'elements_bulkops'), 'elements_bulkops.elementId', 'elements.id') - ->where('elements_bulkops.key', $elementQuery->inBulkOp); - } - }); + public static function applyDateCreated(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('elements.dateCreated', $value); + } + + public static function applyDateUpdated(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('elements.dateUpdated', $value); + } + + public static function applyTitle(Builder $query, mixed $value): void + { + assert($query instanceof ElementQuery); + + if (! isset($value) || $value === '' || ! $query->elementType::hasTitles()) { + return; + } + + if (is_string($value)) { + $value = Query::escapeCommas($value); + } + + $query->whereParam('elements_sites.title', $value, caseInsensitive: true); + } + + public static function applySlug(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereParam('elements_sites.slug', $value); + } + + public static function applyUri(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereParam('elements_sites.uri', $value, caseInsensitive: true); + } + + public static function applyInBulkOp(Builder $query, ?string $value): void + { + if (! $value) { + return; + } + + $query + ->join(new Alias(Table::ELEMENTS_BULKOPS, 'elements_bulkops'), 'elements_bulkops.elementId', 'elements.id') + ->where('elements_bulkops.key', $value); } /** diff --git a/src/Element/Queries/Concerns/QueriesRelatedElements.php b/src/Element/Queries/Concerns/QueriesRelatedElements.php index 4b38046d3a4..1476d69e776 100644 --- a/src/Element/Queries/Concerns/QueriesRelatedElements.php +++ b/src/Element/Queries/Concerns/QueriesRelatedElements.php @@ -37,60 +37,60 @@ trait QueriesRelatedElements protected function initQueriesRelatedElements(): void { - $this->applyRelatedToParam(); - $this->applyNotRelatedToParam(); + $this->beforeQuery(function (ElementQuery $elementQuery) { + static::applyRelatedTo($elementQuery, $elementQuery->relatedTo); + static::applyNotRelatedTo($elementQuery, $elementQuery->notRelatedTo); + }); } - private function applyRelatedToParam(): void + public static function applyRelatedTo(Builder $query, mixed $value): void { - $this->beforeQuery(function (ElementQuery $elementQuery) { - if (! $elementQuery->relatedTo) { - return; - } + assert($query instanceof ElementQuery); + + if (! $value) { + return; + } + + $applied = new ElementRelationParamFilter( + fields: $query->customFields + ? Arr::keyBy( + $query->customFields, + fn (FieldInterface $field) => $field->layoutElement?->getOriginalHandle() ?? $field->handle, + ) + : [] + )->apply( + query: $query->getQuery(), + relatedToParam: $value, + siteId: $query->siteId !== '*' ? $query->siteId : null + ); + + if (! $applied) { + throw new QueryAbortedException; + } + } + + public static function applyNotRelatedTo(Builder $query, mixed $value): void + { + assert($query instanceof ElementQuery); - $applied = new ElementRelationParamFilter( - fields: $elementQuery->customFields + if (! $value) { + return; + } + + $query->whereNot(function (Builder $q) use ($query, $value) { + new ElementRelationParamFilter( + fields: $query->customFields ? Arr::keyBy( - $elementQuery->customFields, + $query->customFields, fn (FieldInterface $field) => $field->layoutElement?->getOriginalHandle() ?? $field->handle, ) : [] )->apply( - query: $elementQuery->getQuery(), - relatedToParam: $elementQuery->relatedTo, - siteId: $elementQuery->siteId !== '*' ? $elementQuery->siteId : null + query: $q, + relatedToParam: $value, + siteId: $query->siteId !== '*' ? $query->siteId : null, + matchNoneWhenInvalid: false, ); - - if (! $applied) { - throw new QueryAbortedException; - } - }); - } - - private function applyNotRelatedToParam(): void - { - $this->beforeQuery(function (ElementQuery $elementQuery) { - if (! $elementQuery->notRelatedTo) { - return; - } - - $notRelatedToParam = $elementQuery->notRelatedTo; - - $elementQuery->whereNot(function (Builder $query) use ($notRelatedToParam, $elementQuery) { - new ElementRelationParamFilter( - fields: $elementQuery->customFields - ? Arr::keyBy( - $elementQuery->customFields, - fn (FieldInterface $field) => $field->layoutElement?->getOriginalHandle() ?? $field->handle, - ) - : [] - )->apply( - query: $query, - relatedToParam: $notRelatedToParam, - siteId: $elementQuery->siteId !== '*' ? $elementQuery->siteId : null, - matchNoneWhenInvalid: false, - ); - }); }); } diff --git a/src/Element/Queries/Concerns/QueriesStatuses.php b/src/Element/Queries/Concerns/QueriesStatuses.php index c3c3b960767..483793f1cfb 100644 --- a/src/Element/Queries/Concerns/QueriesStatuses.php +++ b/src/Element/Queries/Concerns/QueriesStatuses.php @@ -42,10 +42,10 @@ protected function initQueriesStatuses(): void return; } - $this->applyStatusParam($elementQuery); + static::applyStatus($elementQuery, $elementQuery->status); // only set archived=false if 'archived' doesn't show up in the status param - // (_applyStatusParam() will normalize $this->status to an array if applicable) + // (applyStatus() will normalize $elementQuery->status to an array if applicable) if (! is_array($elementQuery->status) || ! in_array($elementQuery->elementType::STATUS_ARCHIVED, $elementQuery->status)) { $elementQuery->whereBool('elements.archived', false); } @@ -100,19 +100,22 @@ public function status(array|string|null $value): static * * @throws QueryAbortedException */ - /** @param ElementQuery<*> $elementQuery */ - private function applyStatusParam(ElementQuery $elementQuery): void + public static function applyStatus(Builder $query, mixed $value): void { - if (! $elementQuery->status || ! $elementQuery->elementType::hasStatuses()) { + assert($query instanceof ElementQuery); + + if (! $value || ! $query->elementType::hasStatuses()) { return; } // Normalize the status param - if (! is_array($elementQuery->status)) { - $elementQuery->status = str($elementQuery->status)->explode(',')->all(); + if (! is_array($value)) { + $value = str($value)->explode(',')->all(); } - $statuses = array_merge($elementQuery->status); + $query->status = $value; + + $statuses = array_merge($value); $firstVal = strtolower((string) reset($statuses)); $glue = 'or'; @@ -125,12 +128,12 @@ private function applyStatusParam(ElementQuery $elementQuery): void return; } - $elementQuery->where(function (Builder $query) use ($statuses, $glue) { + $query->where(function (Builder $q) use ($query, $statuses, $glue) { foreach ($statuses as $status) { if ($glue === 'not') { - $query->whereNot($this->placeholderCondition($this->statusCondition($status))); + $q->whereNot($query->placeholderCondition($query->statusCondition($status))); } else { - $query->orWhere($this->placeholderCondition($this->statusCondition($status))); + $q->orWhere($query->placeholderCondition($query->statusCondition($status))); } } }); diff --git a/src/Element/Queries/Concerns/User/QueriesAffiliatedSite.php b/src/Element/Queries/Concerns/User/QueriesAffiliatedSite.php index 08ff6629c05..999ec5753fe 100644 --- a/src/Element/Queries/Concerns/User/QueriesAffiliatedSite.php +++ b/src/Element/Queries/Concerns/User/QueriesAffiliatedSite.php @@ -8,6 +8,7 @@ use CraftCms\Cms\Site\Data\Site; use CraftCms\Cms\Support\Arr; use CraftCms\Cms\Support\Facades\Sites; +use Illuminate\Database\Query\Builder; use InvalidArgumentException; /** @@ -29,14 +30,19 @@ protected function initQueriesAffiliatedSite(): void } $this->beforeQuery(function (UserQuery $userQuery) { - if (! $userQuery->affiliatedSiteId) { - return; - } - - $userQuery->whereIn('users.affiliatedSiteId', Arr::wrap($this->affiliatedSiteId)); + static::applyAffiliatedSiteId($userQuery, $userQuery->affiliatedSiteId); }); } + public static function applyAffiliatedSiteId(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereIn('users.affiliatedSiteId', Arr::wrap($value)); + } + /** * Narrows the query results based on the users’ affiliated sites. * diff --git a/src/Element/Queries/Concerns/User/QueriesAssetUploaders.php b/src/Element/Queries/Concerns/User/QueriesAssetUploaders.php index 9cab31e19d7..c0ebb3315ca 100644 --- a/src/Element/Queries/Concerns/User/QueriesAssetUploaders.php +++ b/src/Element/Queries/Concerns/User/QueriesAssetUploaders.php @@ -6,6 +6,7 @@ use CraftCms\Cms\Database\Table; use CraftCms\Cms\Element\Queries\UserQuery; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; /** @@ -36,19 +37,24 @@ trait QueriesAssetUploaders protected function initQueriesAssetUploaders(): void { $this->beforeQuery(function (UserQuery $userQuery) { - if (! is_bool($userQuery->assetUploaders)) { - return; - } + static::applyAssetUploaders($userQuery, $userQuery->assetUploaders); + }); + } - $exists = DB::table(Table::ASSETS) - ->whereColumn('uploaderId', 'elements.id'); + public static function applyAssetUploaders(Builder $query, ?bool $value): void + { + if (! is_bool($value)) { + return; + } - $userQuery->when( - $userQuery->assetUploaders, - fn (UserQuery $query) => $query->whereExists($exists), - fn (UserQuery $query) => $query->whereNotExists($exists), - ); - }); + $exists = DB::table(Table::ASSETS) + ->whereColumn('uploaderId', 'elements.id'); + + if ($value) { + $query->whereExists($exists); + } else { + $query->whereNotExists($exists); + } } /** diff --git a/src/Element/Queries/Concerns/User/QueriesAuthors.php b/src/Element/Queries/Concerns/User/QueriesAuthors.php index d99beba4d73..4b40cc448c8 100644 --- a/src/Element/Queries/Concerns/User/QueriesAuthors.php +++ b/src/Element/Queries/Concerns/User/QueriesAuthors.php @@ -8,6 +8,7 @@ use CraftCms\Cms\Element\Contracts\ElementInterface; use CraftCms\Cms\Element\Queries\Exceptions\QueryAbortedException; use CraftCms\Cms\Element\Queries\UserQuery; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Facades\DB; /** @@ -45,26 +46,39 @@ trait QueriesAuthors protected function initQueriesAuthors(): void { $this->beforeQuery(function (UserQuery $userQuery) { - if (is_bool($userQuery->authors)) { - $method = $userQuery->authors ? 'whereExists' : 'whereNotExists'; - - $userQuery->$method(DB::table(Table::ENTRIES_AUTHORS)->whereColumn('authorId', 'elements.id')); - } - - if ($userQuery->authorOf) { - if (! $userQuery->authorOf->id) { - throw new QueryAbortedException; - } - - $userQuery->whereExists( - DB::table(Table::ENTRIES_AUTHORS, 'entries_authors') - ->where('entryId', $this->authorOf->id) - ->whereColumn('entries_authors.authorId', 'users.id'), - ); - } + static::applyAuthors($userQuery, $userQuery->authors); + static::applyAuthorOf($userQuery, $userQuery->authorOf); }); } + public static function applyAuthors(Builder $query, ?bool $value): void + { + if (! is_bool($value)) { + return; + } + + $method = $value ? 'whereExists' : 'whereNotExists'; + + $query->$method(DB::table(Table::ENTRIES_AUTHORS)->whereColumn('authorId', 'elements.id')); + } + + public static function applyAuthorOf(Builder $query, ?ElementInterface $value): void + { + if (! $value) { + return; + } + + if (! $value->id) { + throw new QueryAbortedException; + } + + $query->whereExists( + DB::table(Table::ENTRIES_AUTHORS, 'entries_authors') + ->where('entryId', $value->id) + ->whereColumn('entries_authors.authorId', 'users.id'), + ); + } + /** * Narrows the query results to only users that are authors of an entry. * diff --git a/src/Element/Queries/Concerns/User/QueriesRolesAndPermissions.php b/src/Element/Queries/Concerns/User/QueriesRolesAndPermissions.php index 623305cd6b1..638f95fbd5e 100644 --- a/src/Element/Queries/Concerns/User/QueriesRolesAndPermissions.php +++ b/src/Element/Queries/Concerns/User/QueriesRolesAndPermissions.php @@ -69,16 +69,23 @@ trait QueriesRolesAndPermissions protected function initQueriesRolesAndPermissions(): void { $this->beforeQuery(function (UserQuery $userQuery) { - if (is_bool($userQuery->admin)) { - $userQuery->whereBool('users.admin', $userQuery->admin); - } + static::applyAdmin($userQuery, $userQuery->admin); - if ($this->admin !== true) { - $this->applyCanParam($userQuery); + if ($userQuery->admin !== true) { + static::applyCan($userQuery, $userQuery->can); } }); } + public static function applyAdmin(Builder $query, ?bool $value): void + { + if (! is_bool($value)) { + return; + } + + $query->whereBool('users.admin', $value); + } + /** * Narrows the query results to only users that have admin accounts. * @@ -139,19 +146,16 @@ public function can(mixed $value): self return $this; } - /** - * Applies the 'can' param to the query being prepared. - */ - private function applyCanParam(UserQuery $userQuery): void + public static function applyCan(Builder $query, mixed $value): void { - if ($this->can !== false && empty($this->can)) { + if ($value !== false && empty($value)) { return; } - if (is_string($this->can) && ! is_numeric($this->can)) { + if (is_string($value) && ! is_numeric($value)) { // Convert it to the actual permission ID, or false if the permission doesn't have an ID yet. - $this->can = DB::table(Table::USERPERMISSIONS) - ->where('name', strtolower($this->can)) + $value = DB::table(Table::USERPERMISSIONS) + ->where('name', strtolower($value)) ->select('id') ->value('id') ?? false; } @@ -159,29 +163,29 @@ private function applyCanParam(UserQuery $userQuery): void // False means that the permission doesn't have an ID yet. $permittedUserIds = collect(); - if ($this->can !== false) { + if ($value !== false) { // Get the users that have that permission directly $permittedUserIds = DB::table(Table::USERPERMISSIONS_USERS) - ->whereIn('permissionId', Arr::wrap($this->can)) + ->whereIn('permissionId', Arr::wrap($value)) ->pluck('userId'); // Get the users that have that permission via a user group $permittedUserIdsViaGroups = DB::table(Table::USERGROUPS_USERS, 'g_u') ->select('g_u.userId') ->join(new Alias(Table::USERPERMISSIONS_USERGROUPS, 'p_g'), 'p_g.groupId', '=', 'g_u.groupId') - ->whereIn('p_g.permissionId', Arr::wrap($this->can)) + ->whereIn('p_g.permissionId', Arr::wrap($value)) ->pluck('userId'); $permittedUserIds = $permittedUserIds->merge($permittedUserIdsViaGroups)->unique(); } - $userQuery->when( - $permittedUserIds->isEmpty(), - fn (UserQuery $userQuery) => $userQuery->whereBool('users.admin', true), - fn (UserQuery $userQuery) => $userQuery->where(function (Builder $query) use ($permittedUserIds) { - $query->whereBool('users.admin', true) + if ($permittedUserIds->isEmpty()) { + $query->whereBool('users.admin', true); + } else { + $query->where(function (Builder $q) use ($permittedUserIds) { + $q->whereBool('users.admin', true) ->orWhereIn('users.id', $permittedUserIds); - }), - ); + }); + } } } diff --git a/src/Element/Queries/Concerns/User/QueriesUserGroups.php b/src/Element/Queries/Concerns/User/QueriesUserGroups.php index d0d0fa0fcee..2222d8c26f0 100644 --- a/src/Element/Queries/Concerns/User/QueriesUserGroups.php +++ b/src/Element/Queries/Concerns/User/QueriesUserGroups.php @@ -12,6 +12,7 @@ use CraftCms\Cms\Support\Facades\UserGroups; use CraftCms\Cms\Support\Query; use CraftCms\Cms\User\Data\UserGroup; +use Illuminate\Database\Query\Builder; use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; @@ -68,42 +69,7 @@ protected function initQueriesUserGroups(): void throw new QueryAbortedException; } - if (! $userQuery->groupId) { - return; - } - - // Checking multiple groups? - if ( - is_array($userQuery->groupId) && - is_string(reset($userQuery->groupId)) && - strtolower(reset($userQuery->groupId)) === 'and' - ) { - $groupIdChecks = array_slice($userQuery->groupId, 1); - } else { - $groupIdChecks = [$userQuery->groupId]; - } - - foreach ($groupIdChecks as $i => $groupIdCheck) { - if ( - is_array($groupIdCheck) && - is_string(reset($groupIdCheck)) && - strtolower(reset($groupIdCheck)) === 'not' - ) { - $groupIdOperator = 'whereNotExists'; - array_shift($groupIdCheck); - if (empty($groupIdCheck)) { - continue; - } - } else { - $groupIdOperator = 'whereExists'; - } - - $userQuery->$groupIdOperator( - DB::table(Table::USERGROUPS_USERS, "ugu$i") - ->whereColumn('elements.id', "ugu$i.userId") - ->whereNumericParam('groupId', $groupIdCheck), - ); - } + static::applyGroupId($userQuery, $userQuery->groupId); }); $this->afterQuery(function (mixed $result) { @@ -130,6 +96,46 @@ protected function initQueriesUserGroups(): void }); } + public static function applyGroupId(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + // Checking multiple groups? + if ( + is_array($value) && + is_string(reset($value)) && + strtolower(reset($value)) === 'and' + ) { + $groupIdChecks = array_slice($value, 1); + } else { + $groupIdChecks = [$value]; + } + + foreach ($groupIdChecks as $i => $groupIdCheck) { + if ( + is_array($groupIdCheck) && + is_string(reset($groupIdCheck)) && + strtolower(reset($groupIdCheck)) === 'not' + ) { + $groupIdOperator = 'whereNotExists'; + array_shift($groupIdCheck); + if (empty($groupIdCheck)) { + continue; + } + } else { + $groupIdOperator = 'whereExists'; + } + + $query->$groupIdOperator( + DB::table(Table::USERGROUPS_USERS, "ugu$i") + ->whereColumn('elements.id', "ugu$i.userId") + ->whereNumericParam('groupId', $groupIdCheck), + ); + } + } + /** * Narrows the query results based on the user group the users belong to. * diff --git a/src/Element/Queries/Concerns/User/QueriesUserProperties.php b/src/Element/Queries/Concerns/User/QueriesUserProperties.php index 1f88d732374..705e7e7cbd0 100644 --- a/src/Element/Queries/Concerns/User/QueriesUserProperties.php +++ b/src/Element/Queries/Concerns/User/QueriesUserProperties.php @@ -6,6 +6,7 @@ use CraftCms\Cms\Element\Queries\UserQuery; use CraftCms\Cms\Support\Query; +use Illuminate\Database\Query\Builder; /** * @internal @@ -64,17 +65,8 @@ trait QueriesUserProperties protected function initQueriesUserProperties(): void { $this->beforeQuery(function (UserQuery $userQuery) { - if ($userQuery->lastLoginDate) { - $userQuery->whereDateParam('users.lastLoginDate', $this->lastLoginDate); - } - - if (is_bool($userQuery->hasPhoto)) { - $userQuery->when( - $userQuery->hasPhoto, - fn (UserQuery $q) => $q->whereNotNull('users.photoId'), - fn (UserQuery $q) => $q->whereNull('users.photoId'), - ); - } + static::applyLastLoginDate($userQuery, $userQuery->lastLoginDate); + static::applyHasPhoto($userQuery, $userQuery->hasPhoto); foreach (['username', 'email', 'fullName', 'firstName', 'lastName'] as $property) { if (! $userQuery->$property) { @@ -94,6 +86,28 @@ protected function initQueriesUserProperties(): void }); } + public static function applyLastLoginDate(Builder $query, mixed $value): void + { + if (! $value) { + return; + } + + $query->whereDateParam('users.lastLoginDate', $value); + } + + public static function applyHasPhoto(Builder $query, ?bool $value): void + { + if (! is_bool($value)) { + return; + } + + if ($value) { + $query->whereNotNull('users.photoId'); + } else { + $query->whereNull('users.photoId'); + } + } + /** * Narrows the query results based on the users’ usernames. *