Skip to content
Advertisement

Difference between method calls $model->relation(); and $model->relation;

There is some basic understanding/theory here that I am missing.I don’t understand the difference between these function calls:

$distributors = $store->distributors();
$distributors = $store->distributors;
$distributors = $store->distributors()->get();
$distributors = $store->distributors->get();

What I am trying to accomplis here is to get a list of the distributors for a store (a many to many relationship), and they get each distributors list of beers into one giant list.

foreach ($distributors as $distributor) 
{
    $available_beers = array_merge($distributor->beers(), $available_beers);
}

I don’t know if that is the best way to do this and I can’t get it to work. Similar to the first list of methods, I don’t know if I need ->$beers or ->$beers()

Update

Thanks to everyone who answered! This will be a good reference for me going forward. My biggest lesson was the difference between getting a collection back, vs getting the query builder/relationship object back. For future reference to those who find this question, here is what I set up in my controller:

$store = $this->store->find($id)->first();
$distributors = $store->distributors;
$beers = [];
foreach ($distributors as $distributor){
    $beers = array_merge($distributor->beers->lists('name', 'id'), $beers);
}

Advertisement

Answer

Short answer

$model->relation() returns the relationship object

$model->relation returns the result of the relationship


Long answer

$model->relation() can be explained pretty simple. You’re calling the actual function you defined your relation with. Yours for distributor probably looks somewhat like this:

public function distributors(){
    return $this->hasMany('Distributor');
}

So when calling $store->distributors() you just get the return value of $this->hasMany('Distributor') which is an instance of IlluminateDatabaseEloquentRelationsHasMany

When do you use it?

You usually would call the relationship function if you want to further specify the query before you run it. For example add a where statement:

$distributors = $store->distributors()->where('priority', '>', 4)->get();

Of course you can also just do this: $store->distributors()->get() but that has the same result as $store->distributors.


Which brings me to the explanation of the dynamic relationship property.

Laravel does some things under the hood to allow you to directly access the results of a relationship as property. Like: $model->relation.

Here’s what happens in IlluminateDatabaseEloquentModel

1) The properties don’t actually exist. So if you access $store->distributors the call will be proxied to __get()

2) This method then calls getAttribute with the property name getAttribute('distributors')

public function __get($key)
{
    return $this->getAttribute($key);
}

3) In getAttribute it checks if the relationship is already loaded (exists in relations). If not and if a relationship method exists it will load the relation (getRelationshipFromMethod)

public function getAttribute($key)
{
    // code omitted for brevity

    if (array_key_exists($key, $this->relations))
    {
        return $this->relations[$key];
    }

    $camelKey = camel_case($key);

    if (method_exists($this, $camelKey))
    {
        return $this->getRelationshipFromMethod($key, $camelKey);
    }
}

4) In the end Laravel calls getResults() on the relation which then results in a get() on the query builder instance. (And that gives the same result as $model->relation()->get().

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement