Разница между вызовами метода $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);
}
Ответы
Ответ 1
Короткий ответ
$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
он проверяет, действительно ли отношение уже загружено (существует в 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()
.
Ответ 2
Когда вы работаете с отношениями с Eloquent, это свойство представляет собой коллекцию (Illuminate\Database\Eloquent\Collection
) вашего отношения white, метод - это начало новый запрос.
Скажите, что ваша модель выглядит так:
class User extends Eloquent {
public function roles()
{
return $this->belongsToMany('Role');
}
}
Если вы попытаетесь получить доступ к $user->roles
, 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
), когда метод позволяет настроить ваш запрос.
Ответ 3
Возможно, это будет полезно.
Доступ к методу:
$object->method();
Доступ к собственности:
$object->property;
Ответ 4
$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- > beers;
Ответ 5
Прямой ответ на ваш вопрос:
-
$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). Вы можете узнать больше об этом здесь.
Ответ 6
Представьте, что класс хранилища выглядит следующим образом:
<?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.