Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Collections counting result

On a User model (table with 4 records), when I do:

$coll = User::all();
echo $coll->count();

I get the amount of records found (4).

But when I do:

$coll = User::find(2);
echo $coll->count();

I do not get 1 (As I expect) but the amount of attributes in the resulting collection (23 in this case).

How can I check if more then one records are found?


UPDATE:

OK, thanks to you all I now see the difference in result between collection and model.

But my real problem is that I have to detect if I am having a model or a collection as a result. Depending on this result I perform some changes on the contents of the fields in the items (with map()) or model. How can I detect if the result is a model or a collection?

if(count($coll) > 1)

Works, but is this the right approach?

like image 798
Klaaz Avatar asked May 11 '15 22:05

Klaaz


2 Answers

Here's what's going on with the code you have there:

1. When calling User::all() you'll get a Illuminate\Database\Eloquent\Collection on which you can call count which counts the elements in the collection like so:

public function count()
{
    return count($this->items);
}

This will return the number of items in the collection as you correctly expected.

2. When calling User::find(2) however, the Eloquent Query Builder will not return a Collection, because it will check to see how many results there are, and since you passed one ID you'll get at most one result, so it will return an Eloquent Model instead. The Model does not have a count() method, so when you try to call $coll->count(); it will go to the magic __call method that the class has implemented which looks like this:

public function __call($method, $parameters)
{
    if (in_array($method, array('increment', 'decrement')))
    {
        return call_user_func_array(array($this, $method), $parameters);
    }

    $query = $this->newQuery();

    return call_user_func_array(array($query, $method), $parameters);
}

As you can see the method tries to see if it should call a couple of hardcoded methods (increment and decrement), which of course don't match in this case because $method = 'count', so it continues to create a new Query on which it will call the count method.

The bottom line is that both the first and second code samples end up doing the same thing: counting all the entries in the users table.

And since, as I pointed our above, one ID cannot match more than one row (since IDs are unique), the answer to your question is that there's no need or way to count the results of find(2), since it can only be 0 (if null is returned) or 1 (if a Model is returned).


UPDATE

First of all, for future reference you can use the PHP get_class to determine the class name of an object or get_parent_class to determine the class it is extending. In your case the second function get_parent_class might be useful for determining the model class since the User class extends a Laravel abstract Model class.

So if you have a model get_class($coll) will report User, but get_parent_class($coll) will report \Illuminate\Database\Eloquent\Model.

Now to check if the result is a Collection or a Model you can use instanceof:

instanceof is used to determine whether a PHP variable is an instantiated object of a certain class

Your checks should look something like this:

// Check if it's a Collection
if ($coll instanceof \Illuminate\Support\Collection)

// Check if it's a Model
if ($coll instanceof \Illuminate\Database\Eloquent\Model)

You might also want to check if the result is null, since find will return null if no entry is found with the given ID:

if (is_null($coll))
like image 107
Bogdan Avatar answered Oct 31 '22 19:10

Bogdan


It seems you are expecting the find()-method to behave differently. From the docs

Find a model by its primary key.
like image 22
sevenforce Avatar answered Oct 31 '22 21:10

sevenforce