Разница между вызовами метода $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.