Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Membre à l'essai
    Update de plusieurs enregistrements avec des valeurs différentes en une requête unique
    Bonjour,

    Je cherchais comment, dans Laravel, faire la mise à jour de plusieurs enregistrements avec des valeurs différentes.
    Je suis parvenu à mes fins mais quelle lutte ! J'ai trouvé la démarche assez tordue ; ça m'a pris quelques heures pour y arriver.

    N'ayant qu'une petite année d'expérience sur ce framework, je souhaitais savoir s'il y avait une manière plus simple de m'y prendre.

    Ma table "trainings" se présente comme suit :

    id user_id category_id title order
    1 1 1 Maupassant 1
    2 1 1 Hugo 2
    3 1 1 Voltaire 3

    ... et l'idée, c'était, qu'au moment où je supprime un élément, de retirer une unité à chaque ordre des éléments qui avaient un ordre supérieur à celui de l'élément supprimé. Aussi, dans le cas où j'ai 10000 enregistrements, je me voyais mal balancer 9999 requêtes (en supprimant le premier par exemple).

    Du coup j'ai procédé comme suit :

    Méthode de suppression de mon contrôleur "TrainingController"

    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
        public function destroy(Training $training)
        {
            if (Auth::user()->can('delete', $training)) {
                $id = $training->id;
     
                $trainings = Training::where([
                    ['category_id', '=', $training->category_id],
                    ['order', '>', $training->order]
                ])->get(['id', 'user_id', 'title', 'order']);
     
                foreach ($trainings as $item) {
                    $item->order = $item->order - 1;
                }
     
                $refs = $trainings->pluck('order', 'pluck')->toArray();
                $newRefs = [];
     
                foreach ($refs as $key => $ref) {
                    array_push($newRefs, "($key,$ref)");
                }
     
                $training->delete();
     
                $query = 'INSERT INTO trainings (`id`,`user_id`,`title`,`order`) VALUES ' . implode(',', $newRefs) . ' ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`),`title`=VALUES(`title`),`order`=VALUES(`order`)';
                $stmt = DB::getPdo()->prepare($query);
                $stmt->execute();
     
                return response()->json("Training $id deleted", 200);
            }
     
            return response()->json("Unauthorized action for this user", 401);
        }


    ... sachant que j'ai dû créer un accesseur dans mon modèle pour obtenir la valeur 'pluck' :

    Accesseur de mon modèle "Training"

    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        public function getPluckAttribute()
        {
            return $this->id . "," . $this->user_id . ",'" . $this->title . "'";
        }


    Comme vous pouvez le voir, je suis passé par PDO car je n'ai pas trouvé comment m'y prendre avec Eloquent.
    Quant à l'accesseur, c'est parce que la méthode pluck ne semble accepter que deux arguments max, ce que je trouve assez bizarre vu que ça peut arriver souvent de chercher à récupérer plus de deux colonnes, non ?

    Bref, je suis heureux d'être arrivé au résultat escompté, non sans acharnement, mais...

    M'y suis-je pris comme il faut et n'y-a-t-il pas moyen de faire plus simple ?

    Au plaisir de vous lire.

  2. #2
    Membre habitué
    Avec laravel tu peux créer des requetes personnalisées en SQL brut via RAW SQL.

    Voir ici pour des explications : https://laravel.com/docs/master/database#running-queries

  3. #3
    Membre à l'essai
    oui, j'avais vu cette page de la documentation mais ça ne permettait visiblement pas de répondre à mes besoins.

    DB::update peut mettre à jour plusieurs lignes mais toutes avec la même valeur, ce pourquoi j'en suis arrivé, au final, à cette requête "INSERT INTO ... ON DUPLICATE KEY UPDATE".
    Pour la faire, je n'ai pas vu "Raw SQL query" adaptée et c'est la raison pour laquelle je suis passé par PDO.

  4. #4
    Modérateur

    Simplement un truc comme ca aurait pas suffit ?

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    DB::update('update trainings set order = order -1 where order > ?', [$training->order]);
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre à l'essai
    Ah mais oui !

    J'obtiens bien ce que je souhaite ainsi :
    Code php :Sélectionner tout -Visualiser dans une fenêtre à part
    DB::update('UPDATE trainings SET `order` = `order` - 1 WHERE `category_id` = ' . $training->category_id . ' AND `order` > ?', [$training->order]);


    C'était tout simple en fait, sauf qu'étant un peu réfractaire au SQL, ça ne m'est pas venu à l'esprit.

    Merci grunk.

###raw>template_hook.ano_emploi###