motinska94's avatar

Should I remove ->cascadeOnDelete() if I want to use static::deleting method?

I have a structure like User -> Topic -> Category -> Page -> Resource going down a belongsTo/hasMany relationship chain.

A resource can have a file upload, and while deleting a resource I want the file it has (if it has) to be deleted. And I added that logic with the following code in my Resource.php model file.

protected static function boot()
{
    parent::boot();
    static::deleting(function (Resource $resource) {
        if ($resource->has_file) {
            Storage::disk('public')->delete($resource->data['path']);
        }
    });
}

This does work when I delete a resource with something like $resource->delete(). However it does not trigger when I do $page->delete(), $category->delete(), or $topic->delete() which I need it to.

From the Laravel Docs :

When executing a mass delete statement via Eloquent, the deleting and deleted model events will not be dispatched for the deleted models. This is because the models are never actually retrieved when executing the delete statement.

Does this mean I have to remove ->cascadeOnDelete() method call from resource migration file and handle deletion in a foreach loop on something like static::deleting() method of the Page model? But then there'll be the same issue when I'm deleting a Category, or Topic, or even User.

What would be the best way to approach this? Remove cascade on all the models and write the same foreach resource loop on all models static::deleting method?

0 likes
2 replies
Glukinho's avatar

I think you misunderstand what is "cascade on delete". It is not Laravel logic "when a model is deleted, delete related models too" or "...fire deleting events on related models".

It works only on database level: if a row is deleted and has foreign keys to other rows in other tables, then these connected rows will be deleted too.

Laravel doesn't know when a row in a table is deleted due to cascade on delete happened. That's why when you delete a Page model no events are raised on Resource model even if a row in resources table is actually deleted.

How about you have a scheduled task which regularly deletes orphaned files that don't belong to any existing resources? It will let you keep models logic cleaner.

update: static method name shoud be booted(), not boot

krisi_gjika's avatar

why do this in an event anyway? When you delete a Page you should loop any of it's Resource, something like

class PageService
{
  public function __construct(protected ResourceService $resourceService)
  {}

  public function delete(Page $page)
  {
    $page->resources()->each(function (Resource $resource) {
      	$this->resourceService->delete($resource);
    });

    $page->delete();
  }

and so on if you delete Category, Topic, User

Please or to participate in this conversation.