Reputation: 21
I followed the excellent answer given here: October CMS relation to self
But was left with one problem; it's a one-way relation. In my case I have a "domain" which can have many domains. However, although "domain A" is linked to "domain B" and "domain C", this wasn't the other way around. When editing "Domain B" it wasn't linked to "Domain A" when using the method given by Hardik.
Documentation states:
"To define the inverse of a many-to-many relationship, you simply place another $belongsToMany property on your related model."
, but this is impossible since the model can only have one $belongsToMany
property?
So how do I realize the inverse in a relation to itself?
Upvotes: 2
Views: 1372
Reputation: 865
So as I have done a couple self referencing relationships I have found a many-to-many relationship function uses the primary model is the key
and the joining model is the otherKey
. This is always how the interpreter works. Here examples and solutions I have found.
Here is a belongsToMany relationship
public $belongsToMany = [
'relation' => [
'Author\Plugin\Models\Datas',
'table' => 'author_plugin_datapivot',
'key' => 'relation_one',
'otherKey' => 'relation_two'
]
];
To get the two way many to many relationship working the pivot table needs to look like this. relation_one contains record.id
| relation_two contains relation.id
and the recursive relation.id
| record.id
.
Solution 1 - Create an inverseRelation - Problem with this is now you have to check the model for a relation
and an inverseRelation
.
public $belongsToMany = [
'relation' => [
'Author\Plugin\Models\Datas',
'table' => 'author_plugin_datapivot',
'key' => 'relation_one',
'otherKey' => 'relation_two'
],
'inverseRelation' => [
'Author\Plugin\Models\Datas',
'table' => 'author_plugin_datapivot',
'key' => 'relation_two',
'otherKey' => 'relation_one'
]
];
Solution 2 - Create a function afterSave -- I couldn't get this to work how I wanted - I believe this is possible, my theory was to access the model's relations and then iterate through them to attach this record. However I think attaching the relation is done after the model is saved so you don't have access to the relations yet. There are probably ways to use this method still like maybe a temporary field that holds the id's of the records you want to save. I am not going to try it though.
public function afterSave()
{
$relations = $this->relations;
dd($this);
foreach ($relations as $relation) {
$relation->relations()->attach($this);
}
}
Solution 3 - Create a component/class function - I chose this because I hardly use the backend to edit model data. I created a class function that handles attaching the relations recursively. Key things to note that I found it faster to remove all attached relations (detach()
) then checking to see if I am attaching a duplicate. This is important because you will get an error for attaching duplicates. Also note that using a class function I can look for unique properties where I wouldn't want to use a many-to-many relationship.
public function attachMany($field, $record, $relation)
{
if ($record->relations->first()) {
foreach ($record->relations as $relation) {
$relation->relations()->detach($record);
$record->relations()->detach($relation);
}
}
if ($field->unique) {
$relationRecord->relation_bto()->add($record);
} else {
$relationRecord->relations()->attach($record);
$record->relations()->attach($relationRecord);
}
}
PS I would be curious to know if anyone has found the most optimal way to do this. These are the solutions I have found and so far I have gotten by.
Upvotes: 1