如何解决Laravel在同一张桌子上属于ToMany:如何创建对称关系?
我正在使用Laravel nova构建管理面板。我有一个Items表,使用(当然)一个数据透视表,它本身具有一个belongsToMany。
这本身是有效的,但是当我指定项目A与项目B相关时,该关系的反函数将不会存储,从而导致在项目B上找不到该内容。
我需要它,因为这种关系是对称的,这意味着如果A与B有关,那么B也与A有关。
存储和检索关系的最佳方法是什么?
这是我当前定义关系的代码,并且以一种方式起作用。
class Item extends Model
{
public function related(): BelongsToMany
{
return $this->belongsToMany(Item::class,'item_related','item_id','related_id');
}
}
所以:假设我有一个包含项目A,B和C的表,并且关系在数据透视表中是这样定义的
item_id - related_id
A - B
A - C
B - C
因此,基本上,当我进行B->相关操作时,我希望它返回[A,C]。现在它将仅返回C,并且C根本没有任何相关项
这里有两种可能的解决方案,一种是同时插入逆关系,从而导致
item_id - related_id
A - B
B - A
A - C
C - A
B - C
C - B
这将产生正确的结果,但是如何自动强制laravel也保存反向关系,并确保删除等操作正确完成?
另一个选择是“合并”两个相关的belongsToMany调用。
class Item extends Model
{
public function related(): BelongsToMany
{
// return merged $this->relatedFrom and $this->relatedTo
}
public function relatedFrom(): BelongsToMany
{
return $this->belongsToMany(Item::class,'related_id','item_id');
}
public function relatedTo(): BelongsToMany
{
return $this->belongsToMany(Item::class,'related_id');
}
}
这也会引起各种各样的问题。
那么这里有什么好的方法?
解决方法
我选择了使用观察者和数据透视模型向数据透视表添加反向关系的方法
通常,当具有belongsToMany关系时,不会创建模型。在这种情况下,我需要一个,所以我手动创建了一个。
Pivot模型,请注意它扩展了Pivot而不是Model,将观察者添加到了boot方法中,并将$ timestamps设置为false:
namespace App\Models;
use App\Observers\RelationObserver;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ItemRelated extends Pivot
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'item_related';
public $timestamps = false;
public static function boot(): void
{
parent::boot();
parent::observe(new RelationObserver);
}
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'item_id','related_id',];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'item_id' => 'integer','related_id' => 'integer',];
}
观察者只需要一个创建和删除的方法,分别插入或删除另一个后,就插入和删除反向关系:
namespace App\Observers;
use App\Models\ItemRelated;
class RelationObserver
{
public function created(ItemRelated $itemRelated): void
{
if (ItemRelated::where([
['item_id','=',$itemRelated->related_id],['related_id',$itemRelated->item_id],])->doesntExist()) {
$itemRelatedReverse = new ItemRelated();
$itemRelatedReverse->item_id = $itemRelated->related_id;
$itemRelatedReverse->related_id = $itemRelated->item_id;
$itemRelatedReverse->save();
}
}
public function deleted(ItemRelated $itemRelated): void
{
ItemRelated::where([
['item_id',])->delete();
}
}
最后,我需要通过链接using方法来告诉Item表上的关系使用数据透视表:
public function related(): BelongsToMany
{
return $this->belongsToMany(Item::class,'item_related','item_id','related_id')
->using(ItemRelated::class);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。