我有一个将用户连接到工作区的数据透视表。在数据透视表上,我还有一个role列,它定义了该工作空间的用户角色。我可以提供Accessor(Getter)& Mutator(Setter)方法对pivot表内的角色有何影响?我一直在努力寻找,但是雄辩的数据透视表的细节非常稀少。
我不确定是否需要设置自定义枢轴模型?如果我这样做,一个例子就会很棒,因为关于枢轴模型的文档是非常基础的。
感谢。
答案 0 :(得分:9)
如果你需要做的只是访问数据透视表上的其他字段,你只需要在关系定义中使用withPivot()
方法:
class User extends Model {
public function workspaces() {
return $this->belongsToMany('App\Models\Workspace')->withPivot('role');
}
}
class Workspace extends Model {
public function users() {
return $this->belongsToMany('App\Models\User')->withPivot('role');
}
}
现在您的角色字段将在数据透视表中提供:
$user = User::first();
// get data
foreach($user->workspaces as $workspace) {
var_dump($workspace->pivot->role);
}
// set data
$workspaceId = $user->workspaces->first()->id;
$user->workspaces()->updateExistingPivot($workspaceId, ['role' => 'new role value']);
如果您确实需要为数据透视表创建访问器/更改器,则需要创建自定义数据透视表类。我之前没有这样做过,所以我不知道这是否真的有用,但看起来你会这样做:
创建一个包含访问者/ mutator的新pivot类。此类应扩展默认的Pivot类。这个新类是当User或Workspace创建Pivot模型实例时将要实例化的类。
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class UserWorkspacePivot extends Pivot {
getRoleAttribute() {
...
}
setRoleAttribute() {
...
}
}
现在,更新您的用户和工作区模型以创建此新的数据透视表类,而不是默认的类。这是通过覆盖Model类提供的newPivot()
方法来完成的。您希望覆盖此方法,以便创建新UserWorkspacePivot类的实例,而不是默认的Pivot类。
class User extends Model {
// normal many-to-many relationship to workspaces
public function workspaces() {
// don't forget to add in additional fields using withPivot()
return $this->belongsToMany('App\Models\Workspace')->withPivot('role');
}
// method override to instantiate custom pivot class
public function newPivot(Model $parent, array $attributes, $table, $exists) {
return new UserWorkspacePivot($parent, $attributes, $table, $exists);
}
}
class Workspace extends Model {
// normal many-to-many relationship to users
public function users() {
// don't forget to add in additional fields using withPivot()
return $this->belongsToMany('App\Models\User')->withPivot('role');
}
// method override to instantiate custom pivot class
public function newPivot(Model $parent, array $attributes, $table, $exists) {
return new UserWorkspacePivot($parent, $attributes, $table, $exists);
}
}
答案 1 :(得分:0)
这是一个棘手的问题。我能想到的解决方案很臭,可能会在以后引起一些问题。
我将延伸Patricus的答案以使其发挥作用。
我打算评论帕特里克斯的回答,但是有太多的东西无法解释。要使他的解决方案适用于attach
和sync
,我们必须做一些丑陋的事情。
问题
首先让我们用他的解决方案来识别问题。他的getter和setter确实有效,但在运行sync
,attach
或detach
时,belongsToMany关系不使用Pivot模型。这意味着每当我们使用$attributes
参数调用其中一个时,非变异数据将被放入数据库列。
// This will skip the mutator on our extended Pivot class
$user->workspaces()->attach($workspace, ['role' => 'new role value']);
我们可以只是试着记住,每当我们调用其中一个时,我们就不能使用第二个参数来附加变异数据,只需使用必须的数据调用updateExistingPivot
变异。因此,attach
将是Patricus所说的:
$user->workspaces()->attach($workspace);
$user->workspaces()->updateExistingPivot($workspaceId, ['role' => 'new role value']);
我们永远不会使用正确的方式传递pivot属性作为第一个示例中显示的attach
方法第二个参数。这将导致更多的数据库语句和代码腐烂,因为您必须始终记住不要以正常方式执行。如果您假设每个开发人员,甚至您自己都知道不会将attach
方法与第二个参数一起使用,那么您可能会在以后遇到严重问题。
解决方案(未经测试且不完善)
为了能够在枢轴列上使用mutator调用attach
,你必须做一些疯狂的扩展。我没有对此进行过测试,但如果您想尝试一下,它可能会让您走上正确的道路。我们必须首先创建我们自己的关系类,扩展BelongsToMany
并实现我们的自定义attach
方法:
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class UserWorkspaceBelongsToMany extends BelongsToMany {
public function attach($id, array $attributes = [], $touch = true)
{
$role = $attributes['role'];
unset($attributes['role']);
parent::attach($id, $attributes, $touch);
$this->updateExistingPivot($id, ['role' => $role], $touch);
}
// You will need sync here too
}
现在我们必须让每个Model::belongsToMany
使用新的UserWorkspaceBelongsToMany
类而不是普通的BelongsToMany
。我们通过模拟User和Workspace类中的belongsToMany
来实现这一点:
// put this in the User and Workspace Class
public function userWorkspaceBelongsToMany($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null)
{
if (is_null($relation)) {
$relation = $this->getBelongsToManyCaller();
}
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey();
if (is_null($table)) {
$table = $this->joiningTable($related);
}
$query = $instance->newQuery();
return new UserWorkspaceBelongsToMany($query, $this, $table, $foreignKey, $otherKey, $relation);
}
正如您所看到的,我们仍在更多地调用数据库,但我们不必担心有人使用pivot属性调用attach
并且不会变异。
现在在模型中使用它而不是普通的belongsToMany:
class User extends Model {
public function workspaces() {
return $this->userWorkspaceBelongsToMany('App\Models\Workspace')->withPivot('role');
}
}
class Workspace extends Model {
public function users() {
return $this->userWorkspaceBelongsToMany('App\Models\User')->withPivot('role');
}
}
答案 2 :(得分:0)
无法使用设置器,不会影响数据透视表...而是在控制器中进行更改。
答案 3 :(得分:0)
我知道如何在数据透视表上使用 Accessors
和 Mutators
(我使用的是 Laravel 5.8)
您必须在 using()
关系中使用 belongsToMany
,例如:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
public function workspaces() {
return $this->belongsToMany('App\Workspace')->using('App\UserWorkspace');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Workspace extends Model {
public function users() {
return $this->belongsToMany('App\User')->using('App\UserWorkspace');
}
}
因此,使用您的 Pivot 模型:
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class UserWorkspace extends Pivot {
public function getRoleAttribute() {
// your code to getter here
}
public function setRoleAttribute($value) {
// your code to setter here
}
}