У меня есть модель, которая представляет отчет от пользователя. Модель отчета имеет полиморфное отношение, которое может содержать либо рецепт, либо комментарий.
Цель состоит в том, чтобы иметь возможность удалить комментарий или пользователя и удалить связанные отчеты с помощью eloquent.
При моей текущей настройке (см. Ниже) это не работает, при удалении комментария отчет остается и вызывает ошибку, поскольку теперь он указывает на несуществующий комментарий.
Что я делаю неправильно? Нужно ли мне иметь отношение «принадлежат» на моей полиморфной модели? Если так, как я могу построить эти отношения, когда связь может быть изменена?
Полиморфная модель
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 не имеет ничего встроенного для автоматического удаления связанных записей. Вам нужно создать эту функциональность самостоятельно, что можно сделать с помощью событий модели. Как правило, я настраиваю deleting
событие, которое заботится об удалении связанных записей внутри транзакции.
Ларавел 5 модельный наблюдатель будет выглядеть примерно так:
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;
}
}
}
С помощью этой настройки класса вы регистрируете наблюдателя в boot()
метод в app/Providers/EventServiceProvider.php
:
public function boot(DispatcherContract $events) {
parent::boot($events);
RecipeComment::observe(new RecipeCommentObserver());
}
Других решений пока нет …