问题
I'm extending the rainlab.user
plugin to allow each user to have friends via a simple intermediate table with the following fields:
user_id
friend_id
status
I've extended the User
model:
use RainLab\User\Models\User as FrontUser;
FrontUser::extend(function($model) {
$model->belongsToMany['friends']=[
'RainLab\User\Models\User',
'table' => 'meysam_social_friends',
'pivot' => ['status'],
'pivotModel' => 'Meysam\Social\Models\FriendsPivot',
'timestamps' => true,
'key' => 'user_id',
'otherKey' => 'friend_id'
];
$model->addDynamicMethod('isFriendWith', function (FrontUser $user) use ($model) {
$model->friends->contains($user->id);
});
$model->addDynamicMethod('addFriend', function (FrontUser $user) use ($model) {
$model->friends()->attach($user->id);
});
$model->addDynamicMethod('removeFriend', function (FrontUser $user) use ($model) {
$model->friends()->detach($user->id);
});
});
And also extended the Rainlab.User Controller
to have Friends
tab where all friends of a user are listed and can be added and removed:
use RainLab\User\Controllers\Users as UsersController;
UsersController::extend(function($controller) {
if(!isset($controller->implement['Backend.Behaviors.RelationController'])) {
$controller->implement[] = 'Backend.Behaviors.RelationController';
}
$controller->relationConfig = '$/meysam/social/controllers/user/config_relations.yaml';
});
UsersController::extendFormFields(function($form, $model, $context) {
if(!$model instanceof FrontUser or $context != 'preview'){
// friends tab should not be displayed in update and create contexts
return;
}
$form->addTabFields([
'friends' => [
'label' => '',
'tab' => 'Friends',
'type' => 'partial',
'path' => '$/meysam/social/controllers/user/_friends.htm',
]
]);
});
Now I need to maintain a two-way friendship relationship. i.e. whenever user_id
and friend_id
is added to the friends
table, I want to automatically add friend_id
and user_id
to the table as well. To achieve this, I implemented afterSave
and beforeSave
in the FriendsPivot
model:
class FriendsPivot extends Pivot
{
/*
* Validation
*/
public $rules = [
'status' => 'required'
];
public $belongsTo = [
'user' => ['RainLab\User\Models\User', 'key' => 'user_id'],
'friend' => ['RainLab\User\Models\User', 'key' => 'friend_id']
];
public function getStatusOptions()
{
return [
1 => 'Pending',
2 => 'Approved',
3 => 'Blocked',
];
}
public function afterSave()
{
Log::info('Saving pivot...');
if(!$this->friend->isFriendWith($this->user)) {
$this->friend->addFriend($this->user);
}
}
public function beforeDelete()
{
Log::info('Deleting pivot...');
if($this->friend->isFriendWith($this->user)) {
$this->friend->removeFriend($this->user);
}
}
}
The problem is that beforeDelete
is never called. afterSave
gets called but beforeDelete
never gets called and therefor the inverse of the relationship is not deleted (user_id
-friend_id
gets removed from database but friend_id
-user_id
does not get deleted). Why is beforeDelete
not called? Is there anything I'm doing wrong? Is there any better way to maintain a two-way friendship relation?
回答1:
I found this post because I'm trying to do exactly the same thing as you. If you have solved this then I wonder if you would be willing to share your solution?
回答2:
This sounds very odd at first, but maybe this is because of the special delete behavior of the Pivot model. It appears that it builds a raw query using the QueryBuilder and thus bypasses any regular Eloquent (October) events. In my eyes, the best solution would be to trigger the delete event manually in the delete method, but I'm unsure if this has any side effects. Maybe you could test that and prepare a PR on Github if it works.
来源:https://stackoverflow.com/questions/42740344/octobercms-how-to-maintain-a-two-way-friendship-relation