Skip to content

Conversation

nadinengland
Copy link
Contributor

@nadinengland nadinengland commented Apr 5, 2025

This PR adds findByIds to the EntryRepository contract and Stache implementation. See docs PR.

$items = \Statamic\Facades\Entry::findByIds([ 3, 1, 0, 2 ]);

$this->assertInstanceOf(\Statamic\Entries\EntryCollection::class, $items);
$this->assertCount(3, $items);
$this->assertEveryItemIsInstanceOf(\Statamic\Contacts\Entries\Entry::class);
$this->assertEquals([ 3, 1, 2 ], $items->map->id());

Entries are returned in order of their id's position in the original input argument. Missing IDs are omitted from resultant collection.

Relavancy to other packages

This is part of a wider piece of work I've start to add a fairly large reduction in DB queries to the statamic/eloquent-driver. The principal idea is to route as many components as possible through the repositories. In doing so we can optimise to load directly from the Blink cache, and only defer to the QueryBuilder when we’re missing items.

As I was adding this to the Eloquent Driver package, parity with the core Repository contract felt good as well.

Future considerations

A future goal would be to see the Entries fieldtype use this method and manage the published statuses itself. This could mean we have more occasion to use the blink cache in the eloquent driver solution and also benefit from eager loading see nadinengland/statamic-eloquent-driver#1.

However, this would certainly too much of a breaking change for 5.x, if even desired at all by your team. In the meantime I can just override the behaviour in my projects, but it may be helpful to highlight that approach here for context:

class Entries extends \Statamic\Fieldtypes\Entries
{
    public function augment($values)
    {
        if (config('statamic.system.always_augment_to_query', false)) {
            return parent::augment($values);
        }

        $items = Entry::findByIds($values);

        if ($this->config('max_items') === 1) {
            return $items->first();
        }

        return $items
            ->where(fn ($entry) => $entry->status() === 'published')
            ->values();
    }
}

@nadinengland nadinengland changed the title Adds EntryRepository#findByIds() [5.x] Adds EntryRepository#findByIds() Apr 5, 2025
@nadinengland nadinengland force-pushed the feature/entries-find-by-ids branch from 938890e to 434e627 Compare April 5, 2025 22:06
@duncanmcclean
Copy link
Member

Apologies, I might be misunderstanding this change, but why can't you do Entry::query()->whereIn('id', [1, 2, 3])->get();?

@nadinengland
Copy link
Contributor Author

nadinengland commented May 25, 2025

No worries at all. You certainly can do that, but it won't:

  1. Come back in the same order as requested without manually sorting or using OrderedQueryBuilder.
  2. Benefit from the indirection of using the repository pattern, i.e. in the Eloquent Driver, Entry::find() uses the in-memory Blink cache first, as too does my PR for ::findByIds() which loads from Blink and only queries for what is missing.

@jasonvarga
Copy link
Member

jasonvarga commented Sep 24, 2025

Thanks for your patience. I've made a couple of changes:

  • Renamed method to whereInId to match the other whereSomething methods that return EntryCollections. The find methods imply that you get a single Entry.
  • Commented out the method from the interface as that would make it a breaking change. We can introduce it in v6.

At first I was going to suggest that find could just accept an array of IDs like Eloquent does - but I notice that Eloquent doesn't return them in the order you pass it, which is the important part for you here. I'm fine with adding a specialized method in this case.

@jasonvarga jasonvarga changed the title [5.x] Adds EntryRepository#findByIds() [5.x] Add whereInId to EntryRepository Sep 24, 2025
@jasonvarga jasonvarga merged commit 2fdf1aa into statamic:5.x Sep 24, 2025
25 checks passed
@nadinengland nadinengland deleted the feature/entries-find-by-ids branch September 24, 2025 20:56
@nadinengland
Copy link
Contributor Author

All sounds perfect. Good catch on the find vs where too, certainly something I hadn't considered, but makes total sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants