在 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
最后请注意,访问器的名称可以是任何东西,例如 getFooAttribute
、getBarAttribute
、getBarBazAttribute
。在这种情况下,追加将受到保护 $appends = ['foo'];
并且您可以再次通过父模型访问枢轴的 foo
属性,例如 $game->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->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 中按多对多关系的数据透视表的字段进行排序