我有一个代表用户报告的模型.报表模型具有多态关系,可以包含配方或注释.
目标是能够删除评论或用户,并通过eloquent删除相关报告.
使用我当前的设置(如下所示),这不起作用,当删除评论时报告仍然存在并导致错误,因为它现在指向不存在的评论.
我究竟做错了什么?我的多态模型是否需要“belongsTo”关系?如果是这样,当关系是可变形的时候,我该如何建立这种关系呢?
楷模
多态模型
class Report extends Model {
public function reportable() {
return $this->morphTo();
}
public function User() {
return $this->belongsTo('App\User');
}
}
食谱模型
class Recipe extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
评论模型
class RecipeComment extends Model {
public function user() {
return $this->belongsTo('App\User');
}
public function reports() {
return $this->morphMany('App\Report', 'reportable');
}
}
解决方法:
Laravel没有内置任何内容来自动删除相关记录.您需要自己构建此功能,这可以使用Model事件完成.通常,我设置了一个删除事件,负责删除事务中的相关记录.
Laravel 5 model observer看起来像这样:
class RecipeCommentObserver {
public function deleting($model) {
try {
DB::transaction(function() use ($model) {
/**
* Try to delete the necessary related objects when this object is deleted.
*/
// detach the many-manys from this model, which will delete
// the records in the pivot table.
// e.g. if you had a many-many relationship named 'tags':
// $model->tags()->detach();
// the one-one and one-many relations to try and delete
// for your example, you probably only want 'reports' here.
// you probably don't to delete the user when deleting a comment.
$relations = ['reports'];
foreach ($relations as $relation) {
// get a list of all the related ids for this relation
$ids = $model->$relation()->lists('id');
// use the ->destroy method so any events get fired for the deleted objects
// if the amount deleted is less than expected, an error occurred
if (!empty($ids) && $model->$relation()->getRelated()->destroy($ids) < count($ids)) {
throw new Exception('Error occurred deleting ' . $relation);
}
}
});
} catch (Exception $e) {
throw $e;
}
}
}
使用此类设置,您可以在app / Providers / EventServiceProvider.php中的boot()方法中注册观察者:
public function boot(DispatcherContract $events) {
parent::boot($events);
RecipeComment::observe(new RecipeCommentObserver());
}