before/after delete - strange behavior

I've noticed that beforeDelete and afterDelete callbacks are fired only if we use $record->delete().

deleteAll() and deleteByPk() do the raw sql query, without any triggers.

Is it by design?

Actually, I want related records to be deleted when the main record is deleted.

I cannot do it by DB constraints (on delete cascade) because of some extra things that should be done before the record is deleted (for example, unlink some attached files, write data to log and so on).

Should I grab all related records and then call delete() on each of them? Or there's a better way?

PS. extra param in relation definition (like 'dependent' => true) that allows related records to be deleted automatically would be sooooo nice… )))

I think, this is by design. deleteAll() can use the much faster 'DELETE FROM …' statement. Like you said, you'll have to fetch all records first and call delete() on them.

Maybe a behavior would be a nice option so that developers can add this on demand? It could add two new "enhanced" methods (bad name suggestion: fullDeleteAll() and fullDeleteByPk()…) that fetch all records and call delete().

I agree on deleteAll(), because there's no way to delete related record without grabbing list of IDs first. But the behavior of deleteByPk() was quite unexpected for me.

Should I really use two steps approach (findByPk() + delete())? Isn't it a little bit redundant?

Seems like I've missed something and there's much better way.

Well, this might be true for related records. But you can do much more in beforeDelete()/afterDelete() than only delete related records. That's why the same is true for deleteByPk(): You would need another "SELECT…" to fetch the record attributes. Otherwhise attributes wouldn't be available in the before/afterDeletes.

Maybe the easier approach for you would be to simply add a method like "deleteWithRelated()" and delete related records from there manually, before you delete the records in your main table.

Thank you so much for the information Mike!

It seems logic that you first need to load the record or otherwise attributes wont be available.

Searched quite a while before I found this topic on why afterDelete() was not called after calling deleteByPk()

I think this should be in the documentation/guide.

The logic is simple. delete() is applied to the current model instance and deleteAll()/deleteByPk() are applied to many table rows without creating model instances, so there is no chance before/after delete events will be raised. But I agree it should be mentioned in API.