Php 同一模型上的Laravel-Manytomy关系
我试图在我的标签模型上建立一个双向的多人关系,但我遇到了这个“问题” 我的模型如下所示:Php 同一模型上的Laravel-Manytomy关系,php,mysql,laravel,eloquent,relationship,Php,Mysql,Laravel,Eloquent,Relationship,我试图在我的标签模型上建立一个双向的多人关系,但我遇到了这个“问题” 我的模型如下所示: <?php namespace App; use Illuminate\Database\Eloquent\Model; class Tag extends Model { protected $table = 'tags'; public $timestamps = false; public function tags() { return
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $table = 'tags';
public $timestamps = false;
public function tags()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_one_id', 'tag_two_id');
}
}
+----+------------+------------+
| id | tag_one_id | tag_two_id |
+----+------------+------------+
| 1 | 1 | 2 |
+----+------------+------------+
public function tags($tag1 = 'tag_one_id', $tag2 = 'tag_two_id')
{
return $this->belongsToMany(Tag::class, 'tag_tag', $tag1, $tag2);
}
当我尝试此代码时:
$tag = Tag::find(1);
$tag->tags()->get();
$tag = Tag::find(2);
$tag->tags()->get();
我得到了Tag2实例,它是正确的
但当我尝试运行此代码时:
$tag = Tag::find(1);
$tag->tags()->get();
$tag = Tag::find(2);
$tag->tags()->get();
我想接收Tag1实例,但我没有
使用Laravel default Eloquent在模型上只使用一种方法就可以完成吗?这是可能的。您必须将一个参数传递给
tags()
方法,并使用该参数修改关系上的主键/外键字段。不过,这可能是一个必须要处理的全部痛苦,而且几乎可以肯定的是,仅仅采用第二种关系方法不会那么令人头痛。结果会是这样的:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $table = 'tags';
public $timestamps = false;
public function tags()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_one_id', 'tag_two_id');
}
}
+----+------------+------------+
| id | tag_one_id | tag_two_id |
+----+------------+------------+
| 1 | 1 | 2 |
+----+------------+------------+
public function tags($tag1 = 'tag_one_id', $tag2 = 'tag_two_id')
{
return $this->belongsToMany(Tag::class, 'tag_tag', $tag1, $tag2);
}
然后,当您需要Tag::find(2)->tags('Tag\u two\u id','Tag\u one\u id')时,只需修改这些值即可。
可以按如下所述加载:
您的用例可能比您的帖子所建议的要复杂得多,这可能会使它更合理。事实上,我会考虑一些其他的选择。 为什么它不起作用? 它不起作用,因为在您在
标记中添加的关系中,模型被定义为单向工作。但情况并非相反
如果我们可以定义两个名为tags()
的方法,它将起作用,如下所示:
public function tags()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_one_id', 'tag_two_id');
}
//and
public function tags()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_two_id', 'tag_one_id');
}
不幸的是,这是不可能的
那么,可能的解决方案是什么
一个可能的解决办法是,不要触碰这种关系。相反,如果您能够设法为这些关系插入两个关系,那么它将起作用。
例如:
+----+------------+------------+
| id | tag_one_id | tag_two_id |
+----+------------+------------+
| 1 | 1 | 2 |
+----+------------+------------+
| 1 | 2 | 1 |
+----+------------+------------+
这就是我现在想到的解决办法。也许还有更好的解决办法 我找到了一个解决方案,我就是这样解决的
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* @inheritdoc
*
* @var string
*/
protected $table = 'tags';
/**
* @inheritdoc
*
* @var bool
*/
public $timestamps = false;
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
/**
* Every tag can contain many related tags (TagOne has many TagTwo).
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
protected function tagsOneTwo()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_one_id', 'tag_two_id');
}
/**
* Every tag can contain many related tags (TagTwo has many TagOne).
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
protected function tagsTwoOne()
{
return $this->belongsToMany(Tag::class, 'tag_tag', 'tag_two_id', 'tag_one_id');
}
/**
* This method returns a collection with all the tags related with this tag.
* It is not a real relation, but emulates it.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function tags()
{
return $this->tagsOneTwo()->get()->merge($this->tagsTwoOne()->get())->unique('id');
}
/*
|--------------------------------------------------------------------------
| FUNCTIONS
|--------------------------------------------------------------------------
*/
/**
* Function to relate two tags together.
*
* @param Tag $tag
* @return void;
*/
public function attach(Tag $tag)
{
if ($this->tags()->contains('id', $tag->getKey())) {
return;
}
$this->tagsOneTwo()->attach($tag->getKey());
}
/**
* Function to un-relate two tags.
*
* @param Tag $tag
* @return void;
*/
public function detach(Tag $tag)
{
if ($this->tags()->contains('id', $tag->getKey())) {
// Detach the relationship in both ways.
$this->tagsOneTwo()->detach($tag->getKey());
$this->tagsTwoOne()->detach($tag->getKey());
}
}
/*
|--------------------------------------------------------------------------
| ACCESORS
|--------------------------------------------------------------------------
*/
/**
* Let access the related tags like if it was preloaded ($tag->tags).
*
* @return mixed
*/
public function getTagsAttribute()
{
if (! array_key_exists('tags', $this->relations)) {
$this->setRelation('tags', $this->tags());
};
return $this->getRelation('tags');
}
}
实际上,我已经考虑过了,但问题是我必须合并这两个关系(tag\u one\u id->tag\u two\u id和tag\u two\u id->tag\u one\u id)。我不确定你的意思。我希望这样,但在某种程度上,我仍然可以从该方法返回一个关系。啊,所以您不希望查询生成器执行SQL。就像那个例子中的访问器一样,但它返回一个关系?是的,确切地说,这是可能的吗?