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()
.