From 282d3af4e220de708d52e1905696fdeebb98bc2d Mon Sep 17 00:00:00 2001 From: Daniel Jones Date: Fri, 13 Nov 2026 13:18:07 +0000 Subject: [PATCH] Look an entries field's entries up once for a listing --- src/Fieldtypes/Entries.php | 20 ++++++++----- tests/Fieldtypes/EntriesTest.php | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 8b070789cac..e2b84d24a39 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -402,6 +402,14 @@ protected function collect($value) } private function queryBuilder($values) + { + $ids = $this->entriesInTheirSite($values)->map->id()->all(); + + return (new StatusQueryBuilder(new OrderedQueryBuilder(Entry::query(), $ids))) + ->whereIn('id', $ids); + } + + private function entriesInTheirSite($values) { $site = Site::current()->handle(); if (($parent = $this->field()->parent()) && $parent instanceof Localization) { @@ -412,18 +420,13 @@ private function queryBuilder($values) // filter out entries that don't exist in the current site. They would do that. $shouldLocalize = ! $this->canSelectAcrossSites(); - $ids = (new OrderedQueryBuilder(Entry::query(), $ids = Arr::wrap($values))) + return (new OrderedQueryBuilder(Entry::query(), $ids = Arr::wrap($values))) ->whereIn('id', $ids) ->get() ->when($shouldLocalize, fn ($entries) => $entries ->map(fn ($entry) => $entry->in($site)) ->filter() - ) - ->map->id() - ->all(); - - return (new StatusQueryBuilder(new OrderedQueryBuilder(Entry::query(), $ids))) - ->whereIn('id', $ids); + ); } public function augment($values) @@ -516,7 +519,8 @@ public function getColumns() protected function getItemsForPreProcessIndex($values): SupportCollection { - return $this->queryBuilder($values)->whereAnyStatus()->get(); + // These are the entries a query for them in any status would find, so they aren't looked for a second time. + return Entry::applySubstitutions($this->entriesInTheirSite($values)->unique->id()->values()); } public function relationshipQueryBuilder() diff --git a/tests/Fieldtypes/EntriesTest.php b/tests/Fieldtypes/EntriesTest.php index a13bcc6a0ad..9a3885b6c76 100644 --- a/tests/Fieldtypes/EntriesTest.php +++ b/tests/Fieldtypes/EntriesTest.php @@ -142,6 +142,57 @@ public function it_includes_drafts_when_pre_processing_for_index() $this->assertEquals([456, '123', 'draft', 'scheduled', 'expired'], $preProcessed->map(fn ($entry) => $entry['id'])->all()); } + #[Test] + public function it_looks_the_entries_up_once_when_pre_processing_for_index() + { + config(['statamic.system.fake_sql_queries' => true]); + + $queries = 0; + \Illuminate\Support\Facades\Event::listen(\Illuminate\Database\Events\QueryExecuted::class, function () use (&$queries) { + $queries++; + }); + + $this->fieldtype()->preProcessIndex([456, '123', 'draft']); + + $this->assertSame(1, $queries); + } + + #[Test] + public function it_lists_an_entry_once_when_pre_processing_for_index() + { + $preProcessed = $this->fieldtype()->preProcessIndex(['123', 456, '123']); + + $this->assertEquals(['123', 456], $preProcessed->map(fn ($entry) => $entry['id'])->all()); + } + + #[Test] + public function it_localizes_and_includes_drafts_when_pre_processing_for_index() + { + $parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create(); + + EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create(); + EntryFactory::id('789-fr')->origin('789')->locale('fr')->collection('blog')->slug('three-fr')->data(['title' => 'Le Three'])->date('2021-01-02')->published(false)->create(); + + $preProcessed = $this->fieldtype([], $parent)->preProcessIndex(['789', 'invalid', 456, '123', '123-fr']); + + $this->assertEquals(['789-fr', '123-fr'], $preProcessed->map(fn ($entry) => $entry['id'])->all()); // 456 isn't localized. + $this->assertEquals(['Le Three', 'Le One'], $preProcessed->map(fn ($entry) => $entry['title'])->all()); + } + + #[Test] + public function it_uses_a_substituted_entry_when_pre_processing_for_index() + { + $parent = EntryFactory::id('parent')->collection('blog')->slug('theparent')->locale('fr')->create(); + + EntryFactory::id('123-fr')->origin('123')->locale('fr')->collection('blog')->slug('one-fr')->data(['title' => 'Le One'])->date('2021-01-02')->create(); + + Facades\Entry::substitute((clone Facades\Entry::find('456'))->set('title', 'Two, being previewed')); + Facades\Entry::substitute((clone Facades\Entry::find('123-fr'))->set('title', 'Le One, being previewed')); + + $this->assertEquals(['Two, being previewed'], $this->fieldtype()->preProcessIndex([456])->map(fn ($entry) => $entry['title'])->all()); + $this->assertEquals(['Le One, being previewed'], $this->fieldtype([], $parent)->preProcessIndex(['123'])->map(fn ($entry) => $entry['title'])->all()); + } + #[Test] public function it_localizes_the_augmented_items_to_the_parent_entrys_locale() {