Framework: Calling delete() on a Model in a collection does not remove it from the collection

Created on 5 May 2015  路  4Comments  路  Source: laravel/framework

When iterating over an items in a collection and calling delete() on the item it does not remove it from the collection.

if (is_array($photos['delete'])) {
    foreach ($photos['delete'] as $deletedPhoto) {
        foreach ($listingMetaCollection as $listingMeta) {
            if ($listingMeta->meta_id === $deletedPhoto && substr($listingMeta->meta_key, 0, 6) === 'photo_') {
                $listingMeta->delete();
            }
        }
    }
}

foreach ($listingMetaCollection as $listingMeta) {
    $listingMeta->save();
}

In this example the query is being run to delete the instance of the $listingMeta model however because it still exists in the $listingMetaCollection collection, when the Save function is called on that it recreates all the deleted ones.

There is no clear documentation in the Laravel Docs/API Docs that indicate how best to handle this kind of model event.

The only work around that we have for this at the moment is unsetting the model from the collection.

if (is_array($photos['delete'])) {
    foreach ($photos['delete'] as $deletedPhoto) {
        foreach ($listingMetaCollection as $collectionKey => $listingMeta) {
            if ($listingMeta->meta_id === $deletedPhoto && substr($listingMeta->meta_key, 0, 6) === 'photo_') {
                $listingMeta->delete();
                $listingMetaCollection->forget($collectionKey);
            }
        }
    }
}

Is there a more eloquent way of handling this kind of operation?

Most helpful comment

I don't think it is hacky to be honest. If you think it might be unclear for another developer add a comment. Like:

// deleting in db
$listingMeta->delete();
// removing from collection
$listingMetaCollection->forget($collectionKey);

It would be possible to add a method to the collection class that calls delete on the model and then removes it from the collection. However I don't think it will make it into the core... You could create your own collection class and add such a method but honestly I think you should just stick with the code you have now.

All 4 comments

As an addendum, even when using &$listingMeta to act as a reference to the $listingMetaCollection set, this still won't unset from the Collection.

I don't know how this would be possible. The model itself doesn't know it's inside a collection - therefore it can't remove itself from it.

Even using the each function on the model as below:

$listingMetaCollection->each(function($listingMeta) use ($deletedPhoto) {
    $listingMeta->delete();
});

doesn't remove it from the collection.

@lukasgeiter: I understand this. I was wondering if there were a function I should be using in place of this to both remove an item from a collection and call a delete() in the DB at the same time, rather than having to manually unset the now deleted model from the collection.

It just seems like a really 'hacky' way to work around this.

I don't think it is hacky to be honest. If you think it might be unclear for another developer add a comment. Like:

// deleting in db
$listingMeta->delete();
// removing from collection
$listingMetaCollection->forget($collectionKey);

It would be possible to add a method to the collection class that calls delete on the model and then removes it from the collection. However I don't think it will make it into the core... You could create your own collection class and add such a method but honestly I think you should just stick with the code you have now.

Was this page helpful?
0 / 5 - 0 ratings