我正在制作一款游戏,我目前正在做添加游戏和关卡的管理部分。
我将游戏和关卡通过带有"顺序"列的数据透视表进行引用。
我的游戏模型:
class Game extends Eloquent {
public function levels() {
return $this->belongsToMany('Level')->withPivot('order');
}
}
我的关卡模型:
class Level extends Eloquent {
public function game() {
return $this->belongsToMany('Game')->withPivot('order');
}
}
我想实现的是在添加关卡时自动填充顺序列,并创建moveup()和movedown()函数。
我已经尝试在关卡模型上设置一个模型事件来实现这一点,但没有成功。
首先,这种顺序是单向的。你不能使用相同的列来显示游戏的关卡顺序,反之亦然。
现在,你可以实现你所需要的,例如通过重写attach
方法来检查当前的最大位置,并相应地添加next for insert(不是创建事件或任何东西,因为这与level
创建本身无关,而是将其附加到游戏中)。
也就是说,为了使用自定义的BelongsToMany
关系,您需要扩展Eloquent Model
或使用一个trait。像下面这样的内容应该可以完成这项工作(没有注释等,使其简洁)。
// Game model
class Game extends Eloquent {
use SortablePivotModelTrait;
public function levels()
{
return $this->sortableBelongsToMany('Level', 'order')->withPivot('order');
}
//...
}
// SortablePivotModelTrait.php
use Illuminate'Database'Eloquent'Model;
trait SortablePivotModelTrait {
public function sortableBelongsToMany($related, $orderColumn = null, $table = null, $foreignKey = null, $otherKey = null, $relation = null)
{
// all the code of belongsToMany method needs to go here
// ...
// then just:
return new SortableBelongsToMany($query, $this, $table, $foreignKey, $otherKey, $relation, $orderColumn);
}
}
// SortableBelongsToMany.php
use Illuminate'Database'Eloquent'Model;
use Illuminate'Database'Eloquent'Builder;
use Illuminate'Database'Eloquent'Relations'BelongsToMany;
class SortableBelongsToMany extends BelongsToMany {
protected $orderColumn;
public function __construct(Builder $query, Model $parent, $table, $foreignKey, $otherKey, $relationName = null, $orderColumn = 'order')
{
$this->orderColumn = $orderColumn;
parent::__construct($query, $parent, $table, $foreignKey, $otherKey, $relationName);
}
public function attach($id, array $attributes = array(), $touch = true)
{
$attributes = array_merge($attributes, [$this->getOrderColumnName() => $this->getNextPosition()]);
return parent::attach($id, $attributes, $touch);
}
public function getNextPosition()
{
return 1 + $this->newPivotQuery()->max($this->getOrderColumnName());
}
public function getOrderColumnName()
{
return $this->orderColumn;
}
}
你可以这样做:
$level = new Level;
// do some stuff with the created level
$game = Game::find($id);
// then
$game->save($level);
// or
$level->save();
$game->levels()->attach($level);