Существует некоторое базовое понимание / теория, в которой я отсутствует. Я не понимаю разницы между этими вызовами функций:
$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); }
$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_id
– 1
, 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.