Sunday, February 13, 2022

[FIXED] CakePHP3: How to get the query result count if the result is a collection?

Issue

I have the following code:

$sites = $this->Sites->find()
->contain([
    'Sitecategories',
    'Sitedescriptions.Languages',
    'Countries',
    'Users'
])
->where([
    'postcode LIKE' => $this->request->data['numero'] . '%'
])
->sortBy(function($row) { return substr($row->postcode, 0, 2); }, SORT_ASC);

debug($sites); displays:

object(Cake\Collection\Iterator\SortIterator) {

'count' => (int) 428

}

But I don't understand how to access to that count var.

I tried to access $sites->count() but I get the following error message:

Error: You cannot issue a count on a Collection.

Solution

Counting collections is kinda unreliable, given than they can mutate when being iterated, ie the count and the content can change, and with every iteration, changes may be reapplied for certain operations, causing the collection to possibly mutate in an unwated way (filtering, reducing, modifying contained objects, etc). Another unwanted effect may be unrewindable collections, ie they could not be iterated anymore. So that's basically why no count method is implemented.

The debug info shown there is the return value of iterator_count(), it accepts traversable objects and returns the number of elements in the iterator. Calling this will have the aforementioned side effects, the collection will be iterated and possibly mutated.

If you really need to know the count, and want to keep the collection, then you could for example compile it in beforehand, that would create a new collection based on the source data with all modifications applied, like:

$sites = $sites->compile();
$count = iterator_count($sites);

$sites can safely be reused after that point.

If you don't need the collection anymore, you could always simply convert it into an array and count that:

$sites = $sites->toArray();
$count = count($sites);

See also



Answered By - ndm

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.