Разница между вызовами метода $ model-> relation (); и $ model-> отношение;

Существует некоторое базовое понимание / теория, в которой я отсутствует. Я не понимаю разницы между этими вызовами функций:

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

То, что я пытаюсь сделать, состоит в том, чтобы получить список дистрибьюторов для магазина (отношения многих и многих), и они получают список дистрибьюторов пива в один гигантский список.

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

Я не знаю, это лучший способ сделать это, и я не могу заставить его работать. Как и в первом списке методов, я не знаю, нужно ли мне ->$beers или ->$beers()

Обновить

Спасибо всем, кто ответил! Это будет хорошей ссылкой для меня в будущем. Мой самый большой урок заключался в различии между возвратом коллекции, а также возвратом объекта построителя запросов / отношения. Для дальнейшего обращения к тем, кто находит этот вопрос, вот что я установил в своем контроллере:

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

Solutions Collecting From Web of "Разница между вызовами метода $ model-> relation (); и $ model-> отношение;"

Короткий ответ

$model->relation() возвращает объект отношения

$model->relation возвращает результат отношения

Длительный ответ

$model->relation() можно объяснить довольно просто. Вы называете фактическую функцию, с которой вы определили свою связь. Ваш для distributor вероятно, выглядит примерно так:

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

Поэтому при вызове $store->distributors() вы получаете только возвращаемое значение $this->hasMany('Distributor') которое является экземпляром Illuminate\Database\Eloquent\Relations\HasMany

Когда вы его используете?

Обычно вы вызываете функцию отношений, если хотите дополнительно указать запрос перед его запуском. Например, добавьте оператор where:

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

Конечно, вы также можете просто сделать это: $store->distributors()->get() но имеет тот же результат, что и $store->distributors .


Это подводит меня к объяснению свойства динамических отношений .

Laravel делает некоторые вещи под капотом, чтобы позволить вам напрямую получать доступ к результатам отношений как собственности. Например: $model->relation .

Вот что происходит в Illuminate\Database\Eloquent\Model

1) Свойства фактически не существуют. Поэтому, если вы обратитесь к $store->distributors вызов будет проксирован на __get()

2) Этот метод затем вызывает getAttribute с именем свойства getAttribute('distributors')

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

3) В getAttribute он проверяет, getAttribute ли отношение уже загружено (существует в relations ). Если нет, и если существует метод отношений, он будет загружать отношение ( 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) В конце Laravel вызывает getResults() в отношении, которое затем приводит к get() в экземпляре построителя запроса. (И это дает тот же результат, что и $model->relation()->get() .

Когда вы работаете с отношениями с Eloquent, свойство представляет собой набор ( Illuminate\Database\Eloquent\Collection ) вашего отношения white, метод является началом нового запроса.

Скажите, что ваша модель выглядит так:

 class User extends Eloquent { public function roles() { return $this->belongsToMany('Role'); } } 

Если вы попытаетесь получить доступ к $user->roles role, Eloquent запустит запрос и выберет все роли, связанные с этим пользователем, благодаря магическим методам и вернет экземпляр Illuminate\Database\Eloquent\Collection . У этого класса есть метод, называемый get , поэтому для вас работает $user->roles->get() .

Если вы попытаетесь получить доступ к методу, $user->roles() , вместо этого вы получите объект построителя запросов, чтобы вы могли точно настроить ваш запрос.

 $user->roles()->whereIn('role_id', [1, 3, 4])->get(); 

Это будет возвращать только роли, где role_id1 , 3 или 4 .

Таким образом, свойство возвращает полный запрос, и это приводит к ( Illuminate\Database\Eloquent\Collection ), в то время как метод позволяет настроить ваш запрос.

Может быть, это будет полезно.

Доступ к методу:

 $object->method(); 

Доступ к собственности:

 $object->property; 

$ distributors = $ store-> distributors (); Результат метода (функции)

$ distributors = $ store-> дистрибьюторы; Значение свойства (переменной)

$ distributors = $ store-> distributors () -> get (); Возьмите первый, где это результат метода, если метод возвращает объект, это метод в том возвращенном объекте.

$ distributors = $ store-> distributors-> get (); Если свойство является объектом, то оно вызывает метод в этом свойстве, являющемся объектом.

Re -> $ beers vs -> $ beers () – это динамическое имя свойства / метода в зависимости от того, для чего вы. Просто сделав действительно грубое предположение о том, что вы делаете, в своем классе вы будете иметь

$ this-> beers = array ('bud', 'miller', 'sam');

и в вашем коде, используя объект $ store, вы на самом деле собираетесь что-то вроде

$ drink_type = 'пиво'; $ drink_list = $ store -> $ drink_type;

И это вернет $ this-> пиво из $ store, так же, как писать $ store-> пиво;

Прямой ответ на ваш вопрос:

  • $store->distributors() вернут фактический объект отношения (\ Illuminate \ Database \ Eloquent \ Relations \ BelongsToMany).
  • $store->distributors – это коллекция, содержащая результаты запроса отношения (\ Illuminate \ Database \ Eloquent \ Collection).
  • $store->distributors()->get() будет сборником, содержащим результаты запроса отношения (\ Illuminate \ Database \ Eloquent \ Collection).
  • $store->distributors->get() должен возвращать ошибку, так как вы вызываете get() в объекте Collection, а первый параметр не является необязательным. Если не ошибка, она должна хотя бы вернуть значение null.

Больше информации:

Учитывая следующую модель:

 class Store extends Eloquent { public function distributors() { return $this->belongsToMany('Distributor'); } } 

Вызов метода отношений ( $store->distributors() ) вернет вам отношение (\ Illuminate \ Database \ Eloquent \ Relations \ BelongsToMany) объекта. Это в основном объект запроса, который вы можете продолжать изменять, но вам все равно нужно вызвать некоторый тип метода для получения результатов (например, get() , first() и т. Д.).

Однако доступ к атрибуту отношения ( $store->distributors ) возвратит вам объект коллекции (\ Illuminate \ Database \ Eloquent \ Collection), содержащий результаты выполнения запроса отношения.

По умолчанию атрибут отношения создается и присваивается значение при первом доступе (известном как «ленивая загрузка»). Итак, при первом доступе к $store->distributors , за кулисами выполняется запрос отношения, сохраняя результаты в атрибуте $store->distributors и затем возвращая эти результаты. Однако он делает это только один раз. В следующий раз, когда вы $store->distributors , атрибут уже содержит данные, так что это то, к чему вы обращаетесь.

Чтобы проиллюстрировать это:

 // the following two statements will run the query twice $r1 = $store->distributors()->get(); $r2 = $store->distributors()->get(); // the following two statements will run the query once. // the first statement runs the query, populates $store->distributors, and assigns the variable // the second statement just accesses the data now stored in $store->distributors $r3 = $store->distributors; $r4 = $store->distributors; // at the end, $r1 == $r2 == $r3 == $r4 

Отношения также могут быть «нетерпеливыми» загруженными, используя метод with() в запросе. Это делается для облегчения всех дополнительных запросов, которые могут потребоваться для ленивой загрузки (известной как проблема n + 1). Вы можете узнать больше об этом здесь .

Представьте, что класс магазина выглядит следующим образом:

 <?php class Store { public $distributors; function __construct($distributors = array()) { $this->distributors = $distributors; } public function distributors() { return $this->distributors; } } 

Таким образом, разница заключается в следующем:

 $store = new Store(array('some guy', 'some other guy')); $guys = $store->distributors; # accesing the $distributors property $more = $store->distributors(); # calling the distributors() method.