在 Eloquent 中使用带有数据透视表字段的访问器

Posted

技术标签:

【中文标题】在 Eloquent 中使用带有数据透视表字段的访问器【英文标题】:Using accessors with pivot table fields in Eloquent 【发布时间】:2013-06-16 06:37:36 【问题描述】:

我目前有一些模型通过 laravel 建立了多对多的关系。这是结构:

users
    id
    username
    ...

games
    id
    title
    ...

game_user
    game_id
    user_id
    system

现在,我的模型看起来有点像这样:

<?php

class Game extends Eloquent

    /**
     * A game is owned by many users
     *
     * @return mixed
     */
    public function user()
    
        return $this->belongsToMany('User')->withPivot('system');
    


<?php

class User extends Eloquent

    /**
     * A user has many games.
     *
     * @return mixed
     */
    public function games()
    
        return $this->belongsToMany('Game')->withPivot('system');
    

现在,一切正常。但是,我希望在数据透视表中的系统字段上使用增变器。我找不到关于此的任何文档,并且以下(在用户和游戏模型中)不起作用:

public function getSystemAttribute($val)

    return $val.' Testing';

【问题讨论】:

你能转储表的数据吗 我可以这样做,但这是非常基础的。 【参考方案1】:

我没有测试过,但这应该可以。

public function getSystemAttribute($value)

    return $this->pivot->system . ' Testing';


...

foreach ($user->games as $game)

    echo $game->system;

传入的值是从模型属性中提取的。没有系统属性,所以你应该得到 NULL。我们可以忽略这一点,直接从数据透视表中提取值。

【讨论】:

那里不需要 $value 参数。 为了访问 system 属性(在视图/控制器中),您需要先将属性名称添加到模型上的 appends 属性【参考方案2】:

您需要为枢轴的system 属性定义一个访问器,并将属性名称添加到模型上的 appends 属性。整个过程如下

1) 在父模型中定义一个访问器,我们要从中访问属性:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Game extends Model

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    public function getSystemAttribute() // the name can be anything e.g getFooAttribute
    
        return $this->pivot->system;
    

2) (避免获得 NULL!) 将属性名称添加到模型的 appends 属性中(参见here)。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = ['system']; 

3) 现在您可以从父模型访问新创建的system 属性:

$user = App\User::find($id);
foreach ($user->games as $game)

    echo $game->system;

当然,与每个访问器一样,您也可以在访问数据透视表之前“更改”它的值,例如:

public function getSystemAttribute()

    return $this->pivot->foo .'Hello word!'; //append the ""Hello word!" string to the end of the `foo` attribute value

最后请注意,访问器的名称可以是任何东西,例如 getFooAttributegetBarAttributegetBarBazAttribute。在这种情况下,追加将受到保护 $appends = ['foo']; 并且您可以再次通过父模型访问枢轴的 foo 属性,例如 $game-&gt;foo

【讨论】:

这个有问题。当您调用 Book 模型(不是关系)时,pivot 未定义 -> getSystemAttribute 错误。之前尝试检查pivot,我们总是得到system = null for Book::find(1)。如何只在关系方法中追加?【参考方案3】:

我发现这个问题很有趣,所以我开始研究代码。

如果您需要访问特定条目,这是我的解决方案:

public function getSystemAttribute($game)
    foreach($this->games as $value)
        if($value->id==$game->id)
            $value->pivot->system = 'foo';
            $value->pivot->save();
        
    

你可以简单地调用它:

$user->getSystemAttribute($game)

关于访问器,如果不迭代集合,我找不到任何其他方法。有更漂亮的方法来迭代集合,但这不是这个问题的范围。从documentation,您可以看到如何访问数据透视表的任何属性。

希望对你有帮助

【讨论】:

谢谢!我正在疯狂地环顾四周,想办法将数据添加到数据透视表中,而不是访问它,并且在任何地方都找不到任何东西。一切都只是附加枢轴,而不关心数据列......【参考方案4】:

如果您希望能够在您的响应(JSON 等)中插入您变异的 system 属性,那么您应该将以下内容添加到两个模型(游戏 + 用户)中。

protected $appends = array('system');

【讨论】:

仅作记录,如果您使用的是 Laravel >= 4.0.8,则这是有效的。此外,您仍然需要 'system' 属性访问器才能使该指令生效。【参考方案5】:

我的主要问题是我有一些 json 编码的对象作为文本存储在我的数据透视表中。我想自动编码和解码它们。

因此,由于缺乏真正的替代方案,我想出的是访问器(json 解码)功能的基本解决方法。我首先尝试使用approach provided by Collin James,但不喜欢它创建一个新的自定义属性而不是操作pivot-&gt;random_attribute

在我的表中,我总是有一个 id 属性,所以我为 id 属性编写了一个访问器并包含了数据透视数据操作。

public function getIdAttribute($id) 

    //Decode random_attribute
    if(isset($this->pivot->random_attribute)) 
        $this->pivot->random_attribute = json_decode($this->pivot->random_attribute);
    

    return $id;
 

不幸的是,我无法以类似的方式管理 mutator。但对我来说,访问器要重要得多。

【讨论】:

以上是关于在 Eloquent 中使用带有数据透视表字段的访问器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Eloquent ORM 中按多对多关系的数据透视表的字段进行排序

如何使用 Eloquent 在数据透视表中插入多行?

如何在 laravel 5 中使用 Eloquent 更新数据透视表

Eloquent 从数据透视表中获取数据

在 Eloquent 中将数据透视表与多个表连接起来

如何对 Eloquent 关系中的数据透视表列进行 GROUP 和 SUM?