方法调用之间的区别$ model-> relation(); 和$ model-> relation;

hod*_*ale 25 php arrays methods laravel

这里有一些我缺少的基本理解/理论.我不明白这些函数调用之间的区别:

$distributors = $store->distributors();
$distributors = $store->distributors;
$distributors = $store->distributors()->get();
$distributors = $store->distributors->get();
Run Code Online (Sandbox Code Playgroud)

我在这里要完成的是获得一个商店经销商列表(多对多的关系),他们将每个经销商的啤酒列表列入一个巨大的列表.

foreach ($distributors as $distributor) 
{
    $available_beers = array_merge($distributor->beers(), $available_beers);
}
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是最好的方法,我无法让它工作.与第一个方法列表类似,我不知道我是否需要->$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);
}
Run Code Online (Sandbox Code Playgroud)

luk*_*ter 49

简短的回答

$model->relation()返回关系对象

$model->relation返回关系的结果


答案很长

$model->relation()可以解释得很简单.您正在调用您定义关系的实际功能.你的distributor看起来有点像这样:

public function distributors(){
    return $this->hasMany('Distributor');
}
Run Code Online (Sandbox Code Playgroud)

因此,在调用时$store->distributors(),只需获取其返回值为$this->hasMany('Distributor')的实例Illuminate\Database\Eloquent\Relations\HasMany

你什么时候使用它?

如果要在运行查询之前进一步指定查询,通常会调用关系函数.例如,添加where语句:

$distributors = $store->distributors()->where('priority', '>', 4)->get();
Run Code Online (Sandbox Code Playgroud)

当然你也可以这样做:$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);
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

4)最后,Laravel调用getResults()关系,然后在get()查询构建器实例上生成a.(这给出了相同的结果$model->relation()->get().

  • @FlexElektroDeimling 通过阅读文档和源代码;) (4认同)

pat*_*cus 6

直接回答你的问题:

  • $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');
    }
}
Run Code Online (Sandbox Code Playgroud)

调用关系方法 ( $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
Run Code Online (Sandbox Code Playgroud)

也可以使用with()查询上的方法“急切”加载关系。这样做是为了减轻延迟加载可能需要的所有额外查询(称为 n+1 问题)。您可以在此处阅读更多相关信息。


Mar*_*lln 5

当您使用 Eloquent 处理关系时,属性是关系的集合 ( Illuminate\Database\Eloquent\Collection),方法是新查询的开始。

假设您的模型如下所示:

class User extends Eloquent {

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

}
Run Code Online (Sandbox Code Playgroud)

如果您尝试访问$user->roles,Eloquent 将运行查询并通过魔术方法获取与该用户相关的所有角色,并返回 的实例Illuminate\Database\Eloquent\Collection。该类有一个名为 的方法get,这就是为什么$user->roles->get()适合您。

如果您尝试访问方法 ,$user->roles()您将获得一个查询构建器对象,以便您可以微调您的查询。

$user->roles()->whereIn('role_id', [1, 3, 4])->get();
Run Code Online (Sandbox Code Playgroud)

这只会返回role_idis 1, 3or 的角色4

因此,该属性返回完整的查询及其结果 ( Illuminate\Database\Eloquent\Collection),而该方法允许您自定义查询。