web-dev-qa-db-fra.com

Comment supprimer plusieurs enregistrements en utilisant Laravel Éloquent

Maintenant, d'après ce que je peux voir, cela aurait dû être simple. 

Je veux pouvoir supprimer plusieurs enregistrements de la base de données. J'ai la id 'de tous les enregistrements que je souhaite effacer. J'appelle la route resource.destroy en utilisant une liste d'identifiants séparés par des virgules (id est de type postgres uuid), comme suit:

Request URL:http://foo.app/products/62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5
Request Method:DELETE

De l’autre côté, l’action de mon contrôleur ressemble à ceci:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->delete();
    }
    catch(...) {
    }
}

Cela me donne l'erreur suivante:

BadMethodCallException in Macroable.php line 81:
Method delete does not exist.

in Macroable.php line 81
at Collection->__call('delete', array()) in ProductsController.php line 251
at Collection->delete() in ProductsController.php line 251
at ProductsController->destroy('62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5')

J'ai vérifié que find() renvoie une collection de products correspondant aux identifiants spécifiés.

Qu'est-ce que je rate?

PS: 1. Le modèle Product a plusieurs relations belongsTo avec d'autres modèles . 2. Le code product.destroy fonctionne bien si je lui passe une seule variable id

EDIT Je suppose, j'essaie aussi de comprendre quelle est la différence entre:

$org->products()->find($ids)->delete()

et 

$org->products()->whereIn('id', $ids)->get()->delete()

est? D'après ce que je vois, find et get retournent Collections

7
Code Poet

Le problème est que vous appelez delete() sur une collection, qui n'a pas cette méthode.

Vous avez deux options ici.

Evènements modèles

Si vous disposez d'écouteurs d'événements pour les événements de modèle deleting/deleted, vous devez vous assurer que la suppression a lieu de manière à ce que chaque modèle soit chargé, puis supprimé.

Dans ce cas, vous pouvez utiliser la méthode destroy sur le modèle prenant une liste d'identifiants. Il chargera un nouveau modèle pour chaque identifiant, puis appellera delete(). Comme vous l'avez mentionné dans un commentaire, la suppression ne sera pas limitée aux seuls produits de l'organisation. Vous devez donc filtrer ces identifiants avant de passer la liste à la méthode destroy().

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        // intersect the product ids for the org with those passed in
        $orgIds = array_intersect($org->products()->lists('id'), $ids);
        // now this will only destroy ids associated with the org
        \App\Product::destroy($orgIds);
    }
    catch(...) {
    }
}

Si vous n'aimez pas particulièrement cette approche, vous devrez itérer votre collection de produits d'organisation et appeler delete() individuellement. Vous pouvez utiliser une variable foreach standard ou la méthode each sur la collection:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->each(function ($product, $key) {
            $product->delete();
        });
    }
    catch(...) {
    }
}

Aucun événement modèle

Maintenant, si vous n'avez aucun événement modèle à écouter, les choses sont un peu plus faciles. Dans ce cas, vous pouvez simplement appeler delete() dans le générateur de requête, ce qui entraînera directement la suppression des enregistrements sans charger d'objet de modèle. Ainsi, vous obtenez un code plus propre avec de meilleures performances:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        // call delete on the query builder (no get())
        $org->products()->whereIn('id', $ids)->delete();
    }
    catch(...) {
    }
}
13
patricus

J'ai aussi fait face à ce problème. Soit $orgs contient quelques enregistrements en tant que collection. Maintenant, vous pouvez facilement supprimer ces enregistrements en utilisant une boucle comme celle-ci-

foreach($orgs as $org) 
{
    $org->delete();
}
0