From 341f506f8c07e849182a285c63dfc406d1da6730 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Thu, 2 May 2024 23:41:00 -0400 Subject: [PATCH] [5.x] Extract whereSite query method to trait (#9991) --- src/Entries/Entry.php | 2 +- src/Stache/Query/EntryQueryBuilder.php | 114 ++++++------------------ src/Stache/Query/QueriesEntryStatus.php | 67 ++++++++++++++ 3 files changed, 96 insertions(+), 87 deletions(-) create mode 100644 src/Stache/Query/QueriesEntryStatus.php diff --git a/src/Entries/Entry.php b/src/Entries/Entry.php index a77a55fe9a..47862e6691 100644 --- a/src/Entries/Entry.php +++ b/src/Entries/Entry.php @@ -1076,6 +1076,6 @@ public function __sleep() $this->slug = $slug($this); } - return array_keys(Arr::except(get_object_vars($this), ['cachedKeys', 'computedCallbackCache', 'siteCache'])); + return array_keys(Arr::except(get_object_vars($this), ['cachedKeys', 'computedCallbackCache', 'siteCache', 'augmentationReferenceKey'])); } } diff --git a/src/Stache/Query/EntryQueryBuilder.php b/src/Stache/Query/EntryQueryBuilder.php index 923cecc9e4..d20fe0c77b 100644 --- a/src/Stache/Query/EntryQueryBuilder.php +++ b/src/Stache/Query/EntryQueryBuilder.php @@ -11,9 +11,7 @@ class EntryQueryBuilder extends Builder implements QueryBuilder { - use QueriesTaxonomizedEntries; - - private const STATUSES = ['published', 'draft', 'scheduled', 'expired']; + use QueriesEntryStatus, QueriesTaxonomizedEntries; protected $collections = []; @@ -70,39 +68,6 @@ protected function getFilteredKeys() : $this->getKeysFromCollectionsWithWheres($collections, $this->wheres); } - private function addCollectionWheres(): void - { - $this->collections = $this->getCollectionWheres(); - } - - private function getCollectionWheres(): array - { - // If the collections property isn't empty, it means the user has explicitly - // queried for them. In that case, we'll use them and skip the auto-detection. - if (! empty($this->collections)) { - return $this->collections; - } - - // Otherwise, we'll detect them by looking at where clauses targeting the "id" column. - $ids = collect($this->wheres)->where('column', 'id')->flatMap(fn ($where) => $where['values'] ?? [$where['value']]); - - // If no IDs were queried, fall back to all collections. - if ($ids->isEmpty()) { - return Collection::handles()->all(); - } - - return Blink::once('entry-to-collection-map', function () { - return Collection::handles() - ->flatMap(fn ($collection) => $this->getWhereColumnKeysFromStore($collection, ['column' => 'collectionHandle'])) - ->keys() - ->mapWithKeys(function ($value) { - [$collection, $id] = explode('::', $value); - - return [$id => $collection]; - }); - })->only($ids->all())->unique()->values()->all(); - } - protected function getKeysFromCollections($collections) { return collect($collections)->flatMap(function ($collection) { @@ -178,69 +143,46 @@ protected function getWhereColumnKeyValuesByIndex($column) }); } - public function whereStatus(string $status) + private function ensureCollectionsAreQueriedForStatusQuery(): void { - $this->addCollectionWheres(); - - if (! in_array($status, self::STATUSES)) { - throw new \Exception("Invalid status [$status]"); - } - - if ($status === 'draft') { - return $this->where('published', false); + // If the collections property isn't empty, it means the user has explicitly + // queried for them. In that case, we'll use them and skip the auto-detection. + if (! empty($this->collections)) { + return; } - $this->where('published', true); - - return $this->where(fn ($query) => $this - ->getCollectionsForStatus() - ->each(fn ($collection) => $query->orWhere(fn ($q) => $this->addCollectionStatusLogicToQuery($q, $status, $collection)))); - } - - private function getCollectionsForStatus() - { - // Since we have to add nested queries for each collection, if collections have been provided, - // we'll use those to avoid the need for adding unnecessary query clauses. + // Otherwise, we'll detect them by looking at where clauses targeting the "id" column. + $ids = collect($this->wheres)->where('column', 'id')->flatMap(fn ($where) => $where['values'] ?? [$where['value']]); - if (empty($this->collections)) { - return Collection::all(); - } + // If no IDs were queried, fall back to all collections. + $this->collections = $ids->isEmpty() + ? Collection::handles()->all() + : Blink::once('entry-to-collection-map', function () { + return Collection::handles() + ->flatMap(fn ($collection) => $this->getWhereColumnKeysFromStore($collection, ['column' => 'collectionHandle'])) + ->keys() + ->mapWithKeys(function ($value) { + [$collection, $id] = explode('::', $value); - return collect($this->collections)->map(fn ($handle) => Collection::find($handle)); + return [$id => $collection]; + }); + })->only($ids->all())->unique()->values()->all(); } - private function addCollectionStatusLogicToQuery($query, $status, $collection) + protected function addCollectionWhereToStatusQuery($query, $collection): void { // Using collectionHandle instead of collection because we intercept collection // and put it on a property. In this case we actually want the indexed value. // We can probably refactor this elsewhere later. - $query->where('collectionHandle', $collection->handle()); - - if ($collection->futureDateBehavior() === 'public' && $collection->pastDateBehavior() === 'public') { - if ($status === 'scheduled' || $status === 'expired') { - $query->where('date', 'invalid'); // intentionally trigger no results. - } - } - - if ($collection->futureDateBehavior() === 'private') { - $status === 'scheduled' - ? $query->where('date', '>', now()) - : $query->where('date', '<', now()); - - if ($status === 'expired') { - $query->where('date', 'invalid'); // intentionally trigger no results. - } - } + $query->where('collectionHandle', $collection); + } - if ($collection->pastDateBehavior() === 'private') { - $status === 'expired' - ? $query->where('date', '<', now()) - : $query->where('date', '>', now()); + protected function getCollectionsForStatusQuery(): \Illuminate\Support\Collection + { + // Since we have to add nested queries for each collection, we only want to add clauses for the + // applicable collections. By this point, there should be where clauses on the collection column. - if ($status === 'scheduled') { - $query->where('date', 'invalid'); // intentionally trigger no results. - } - } + return collect($this->collections)->map(fn ($handle) => Collection::find($handle)); } public function prepareForFakeQuery(): array diff --git a/src/Stache/Query/QueriesEntryStatus.php b/src/Stache/Query/QueriesEntryStatus.php new file mode 100644 index 0000000000..e26b8f7d0a --- /dev/null +++ b/src/Stache/Query/QueriesEntryStatus.php @@ -0,0 +1,67 @@ +ensureCollectionsAreQueriedForStatusQuery(); + + if ($status === 'draft') { + return $this->where('published', false); + } + + $this->where('published', true); + + return $this->where(fn ($query) => $this + ->getCollectionsForStatusQuery() + ->each(fn ($collection) => $query->orWhere(fn ($q) => $this->addCollectionStatusLogicToQuery($q, $status, $collection)))); + } + + private function addCollectionStatusLogicToQuery($query, $status, $collection): void + { + $this->addCollectionWhereToStatusQuery($query, $collection->handle()); + + if ($collection->futureDateBehavior() === 'public' && $collection->pastDateBehavior() === 'public') { + if ($status === 'scheduled' || $status === 'expired') { + $query->where('date', 'invalid'); // intentionally trigger no results. + } + } + + if ($collection->futureDateBehavior() === 'private') { + $status === 'scheduled' + ? $query->where('date', '>', now()) + : $query->where('date', '<', now()); + + if ($status === 'expired') { + $query->where('date', 'invalid'); // intentionally trigger no results. + } + } + + if ($collection->pastDateBehavior() === 'private') { + $status === 'expired' + ? $query->where('date', '<', now()) + : $query->where('date', '>', now()); + + if ($status === 'scheduled') { + $query->where('date', 'invalid'); // intentionally trigger no results. + } + } + } + + protected function addCollectionWhereToStatusQuery($query, $collection): void + { + $query->where('collection', $collection); + } + + abstract protected function ensureCollectionsAreQueriedForStatusQuery(): void; + + abstract protected function getCollectionsForStatusQuery(): Collection; +}