Enregistrer les champs dans 2 tables !

Par Zulkar, il y a 8 ans


Base de données MySQL

Bonjour,

Voila je rencontre un petit problème avec mon code et je vais essayer d'être le plus clair possible.
J'avais commencé un bout d'application web pour la gestion de mes ingrédients et mes recettes ... et je me suis décidé à visionner la formation PHP POO, ce que j'ai fait plusieurs fois.
Maintenant, j'essais de mettre certaines choses en application en re-visonnant à nouveau !

Ce que je fais

J'ai donc pu réaliser ma partie 'Ingrédients' avec la visualisation de tous mes ingrédients dans un tableau et la possibilité d'ajouter, éditer ou supprimer. Tout fonctionne.

J'y vais lentement, mais sûrement.
Je me penche maintenant sur la partie 'Création d'une recette'.
J'ai cherché comment j'allais présenter visuellement cette page, et sans avoir de réelles idées, je vais sans doute partir sur du simple, comme sur l'image je pense !

Donc, en haut de ma page 'recette.add.php', je pensais mettre ceci :

<?php $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { $result = $recetteTable->create([ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); if ($result) { header('Location: index.php?p=recette.add&id=' . App::getInstance()->getDb()->lastInsertId()); } } $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $familles = App::getInstance()->getTable('Famille')->extract('id', 'familles'); $form = new \Core\HTML\BootstrapForm($_POST); ?>

Ce code fonctionne ... que pour l'enregistrement des informations qui sont dans la partie gauche de mon image. Et ces données s'enregistrent bien dans ma table 'Recettes'.

Seulement, mes tables sont jointes comme ceci :

Ce que je veux

Les tables 'Ingredients' et 'Recettes' sont jointes avec 'Composition_Recettes'.
J'imagine donc qu'il me faut la table 'Composition_Recettes' pour pouvoir enregistrer la liste des ingrédients nécessaires à la recette,
ce qui correspont à ma partie droite de ma première image.

Donc voilà, avant de me lancer dans le tri des ingrédients avec le champs 'Familles' que vous pouvez voir, je souhaitais faire un test en faisant un enregistrement avec un ingrédient pour voir le comportement.

Je bloque à ce niveau, comment faire pour réussir à renregistrer
tous les élements au bon endroit, dans les bonnes tables ?

Merci d'avance !!!

172 réponses

Zulkar, il y a 8 ans

Hello,
Un SELECT mais des options différentes !!!
L'explication pour mon cas ?

tamplan, il y a 8 ans

Je n'ai pas compris ta question.

Zulkar, il y a 8 ans

Le lien que tu donnes, c'est pour mon problème d'édition des ingrédients et des quantités ?
Donc je me demandais qu'elle action ça aurait pour mon cas.

antho07, il y a 8 ans

Bonjour,

je ne comprends pas trop le problème que tu rencontres. Dans la même transaction tu commences par enregistrer la recette. Tu obtiens alors sa clé primaire. Il suffit ensuite d'enregistrer dans ta table d'association recette-ingrédient la liste des ingrédients fournis dans le formulaire (tu dois avoir l'id).

Dans le cas où cette page permet également de créer des ingrédients, c'est plus compliqué, il faudra d'abord sauvegarder les ingrédients avant de sauvegarder l'association (mais attention aux créations identiques en parallèles)

Dernière chose, au vue de la structure de tes tables, comment vas-tu gérer les accès concurrents? : Toto charge la recette A, Tata modifie la recette A, Toto enregistre ses modifications sur A , qui l'emporte?

Zulkar, il y a 8 ans

Bonjour,
Qui l'emporte ? Bahhh ... moi :) ... C'est une appli pesonnelle, pour un usage personnel et en local sur mon pc portable !
Pour les ingrédients, c'était la première partie de l'appli, la création, l'édition et la suppression fonctionne de ce côté là.

Pour la question que tu posais, toi tu ne vois pas de problème car tu es développeur :) ... mais pour moi qui suis cuisinier, comprendre le cheminement est une autre, mais le mette en application avec une retranscription en code, ce n'est pas si évident !

Pour le sujet que j'ai ouvert, la partie ajout d'une recette fonctionne de cette façon :

<?php $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { $result = $recetteTable->create([ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); $recette_id = App::getInstance()->getDb()->lastInsertId(); $compositionTable = App::getInstance()->getTable('CompositionRecette'); $id_composition = []; foreach ($_POST['ingredients_id'] as $key => $ingredient_id) { $quantite = $_POST['quantite'][$key]; $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $quantite ]); $id_composition[] = App::getInstance()->getDb()->lastInsertId(); } if ($recette_id && count($id_composition)) { //redirection } } $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); $form = new \Core\HTML\BootstrapForm($_POST); ?>

Maintenant, je passe à la partie Edition, et là, je n'arrive à faire que la moitié, j'ai plusieurs choses à voir !!

tamplan, il y a 8 ans

Bonsoir,

Pour pouvoir mieux t'aider, je pense qu'il faudrait que tu nous montres le code de ton formulaire, il se peut que tu n'ai pas utilisé de nom de champs avec des [] pour indiquer que tu passer un tableau d'id d'ingrédients et un tableau de quantité.

Je peux me permettre un conseil en passant ?
Je suppose que ton schéma de base de données a changé par rapport à ton image ici à la la lecture de ton code.

Je te suggère les modifications suivantes :

  • table 'recettes', champ 'recettes' à renommer en nom, tu pourras écrire $recette->nom à la place de $recette->recette, tu t'y retrouveras mieux pareil pour les tables 'familles', 'ingredient', 'categories' ...
  • table 'recettes' toujours en renommant le champ categories_id en categorie_id, tu feras référence à l'id de la catégorie de ta recette, une recette appartenant à une seule catégorie selon ton schéma
  • table 'composition_recettes' devrait s'appeler 'ingredients_recettes' par convention avec des clés au singulier
  • table 'ingredient', j'aurais sorti le fournisseur et le prix comme tu as commencé à faire avec les familles (2 fournisseurs peuvent de faire 2 prix pour un même produit)
  • enfin pour des raisons de sécurité (même pour un usage personnel, il n'est pas inutile de se former avec des bonnes pratiques), on ne fait JAMAIS confiance aux données fournies par l'utilisateur, tu peux certainement convertir des $_POST... en nombre entier là où tu t'attends à voir des nombres entiers.

Sinon pour re-répondre à ton problème, je suppose qu'il se trouve dans le code de ton formulaire.

Zulkar, il y a 8 ans

Bonsoir et merci pour tous ces conseils.
Je ne sais pas par où commencer ... pour te répondre.
Pour répondre à ta supposition, non, mon schéma de base de données n'a pas changé depuis le début du projet.
Et voici le code complet de ma page ADD, je pensais partir de cette page pour créer la page EDIT.
Pour la partie EDIT la table Recettes, j'y arrive, mais quant aux ingrédients et aux quantités, ça c'est une autre histoire.

<?php $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { $result = $recetteTable->create([ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); $recette_id = App::getInstance()->getDb()->lastInsertId(); $compositionTable = App::getInstance()->getTable('CompositionRecette'); $id_composition = []; foreach ($_POST['ingredients_id'] as $key => $ingredient_id) { $quantite = $_POST['quantite'][$key]; $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $quantite ]); $id_composition[] = App::getInstance()->getDb()->lastInsertId(); } if ($recette_id && count($id_composition)) { //redirection } } $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); $form = new \Core\HTML\BootstrapForm($_POST); ?> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Recettes <small>Control Panel</small> </h1> <ol class="breadcrumb"> <li><a href="index.php?p=home"><i class="fa fa-dashboard"></i> Home</a></li> <li class="active"><a href="index.php?p=ingredients">Recettes</a></li> <li class="active">Ajouter</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <form method="POST"> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Création de la recette</h3> </div> <div class="box-body"> <!-- Catégories --> <?= $form->select('categories_id', 'Catégorie', $categories); ?> <!-- /.form group --> <!-- Nom de la recette --> <?= $form->input('recettes', 'Choisir le nom de la recette'); ?> <!-- /.form group --> <!-- Nombre de personnes --> <?= $form->input('nbpersonnes', 'Nombre de personnes'); ?> <!-- /.form group --> <!-- Marge --> <?= $form->input('marge', 'Marge'); ?> <!-- /.form group --> <!-- Observation --> <?= $form->input('observations', 'Observations', ['type'=>'textarea']); ?> <!-- /.form group --> <button id="add" class="btn btn-block submit">Valider</button> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Sélectionner les ingrédients</h3> </div> <div class="box-body"> <div data-role="dynamic-fields"> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <?= $form->input('quantite[]', 'Quantité'); ?> <!-- /.form group --> </div> <div class="col-md-2"> <label>Action</label> <button class="btn btn-default remove" data-role="remove"> <span class="glyphicon glyphicon-remove"></span></button> <button class="btn btn-default" data-role="add"> <span class="glyphicon glyphicon-plus"></span></button> </div> </div> </div> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> </form> <!-- /.form --> </div> <!-- /.row --> </section> <!-- /.content --> </div> <!-- /.content-wrapper -->

Pour les modifications que tu me demandes, je vais y regarder ... MERCI !!!

tamplan, il y a 8 ans

Attention, je ne demande rien moi, je te conseille simplement ! ^^

Là ou je pense que ton schéma a changé, c'est quand je lis :

$result = $recetteTable->create([ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]);

Dans la table 'recettes', il te manque les champs 'marge' et 'observations' donc ton script devrait échouer et ne pas aller plus loin je pense.

Il faudrait que tu regardes le code html généré par la class de formulaire et vérifier que tu as bien 'ingredients_id[]' et 'quantite[]' dans le code source de ta page, je pense que c'est ça qui doit bloquer aussi.

Tu peux également vérifier les champs transmis lors de la soumission du formulaire en modifiant ton script comme ceci :

' Pour débogage echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); $recetteTable = App::getInstance()->getTable('Recette'); ...

Tu commentes la ligne 'echo ...' quand tu veux exécuter ton script et la décommente quand tu veux vérifier les champs transmis...

Zulkar, il y a 8 ans

Ah oui, bien vue ^^, j'ai en effet ajouté les champs 'marge' et 'observations' :)

Le code HTML généré pour la page EDIT, sur laquelle je souhaite travailler et qui fournit donc une erreur :

<!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Recettes <small>Control Panel</small> </h1> <ol class="breadcrumb"> <li><a href="index.php?p=home"><i class="fa fa-dashboard"></i> Home</a></li> <li class="active"><a href="index.php?p=ingredients">Recettes</a></li> <li class="active">Editer</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <form method="POST"> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Mise à jour de la recette</h3> </div> <div class="box-body"> <!-- Catégories --> <div class="form-group"><label>Catégorie</label><select class="form-control" name="categories_id"><option value='1'>Apéritifs</option><option value='2'>Entrées</option><option value='3'>Plats</option><option value='4'>Desserts</option><option value='5' selected>Sauces</option><option value='6'>Divers</option><option value='7'>Cake Design</option></select></div> <!-- /.form group --> <!-- Nom de la recette --> <div class="form-group"><label>Choisir le nom de la recette</label><input type="text" name="recettes" value="Crème de champignons" class="form-control"></div> <!-- /.form group --> <!-- Nombre de personnes --> <div class="form-group"><label>Nombre de personnes</label><input type="text" name="nbpersonnes" value="4" class="form-control"></div> <!-- /.form group --> <!-- Marge --> <div class="form-group"><label>Marge</label><input type="text" name="marge" value="4.5" class="form-control"></div> <!-- /.form group --> <!-- Observation --> <div class="form-group"><label>Observations</label><textarea name="observations" class="form-control">Test observations crème de champignons</textarea></div> <!-- /.form group --> <button id="add" class="btn btn-block submit">Sauvegarder</button> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Sélectionner les ingrédients</h3> </div> <div class="box-body"> <div data-role="dynamic-fields"> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <br /> <font size='1'><table class='xdebug-error xe-uncaught-exception' dir='ltr' border='1' cellspacing='0' cellpadding='1'> <tr><th align='left' bgcolor='#f57900' colspan="5"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> Fatal error: Uncaught Error: Call to undefined method App\Entity\RecetteEntity::getIngredients_id[]() in /srv/http/Dev/Dashboard/core/Entity/Entity.php on line <i>13</i></th></tr> <tr><th align='left' bgcolor='#f57900' colspan="5"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> Error: Call to undefined method App\Entity\RecetteEntity::getIngredients_id[]() in /srv/http/Dev/Dashboard/core/Entity/Entity.php on line <i>13</i></th></tr> <tr><th align='left' bgcolor='#e9b96e' colspan='5'>Call Stack</th></tr> <tr><th align='center' bgcolor='#eeeeec'>#</th><th align='left' bgcolor='#eeeeec'>Time</th><th align='left' bgcolor='#eeeeec'>Memory</th><th align='left' bgcolor='#eeeeec'>Function</th><th align='left' bgcolor='#eeeeec'>Location</th></tr> <tr><td bgcolor='#eeeeec' align='center'>1</td><td bgcolor='#eeeeec' align='center'>0.0004</td><td bgcolor='#eeeeec' align='right'>370664</td><td bgcolor='#eeeeec'>{main}( )</td><td title='/srv/http/Dev/Dashboard/public/index.php' bgcolor='#eeeeec'>.../index.php<b>:</b>0</td></tr> <tr><td bgcolor='#eeeeec' align='center'>2</td><td bgcolor='#eeeeec' align='center'>0.0011</td><td bgcolor='#eeeeec' align='right'>421552</td><td bgcolor='#eeeeec'>require( <font color='#00bb00'>'/srv/http/Dev/Dashboard/pages/recettes/recette.edit.php'</font> )</td><td title='/srv/http/Dev/Dashboard/public/index.php' bgcolor='#eeeeec'>.../index.php<b>:</b>31</td></tr> <tr><td bgcolor='#eeeeec' align='center'>3</td><td bgcolor='#eeeeec' align='center'>0.0064</td><td bgcolor='#eeeeec' align='right'>496384</td><td bgcolor='#eeeeec'>Core\HTML\BootstrapForm->select( )</td><td title='/srv/http/Dev/Dashboard/pages/recettes/recette.edit.php' bgcolor='#eeeeec'>.../recette.edit.php<b>:</b>109</td></tr> <tr><td bgcolor='#eeeeec' align='center'>4</td><td bgcolor='#eeeeec' align='center'>0.0064</td><td bgcolor='#eeeeec' align='right'>496520</td><td bgcolor='#eeeeec'>Core\HTML\BootstrapForm->getValue( )</td><td title='/srv/http/Dev/Dashboard/core/HTML/BootstrapForm.php' bgcolor='#eeeeec'>.../BootstrapForm.php<b>:</b>35</td></tr> <tr><td bgcolor='#eeeeec' align='center'>5</td><td bgcolor='#eeeeec' align='center'>0.0064</td><td bgcolor='#eeeeec' align='right'>496520</td><td bgcolor='#eeeeec'>App\Entity\RecetteEntity->__get( )</td><td title='/srv/http/Dev/Dashboard/core/HTML/Form.php' bgcolor='#eeeeec'>.../Form.php<b>:</b>41</td></tr> </table></font>
Zulkar, il y a 8 ans

Et ton code pour le débogage me renvoie un Array vide

tamplan, il y a 8 ans

Tu as un problème à cette ligne :

<?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?>

Supprime la ainsi que la ligne pour la catégorie et teste pour voir, ton problème vient de là. La classe form n'est pas adaptée pour générer le code html de plusieurs champs select avec le même identifiant.

Autrement dit, si tu modifies ton code comme ceci :

<?= $form->select('ingredients_id', 'Ingrédient', $ingredients); ?>

ça va fonctionner mais tu n'auras qu'un seul ingrédient, il te faut modifier la classe form pour l'adapter à ce que tu veux faire.

Peux tu me donner l'url du chapitre de la formation dans lequel la classe est modifiée pour gérer le select s'il te plait ?

Zulkar, il y a 8 ans

La class form a été créée dans ce chapitre :
https://www.grafikart.fr/formations/programmation-objet-php/exemple-class-form
Il y a aussi des modifications dans le chapitre TP: Back-end :
https://www.grafikart.fr/formations/programmation-objet-php/tp-backend

J'ai bien vu que dans le cas de l'édition, les [ ] posaient problème et en les enlevant, le problème était toujours le même.

Si je retire les lignes ingredients_id[] et quantite[] la mise à jour fonctionne pour les champs catégories_id, recettes, nbpersonnes, marge, observations.

Zulkar, il y a 8 ans

OK pour demain en fin d'après-midi, ça m'arrange car c'est mon après-midi en soins hospitaliers ...

tamplan, il y a 8 ans

Le problème vient bien de la class form qui ne gère pas les identifiants avec [] pour le moment, on va corriger ça prochainement...

tamplan, il y a 8 ans

En attendant, tu peux modifier dans la fonction select de la classe BootstrapFrom.php la ligne '$input...' comme ceci :

$input = '<select> class="form-control" name='. $name .'[]">';

pour contourner le problème mais c'est une solution temporaire plutôt dégueulasse ^^

tamplan, il y a 8 ans

Dans les réponses données sur la page dont je t'ai indiqué le lien, il est fait mention de plusieurs selects avec des [] et un nom identique (cars[]) , c'est le même principe que tu devrais utiliser pour tes ingrédients et quantités.

Zulkar, il y a 8 ans

Pour faire le tri par Familles ?
Mais pour les quantités, je ne vois pas !!!

tamplan, il y a 8 ans

Tu rajoutes bien un certain nombre d'ingrédients d'une certaine famille avec ton bouton + dans ta colonne action ?

Zulkar, il y a 8 ans

Oui, tout à fait !
Et je me disais même qu'il serait bien de filtrer les ingrédients par familles, sinon je vais me retrouver avec un SELECT mega long !

tamplan, il y a 8 ans

Je me suis mal exprimé. Est-ce que tu cherches à ajouter les ingrédients un par un en soumettant le formulaire à chaque fois ou quand tu appuies sur le bouton +, tu as de nouveaux champs select et quantité ?

tamplan, il y a 8 ans

Je te propose que l'on discute de tout ça en live sur le tchat.

Zulkar, il y a 8 ans

Ah ok excuses, je suis à l'ouest ... lol ... je préfère ajouter un ingrédient, sa quantité ... cliquer sur + pour ajouter de nouveaux champs pour ajouter un nouvel ingrédient et sa quantité ... ainsi de suite !!

tamplan, il y a 8 ans

Dans ce cas, c'est encore plus simple, tu oublies les [] et tu gères ça avec une requête ajax quand tu appuies sur le +

Je pense cependant que tu devrais envisager de modifier un peu ta façon de faire et faire comme ce que tu fais déjà avec tes ingrédients (ajout, édition, suppression) mais avec tes recettes et ne gérer les ingrédients que lorsque tu édites une recette.

Tu créés une nouvelle recette, tu peux pas ajouter d'ingrédient.
Tu édites ta nouvelle recette, et là seulement tu peux ajouter/supprimer tes ingrédients (tu t'arrages pour mettre l'id de ta recette dans le formulaire).
Ce sera certainement plus facile à coder.

Zulkar, il y a 8 ans

J'avais déjà réfléchi à cette solution en effet.

Donc aujourd'hui, j'ai mon fichier recette.add.php qui enregistre bien le champ catégorie, recette, nombre de personnes, marge, observation, ingrédient, quantité, le bouton + ajoute une nouvelle ligne pour ajouter un ingrédient, une quantité, etc ... ou supprimer la ligne précédente ...

Avec ta suggestion, j'enlève la partie 'Sélectionner les ingrédients' pour enregistrer seulement le reste.

Donc les ingrédients et les quantités, je les enregistre comment ?
Et lorsque je vais éditer une recette, je vais bien récupérer tous les champs de la table recette + les ingrédients et les quantités ?
Donc le problème de l'édition sera le même ?

Je me trompe peut-être !!!!

tamplan, il y a 8 ans

Pour l'ajout et la suppression d'une recette, je te conseille de faire aussi simplement que ce que tu sembles avoir fait avec les ingrédients (c'est ce à quoi tu fais référence quand tu parles du tableau dans le premier message de ton sujet).

C'est seulement quand tu édites une recette que tu peux mettre tes ingrédients en relation avec ta recette (et leurs quantités), ajouter/supprimer un ingrédient de ta recette pas de ta base de données.

Je ne sais pas si je suis très clair.

Zulkar, il y a 8 ans

Pour mes ingrédients, j'ai fait comme ceci, je récupère tout :

Pour ajouter un ingrédient :

Pour éditer un ingrédient :

tamplan, il y a 8 ans

Fais la même chose pour tes recettes sans gérer les ingrédients rattachés à tes recettes dans un premier temps, ajoutes la gestion des ingrédients uniquement quand tu modifies tes recttes.

Qu'en penses tu ?

Zulkar, il y a 8 ans

Oui, c'est faisable ...j'enlève juste le code php correspondant à cette partie, ça prend pas longtemps !
C'est juste dommage car j'avais réussi à ajouter les ingrédients à cette page lol :D

Mais c'est surtout que je ne comprends pas la différence entre le problème que j'ai pour l'édition en ce moment et le mode édition que tu veux me faire faire.

Et il faut donc que je change mon visuel pour mes recettes alors ?

tamplan, il y a 8 ans

Je pense que ton problème vient du fait que tu veuilles créer une nouvelle recette et y associer des ingrédients en une seule étape.

Tu auras sans doute également besoin parfois de modifer les ingrédients de tes recettes ou leurs quantités, c'est pour cela que je te conseille de gérer tout ça uniquement quand tu modifies tes recettes.
Du coup tu n'as besoin de traiter le cas si la recette est nouvelle ou si tu la modifies, ton code est plus simple à écrire.

Après, ça reste tes choix et ton code.

Zulkar, il y a 8 ans

D'accord !

Dans le visuel/design, tu vois ça comment ?

tamplan, il y a 8 ans

Le tiens est épuré, priorité au fonctionnel, c'est plutôt classe.

Quelque chose te chagrine ?

Zulkar, il y a 8 ans

Merci !!!

Donc, du coup, pour le mode édition !
Je récupère l'id de la recette, tous les champs pré-remplis et pour les ingrédients et les quantités, je ne procède plus comme avant avec le bouton + ?

tamplan, il y a 8 ans

Si tu fais comme avant et comme tu l'as indiqué.

As tu tenté la modification de la classe BootstrapForm comme je te l'ai conseillé pour gérer les [] ?

Zulkar, il y a 8 ans

Tu avais conseillé :

$input = '<select> class="form-control" name='. $name .'[]">';

Ce n'est pas plutôt :

$input = '<select class="form-control" name="' . $name . '[]">';
tamplan, il y a 8 ans

Bonjour,
Oui en effet, j'ai fait une faute de frappe...

Zulkar, il y a 8 ans

Bonjour,
Pour récap. , j'ai donc un fichier recette.add.php avec simplement les champs correspondant à ma table Recette.
Lorsque j'édite la recette, je récupère les champs pré-remplis et en plus, j'ai les champs pour ajouter les ingrédients et les quantités.
Donc dans cette page, j'ai 2 fonctions, à la fois UPDATE pour la partie recette et CREATE pour les ingrédients !

Et si je souhaite ré-éditer la recette, j'en reviens à mon problème initiale, c'est-à-dire récupérer tous les champs pré-remplis y compris les ingrédients et les quantités ? :D

tamplan, il y a 8 ans

Peux tu me montrer ton nouveau code et capture d'écran s'il te plait ?

Zulkar, il y a 8 ans

Donc, pour la partie Ajouter, je n'ai plus la partie de droite avec les ingrédients et les quantités :

<?php // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { // INSERT des données saisies $result = $recetteTable->create([ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); if ($result) { // Redirection et/ou Message } } // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); // Chargement des paramètres du formulaire $form = new \Core\HTML\BootstrapForm($_POST); ?> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Recettes <small>Control Panel</small> </h1> <ol class="breadcrumb"> <li><a href="index.php?p=home"><i class="fa fa-dashboard"></i> Home</a></li> <li class="active"><a href="index.php?p=ingredients">Recettes</a></li> <li class="active">Ajouter</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <form method="POST"> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Création de la recette</h3> </div> <div class="box-body"> <!-- Catégories --> <?= $form->select('categories_id', 'Catégorie', $categories); ?> <!-- /.form group --> <!-- Nom de la recette --> <?= $form->input('recettes', 'Choisir le nom de la recette'); ?> <!-- /.form group --> <!-- Nombre de personnes --> <?= $form->input('nbpersonnes', 'Nombre de personnes'); ?> <!-- /.form group --> <!-- Marge --> <?= $form->input('marge', 'Marge'); ?> <!-- /.form group --> <!-- Observation --> <?= $form->input('observations', 'Observations', ['type'=>'textarea']); ?> <!-- /.form group --> <button id="add" class="btn btn-block submit">Valider</button> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> </form> <!-- /.form --> </div> <!-- /.row --> </section> <!-- /.content --> </div> <!-- /.content-wrapper -->

Pour la partie Edition, je ne peux pas te montrer le visuel car il récupère bien les champs pré-remplis de la partie gauche Recette, mais j'ai une erreur pour la partie ingrédients et quantités.
Il n'aime pas :

<?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?>

Le code complet de la page est :

<?php //Pour débogage //echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { // UPDATE des données récupérées $result = $recetteTable->update($_GET['id'], [ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); // Trouver le code pour INSERT et UPDATE des ingrédients et quantités if ($result) { // Redirection et/ou Message } } // On récupère l'id de la recette $recette = $recetteTable->find($_GET['id']); // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); // On reprend le formulaire de la recette $form = new \Core\HTML\BootstrapForm($recette); ?> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Recettes <small>Control Panel</small> </h1> <ol class="breadcrumb"> <li><a href="index.php?p=home"><i class="fa fa-dashboard"></i> Home</a></li> <li class="active"><a href="index.php?p=ingredients">Recettes</a></li> <li class="active">Editer</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <form method="POST"> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Mise à jour de la recette</h3> </div> <div class="box-body"> <!-- Catégories --> <?= $form->select('categories_id', 'Catégorie', $categories); ?> <!-- /.form group --> <!-- Nom de la recette --> <?= $form->input('recettes', 'Choisir le nom de la recette'); ?> <!-- /.form group --> <!-- Nombre de personnes --> <?= $form->input('nbpersonnes', 'Nombre de personnes'); ?> <!-- /.form group --> <!-- Marge --> <?= $form->input('marge', 'Marge'); ?> <!-- /.form group --> <!-- Observation --> <?= $form->input('observations', 'Observations', ['type'=>'textarea']); ?> <!-- /.form group --> <button id="add" class="btn btn-block submit">Sauvegarder</button> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Sélectionner les ingrédients</h3> </div> <div class="box-body"> <div data-role="dynamic-fields"> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <?= $form->input('quantite[]', 'Quantité'); ?> <!-- /.form group --> </div> <div class="col-md-2"> <label>Action</label> <button class="btn btn-default remove" data-role="remove"> <span class="glyphicon glyphicon-remove"></span></button> <button class="btn btn-default" data-role="add"> <span class="glyphicon glyphicon-plus"></span></button> </div> </div> </div> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> </form> <!-- /.form --> </div> <!-- /.row --> </section> <!-- /.content --> </div> <!-- /.content-wrapper -->
tamplan, il y a 8 ans

Je vois que tu as un champ input avec des [] également.

Je te propose la chose suivante, vu que tu connais parfaitement ton code, n'utilise pas (pour le moment) la classe BootstapFrom chaque fois que tu utilises des [] dans des champs, tu as donc ces lignes à modifier pour les remplacer par le code html attendu :

<?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?>

et

<?= $form->input('quantite[]', 'Quantité'); ?>

Et tu testes avec la ligne de debogage décommentée, normalement tu devrais avoir toutes tes données dans la variable $_POST.

En attendant, je te cherche des liens pour t'expliqer la suite...

tamplan, il y a 8 ans

Avant de lire la suite, recopies plusieurs fois, ce bloc modifié (code html en dur et non généré par la classe) :

<div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <?= $form->input('quantite[]', 'Quantité'); ?> <!-- /.form group --> </div> <div class="col-md-2"> <label>Action</label> <button class="btn btn-default remove" data-role="remove"> <span class="glyphicon glyphicon-remove"></span></button> <button class="btn btn-default" data-role="add"> <span class="glyphicon glyphicon-plus"></span></button> </div> </div>

Et teste la soumission du formulaire pour voir toutes les données passées dans la variables $_POST.

Du coup, tu vas peut-être changer les boutons + en boutons - (pour supprimer chaque ligne d'ingrédient) et rajouter dessous un seul bouton + pour ajouter un nouveau bloc pour un nouvel ingrédient.

Passons à la suite maintenant...

Regarde par exemple ce lien http://christianelagace.com/php/ajax-pour-gerer-des-listes-deroulantes-imbriquees/ (un pays choisi dans une liste propose le choix d'une province dans une liste liée).
Toi, tu vas pouvoir te servir de ça et adapter pour choisir la famille dans une liste qui te permettra de choisir l'ingrédient dans une liste.

Mais, ce n'est pas tout, il te faut gérer également l'ajout de plusieurs ingrédients (bouton +). Dès que tu appuis sur +, 2 nouvelles listes (familles et ingrédients) et un champ input (quantité) (en gros le bloc que j'ai recopié ici) doivent être ajoutés via une requête ajax.

Que penses-tu de tout ça ?

Zulkar, il y a 8 ans

Alors, j'ai décommenté la ligne de debogage !
J'ai remplacé le code, par du code HTML.
Lorsque je demande l'édition d'une recette, il me renvoie un Array vide.
Si je commente la ligne de debogage, j'ai bien ma page recette.edit.php avec les champs de la recette pré-rempli et la partie ingrédients/quantités cette fois-ci.

<?php //Pour débogage //echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { // UPDATE des données récupérées $result = $recetteTable->update($_GET['id'], [ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); // Trouver le code pour INSERT et UPDATE des ingrédients et quantités if ($result) { // Redirection et/ou Message } } // On récupère l'id de la recette $recette = $recetteTable->find($_GET['id']); // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); // On reprend le formulaire de la recette $form = new \Core\HTML\BootstrapForm($recette); ?> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <section class="content-header"> <h1> Recettes <small>Control Panel</small> </h1> <ol class="breadcrumb"> <li><a href="index.php?p=home"><i class="fa fa-dashboard"></i> Home</a></li> <li class="active"><a href="index.php?p=ingredients">Recettes</a></li> <li class="active">Editer</li> </ol> </section> <!-- Main content --> <section class="content"> <div class="row"> <form method="POST"> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Mise à jour de la recette</h3> </div> <div class="box-body"> <!-- Catégories --> <?= $form->select('categories_id', 'Catégorie', $categories); ?> <!-- /.form group --> <!-- Nom de la recette --> <?= $form->input('recettes', 'Choisir le nom de la recette'); ?> <!-- /.form group --> <!-- Nombre de personnes --> <?= $form->input('nbpersonnes', 'Nombre de personnes'); ?> <!-- /.form group --> <!-- Marge --> <?= $form->input('marge', 'Marge'); ?> <!-- /.form group --> <!-- Observation --> <?= $form->input('observations', 'Observations', ['type'=>'textarea']); ?> <!-- /.form group --> <button id="add" class="btn btn-block submit">Sauvegarder</button> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> <div class="col-md-6"> <div class="box box-danger"> <div class="box-header"> <h3 class="box-title">Sélectionner les ingrédients</h3> </div> <div class="box-body"> <div data-role="dynamic-fields"> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <div class="group-form"> <label>Ingrédient</label> <select name="ingredients" id="ingredients" class="form-control"> <?php foreach (App::getInstance()->getTable('Ingredient')->getIngredients() as $ingredient): ?> <option value="<?= $ingredient->id; ?>"><?= $ingredient->ingredients; ?></option> <?php endforeach; ?> </select> </div> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <label>Quantité</label> <input type="text" class="form-control" /> </div> <!-- /.form group --> </div> <div class="col-md-2"> <label>Action</label> <button class="btn btn-default remove" data-role="remove"> <span class="glyphicon glyphicon-remove"></span></button> <button class="btn btn-default" data-role="add"> <span class="glyphicon glyphicon-plus"></span></button> </div> </div> </div> </div> <!-- /.box-body --> </div> <!-- /.box --> </div> </form> <!-- /.form --> </div> <!-- /.row --> </section> <!-- /.content --> </div> <!-- /.content-wrapper -->

EDIT : Tu as été plus vite que moi pour poster lol ... je lis ton message à l'instant.

tamplan, il y a 8 ans

J'ai répondu avant ton message, tu as eu le temps de le lire ?

Zulkar, il y a 8 ans

Alors je viens de lire ton message avant le miens et je vais faire le point avant qu'on se mélange les pinceaux ;)
Pour le lien que tu donnes, j'avais aussi pensé aux champs imbriqués. Mais je ne l'ai jamais mis en place car je cherchais toutes les différentes manières que je pouvais utiliser pour ajouter mes ingrédients.
Pour les boutons + et -, ils fonctionnent bien depuis le début, avec un code dans mon fichier JS.

tamplan, il y a 8 ans

Ok pour le point et les boutons + et -.
Attention en effet, tu as changé d'avis entre temps, maintenant tu n'utilises qu'une seule liste pour les ingrédients.

Pour résumer ton problème, il se situe au niveau de ton formulaire html.

Une petite explication au passage qui te sera peut-être inutile : chaque fois que tu utilises un champs dans un formulaire et quelque soit son type (input, select, textarea...) la valeur de l'attribut name sert de clé dans le tableau associatif $_POST.
Tu peux (et c'est ce que tu cherches à faire ici) utiliser plusieurs fois le même name (pour chaque ingrédient et sa quantité) mais seul les derniers champs ingrédient et quantité seront passés dans la variable $_POST, c'est pour cela qu'il faut utiliser des [].

Pour le moment, oublies la partie base de données, recopie ton code html de ta page web plusieurs fois (on va dire le bloc ingrédient dans ta div inline) quite à changer les attributs name (ingredient1, quantite1, ingredient2, quantite2 ...) et testes si tu récupères bien les données dans la variable $_POST.

Tu essaies les deux méthodes :

  • ingredient[] et quantite[]
  • ingredient1 et quantite2

Et tu vois ce qui est passé dans $_POST.

tamplan, il y a 8 ans

Attention, j'ai modifié mon précédent message.

Zulkar, il y a 8 ans

Pour l'instant, ça ne donne rien de rien !
Mais je me disais que c'était sûrment normal puisque à aucun moment je me connecte à la table de liaison ?

tamplan, il y a 8 ans

Oublies la base de données pour le moment... Il faut d'abord tester ton formulaire et les champs qui seront soumis.

Tu as essayé les deux méthodes ?

Zulkar, il y a 8 ans
<div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <div class="group-form"> <label>Ingrédient</label> <select name="ingredient1" id="ingredient1" class="form-control"> <?php foreach (App::getInstance()->getTable('Ingredient')->getIngredients() as $ingredient): ?> <option value="<?= $ingredient->id; ?>"><?= $ingredient->ingredients; ?></option> <?php endforeach; ?> </select> </div> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <label>Quantité</label> <input type="text" name="quantite1" class="form-control" /> </div> <!-- /.form group --> </div> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <div class="group-form"> <label>Ingrédient</label> <select name="ingredient[]" id="ingredient1" class="form-control"> <?php foreach (App::getInstance()->getTable('Ingredient')->getIngredients() as $ingredient): ?> <option value="<?= $ingredient->id; ?>"><?= $ingredient->ingredients; ?></option> <?php endforeach; ?> </select> </div> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <label>Quantité</label> <input type="text" name="quantite[]" class="form-control" /> </div> <!-- /.form group --> </div>

Je dois mal m'y prendre.

tamplan, il y a 8 ans

Modifies ton code comme ceci :

<?php // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { //Pour débogage echo '<pre>' . print_r($_POST, true) . '</pre>'; die();

ça risquait pas de marcher sinon :)

tamplan, il y a 8 ans

J'ai lu ton précédent message, c'est ma faute, avec mon précédent message, ça devrait aller.
Le die() interrompt le script donc forcément là où il était placé, tu avais juste un Array vide sans pouvoir soumettre ton formulaire...

Milles excuses !!! :-)

Zulkar, il y a 8 ans

T'inquiètes !!!
Ça ne récupère toujours pas les ingrédients et les quantités dans les champs pré-remplis.

tamplan, il y a 8 ans

C'est à dire, les ingrédients que tu aurais déjà liés à ta recette ?
La variable $_POST n'est pas vide et contient bien un ingrédient quand tu en rentres un ?

Zulkar, il y a 8 ans

Pour la première question ... oui.

tamplan, il y a 8 ans

Pour le moment, c'est normal sinon le reste fonctionne ? avec les deux méthodes et plusieurs lignes d'ingrédients et quantités ? Les données sont bien transmises dans la variable $_POST ?

Zulkar, il y a 8 ans

Autant pour moi, c'est moi qui me plante sur ce que tu veux me faire faire :)
Donc, maintenant que j'ai compris, les 2 méthodes fonctionnent.
Avec les name1 et name2

Array ( [categories_id] => 5 [recettes] => Crème de champignons [nbpersonnes] => 4 [marge] => 4.5 [observations] => Test observations crème de champignons [ingredient1] => 123 [quantite1] => 0.900 [ingredient2] => 145 [quantite2] => 0.500 )

Avec les name[]

Array ( [categories_id] => 5 [recettes] => Crème de champignons [nbpersonnes] => 4 [marge] => 4.5 [observations] => Test observations crème de champignons [ingredient] => Array ( [0] => 123 [1] => 145 ) [quantite] => Array ( [0] => 0.900 [1] => 0.500 ) )
tamplan, il y a 8 ans

Tu peux voir que ça sera facile de récupérer les données avec les deux méthodes :

  • méthode avec [] on récupére des tableau avec des clés "propres"
  • méthode avec des noms et des chiffres, il faudra analyser toutes les clés mais on pourra passer les identifiants des ingrédients

Bon, donc la partie formulaire fonctionne en dur, maintenant essaies avec la classe BootstapFrom avec le code que tu utilisais avant :

<?= $form->select('ingredients_id[]', 'Ingrédient', $ingredients); ?>

ça devrait te donner le même résultat qu'avec la méthode [].

Zulkar, il y a 8 ans

Si j'utilise à nouveau la classe Bootstrapform, il me remet mon message d'erreur pour la form ingredients_id[]

tamplan, il y a 8 ans

Donc il va falloir modifier la classe BootstrapForm et rajouter une nouvelle méthode pour prendre ce cas en compte ou mieux, on va utiliser la solution avec les clés de la forme 'ingredientt_1', 'ingredientt_2', on pourra tester les clés dans la variable $_POST avec les fonctions http://php.net/manual/fr/function.array-keys.php et http://php.net/manual/fr/function.strpos.php mais on modifiera quand même la classe.

Maintenant, on va réfléchir à la mainère de trouver les ingrédients liés à une recette et il faudra générer du code html pour chaque ingrédient (nom de l'ingrédient dans une liste avec l'ingrédient sélectionné et un champ de type input pour la quantité avec l'id de l'ingrédient).

Je te propose de mettre tout ce code dans une classe dans App\Table\Recette par exemple ou autre.
On peut envisager une méthode dans la classe Recette pour écrire $recette->getIngredients(recette_id) ou une méthode $recette->getListHTMLIngredients(recette_id).

A toi de bien penser ton design pour voir si tu utilises un seul bouton + et plusieurs lignes et des boutons - ou autre.

Je regarde la video de la formation sur les tables et on voit ça dimanche, je ne serais pas disponible demain soir.

Zulkar, il y a 8 ans

J'ai un seul bouton + qui me rajoute des lignes avec des boutons -

Pourquoi dans mon code de départ, lorsque j'ajoutais les ingrédients et les quantités en même temps que tout le reste, il prenait bien en compte la classe BootstrapForm, mais pour l'édition il n'en veut pas ?

Dans mon App\Table\Recette, j'avais ça :

<?php namespace App\Table; use Core\Table\Table; /** * */ class RecetteTable extends Table { protected $table = 'recettes'; /** * Récupère les ingrédients en liant les familles et les unités associées * @return \App\Entity\IngredientEntity */ public function getRecettes() { return $this->query(" SELECT C.categories, C.id, R.recettes, R.nbpersonnes, I.ingredients, I.prix FROM categories C JOIN recettes R ON C.id=R.categories_id JOIN composition_recettes CR ON R.id=CR.recettes_id JOIN ingredients I ON I.id=CR.ingredients_id ORDER BY recettes DESC"); } public function getDetailRecette() { return $this->query(" SELECT C.categories, C.id, R.recettes, R.nbpersonnes, marge, observations, I.ingredients, quantites, I.prix FROM categories C JOIN recettes R ON C.id=R.categories_id JOIN composition_recettes CR ON R.id=CR.recettes_id JOIN ingredients I ON I.id=CR.ingredients_id "); } }
tamplan, il y a 8 ans

Il faut que tu récupéres des informations sur ta table compositions_recettes que tu as peut-être renommé comme je te l'ai conseillé et non la table ingredients mais en 2 étapes.
Dans le meilleur des cas, tu ne trouveras qu'un seul ingrédient avec ta requête actuelle.

Le join te permet de faire une relation 1:1, là il te faut une relation 1:n qui va te retourner plusieurs enregistrements (les ingrédients liés à ta recette) à la différence de la relation 1:1 qui comme son nom l'indique te retourne un seul résultat (ta recette).

tamplan, il y a 8 ans

Bonjour,
Je viens de modifier les sources du chapitre https://www.grafikart.fr/formations/programmation-objet-php/mvc-model-view-controller pour les adpater à ton application.

Il te faudrait une classe App\Table\IngredientTable.php, définie par exemple comme ceci :

<?php namespace App\Table; use Core\Table\Table; class IngredientTable extends Table{ protected $table = 'ingredients'; /** * Récupère les ingrédient liés ) une recette * @param $id int * @return \App\Entity\IngredientEntity */ public function findForRecette($id){ return $this->query(" SELECT I.*, F.familles, CR.quantites, U.unites, U.symboles FROM ingredients I JOIN composition_recettes CR ON CR.ingredients_id = I.id JOIN familles F ON F.id = I.familles_id JOIN unites U ON U.id = I.unites_id WHERE CR.recettes_id = ?", [$id], false); } }

Après tu peux utiliser :

$ingredients_recette = App::getInstance()->getTable('Ingredient')->findForRecette($recette_id);

Tu obtiendras un tableau de App\Entity\IngredientEntity dont voici le code :

<?php namespace App\Entity; use Core\Entity\Entity; class IngredientEntity extends Entity{ }

J'ai gardé la définition de tes tables en suivant l'illustration de ton schéma sans savoir si tu as modifié ou pas les champs de tes tables comme je te l'avais conseillé.

Un argument supplémentaire concernant la modifications des champs :

  • un champ au singulier te fera penser à une relation 1:1 (exemple champs categorie_id et non categories_id dans la table recette puisque une recette appartient à une seule catégorie, ce qui implique l'utilisation de join pour avoir toutes les données liées par la relation)
  • une variable au singulier pour représenter un seul objet
  • une variable au pluriel pour représenter plusieurs objets (souvent un tableau d'objet), exemple $ingredients_recette, ce qui implique une relation 1:n et l'utilisation d'une requête supplémentaire par rapport à ton objet principal (ici ta recette 1:n ingrédients).

Il te faut maintenant une autre classe chargée de générer le code html pour les champs de formulaire de tous les ingrédients en relation avec une recette qui devrait se situer en toute logique dans l'espace de nom App\Html et pourrait s'appeler IngredientForm.

Zulkar, il y a 8 ans

Bonjour et merci.
Je n'ai pas encore changé mon schéma par rapport à tes conseils.
J'ai inséré ton code et je n'ai pas touché à IngredientEntity, j'avais déjà cette classe.

Zulkar, il y a 8 ans

Ce n'est sans doute l'idéal, mais pour les tests, j'ai donc rajouté ce code à ma page recette.edit.php

$form2 = new \Core\HTML\IngredientForm($_POST);

J'ai laissé une seule div class="inline">...</div avec ingredients_id[] et quantite[]
J'utilise le bouton + pour ajouter une ligne et je saisie des données.
Le tableau me retourne donc :

Array ( [categories_id] => 5 [recettes] => Crème de champignons [nbpersonnes] => 4 [marge] => 4.5 [observations] => Test observations crème de champignons [ingredients_id] => Array ( [0] => 123 [1] => 124 ) [quantite] => Array ( [0] => 0.900 [1] => 0.500 ) )

Donc la même chose que nos tests en dur !!!

tamplan, il y a 8 ans

Rajoutes également l'id de la recette dans un champ caché par exemple, du coup, tu peux lier les ingrédients à ta recette dans ta table composition_recettes.

Tu as 2 tableaux ingredients_id et quantite dans la variable $_POST, l'id de la recette.
Tu dois pouvoir te servir d'une fonction de tableau de php pour obtenir un tableau contenant :

$ingredients[0] = array('recettes_id' => $recette_id, 'ingredients_id' => 123, 'quantite' => 0.900); $ingredients[1] = array('recettes_id' => $recette_id, 'ingredients_id' => 124, 'quantite' => 0.500);

Tu supprimes d'abord les ingrédients liés à ta recette puis tu ajoutes les données que tu as dans la variable $_POST pour gérer le cas où tu aurais enlever un ou plusieurs ingrédient(s) en éditant ta recette.

Zulkar, il y a 8 ans

J'ai fait ceci :

<div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <input type="hidden" name="recette_id" value="<?= $recette->id ?>"> <?= $form2->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <?= $form2->input('quantite[]', 'Quantité'); ?> </div> <!-- /.form group --> </div>

Avec 1 seul ingrédient et la quantité, $_POST m'indique l'id de la recette, mais si j'ajoute un 2ème ingrédient, $_POST m'indique un id recette vide.

tamplan, il y a 8 ans

Essaies comme ceci :

<input type="hidden" name="recette_id" value="<?= $recette->id ?>"> <div class="inline"> <div class=" col-md-7"> <!-- Ingrédient --> <?= $form2->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <?= $form2->input('quantite[]', 'Quantité'); ?> </div> <!-- /.form group --> </div>

Tu devrais pouvoir rajouter d'autres ingrédients.
Pourquoi ne pas en profiter pour générer le code hml pour les champs des ingrédients avec ta classe IngredientForm en changeant son constructeur pour lui passer également la liste des ingrédients ?

Zulkar, il y a 8 ans

Avant de continuer, si je place l'input caché avant la div inline, le bouton + ne fonctionne plus !

tamplan, il y a 8 ans

Tu gères ton bouton + avec du code javascript je suppose, tu l'as déjà posté ici que l'on regarde tout ça ?

Zulkar, il y a 8 ans

C'est bon, j'ai placé le input encore une div avant et je peux ajouter autant d'ingrédients que je veux.

Donc tu voulais dire quoi pour la classe IngredientForm ?

tamplan, il y a 8 ans

Et bien que tu devrais peut-être t'en servir pour générer out le code html pour la gestion des champs des ingrédients.
Tu passes le tableau des ingrédients dans le constructeur de ta classe et tu peux générer tout ce code :

<div class=" col-md-7"> <!-- Ingrédient --> <?= $form2->select('ingredients_id[]', 'Ingrédient', $ingredients); ?> <!-- /.form group --> </div> <div class="col-md-3"> <!-- Quantités --> <div class="group-form"> <?= $form2->input('quantite[]', 'Quantité'); ?> </div> <!-- /.form group --> </div>

plusieurs fois pour chaque ingrédients avec une fonction $form2->getFiledsForIngredients par exemple.

Zulkar, il y a 8 ans

Sans doute ! Je sais pas !

Donc là, il faut que j'arrive à récupérer les champs pré-remplis pour les ingrédients et les quantités de la recette ?
Ensuite, je dois :
. essayer de modifier un ingrédient ou une quantité
. essayer d'ajouter un ingrédient et la quantité
. essayer de supprimer un ingrédient
???

tamplan, il y a 8 ans

Tu géres l'affichage des champs avant que ton formulaire ne soit soumis quant tu modifies ta recette tu dois avoir les ingrédients avec le champ ingrédient et son champ quantité.
Les champs pré-remplis tu peux les gérer dans la fonction $form2->getFiledsForIngredients.
Tu fais ça avec une autre fonction chargée de générer le code html pour le champ ingrédient et son champ quantité justement.
Ensuite quand tu peux ajouter un ingrédient en cliquant sur le bouton + qui en ajax te retourne champ ingrédient et son champ quantité.
Tu valide ton formulaire et là tu ajoutes les ingrédients dans la base de données comme indiqué plus haut (en les supprimant avant comme indiqué).

Zulkar, il y a 8 ans

Je vais relire, essayer de comprendre et voir si je suis capable de faire ça à tête reposée !

tamplan, il y a 8 ans

ok ça marche

Zulkar, il y a 8 ans

Dans la classe IngredientForm, j'ai les fonctions input et select, donc dans la fonction getFieldsForIngredients il faut que je les utilise. Enfin je pense !
Mais, pour les

<div class=" col-md-7"> // et <div class=" col-md-3">

Je les indique comment ?

tamplan, il y a 8 ans

Tu peux utiliser des fonctions echo :

echo '<div class=" col-md-7">'; ... echo '</div>'; ...
Zulkar, il y a 8 ans
public function getFieldsForIngredients(){ echo '<div class="col-md-7"> <?= $form2->select(' . "'ingredients_id[]'" . ', ' . "'Ingrédient'" . ', ' . '$ingredients' . '); ?> </div> <div class="col-md-3"> <?= $form2->input(' . "'quantite[]'" . ', ' . "'Quantité'" . '); ?> </div>'; }
tamplan, il y a 8 ans

Hello, c'est pas tout à fait ça.
Je montre comment j'aurais fait à partir de 18h00 ce soir.

tamplan, il y a 8 ans

Alors, voilà ce que je te propose et que je viens de tester :

App\Entity\IngredientEntity

<?php namespace App\Entity; use Core\Entity\Entity; class IngredientEntity extends Entity { public function getQuantites() { return isset($this->quantites) ? $this->quantites : null; } public function getUnites() { return isset($this->unites) ? $this->unites : null; } }

App\HTML\FormIngredient

<?php namespace App\HTML; class FormIngredient { private $ingredients; /** * Constructeur avec la liste de tous les ingredients * * @param $ingredients */ public function __construct($ingredients) { $this->ingredients = $ingredients; } /** Retourne une ligne d'un groupe de champs * @param $ingredient App\Entity\IngredientEntity * @return string */ public function getFieldRow($ingredient) { // Chaîne à retourner $html = ''; // Ouverture d'une div regroupant les champs $html .= $this->getStartRow($ingredient->id); // Ingrédient sélectionné dans la liste de tous les ingrédients $html .= $this->getSelectField($ingredient, 'Ingrédient'); // Quantité pour l'ingrédient sélectionné $html .= $this->getInputField($ingredient, 'Quantité'); // Actions gérer la suppression d'un ingrédient $html .= $this->getActionsRow($ingredient->id); // Fermeture de la div $html .= $this->getEndRow(); return $html; } /** * @param $html string Code HTML à entourer * @return string */ private function surround($html){ return "<div class=\"form-group\">{$html}</div>"; } /* Début d'une ligne d'un groupe de champs identifié au niveau javascript * par l'identifiant unique d'un ingrédient * * @param $ingredient_id int identifiant unique d'un ingrédient * @return string */ private function getStartRow($ingredient_id) { return '<div class="inline" id="' . $ingredient_id . '">'; } /* Affiche une liste d'ingrédients sous la forme d'une liste d'options * @param $ingredient App\Entity\IngredientEntity * ingrédient sélectionné dans la liste * * @param $label string nom du label * @return string */ private function getSelectField($ingredient, $label) { $html = '<div class=" col-md-7">'; $label = '<label>' . $label . '</label>'; $input = '<select class="form-control" name="ingredient_' . $ingredient->id . '">'; foreach($this->ingredients as $an_ingredient) { $attributes = ''; // Si l'ingrédient est lié à la recette en cours de modification if($an_ingredient->ingredients == $ingredient->ingredients){ $attributes = ' selected'; } $input .= "<option value='{$an_ingredient->id}'$attributes>{$an_ingredient->ingredients}</option>"; } $input .= '</select>'; $html .= $this->surround($label . $input); $html .= '</div>'; return $html; } /** Permet de changer la quantité d'ingrédient * @param $ingredient App\Entity\IngredientEntity * ingrédient pour connaître sa quantité * * @param $label string nom du label * @return string */ private function getInputField($ingredient, $label) { $html = '<div class=" col-md-3">'; $label = '<label>' . $label . '</label>'; $input = '<input type="text" name="ingredient_' . $ingredient->id . '" value="' . $ingredient->quantites . '" class="form-control">'; $help = '<p class="help-block">Exprimée en ' . $ingredient->unites . '</p>'; $html .= $this->surround($label . $input . $help); $html .= '</div>'; return $html; } /* Permet la suppression d'un ingrédient * * @param $ingredient_id int identifiant unique d'un ingrédient * @return string */ private function getActionsRow($ingredient_id) { $html = '<div class="col-md-2">'; $html .= '<label>Action</label>'; $html .= '<button class="btn btn-default remove" data-role="remove" id="' . $ingredient_id . '"> '; $html .= '<span class="glyphicon glyphicon-remove"></span></button>'; $html .= '</div>'; return $html; } // Fin d'une ligne d'un groupe de champs private function getEndRow() { return '</div>'; } }

A utiliser avec ce bout de code :

$ingredients = App::getInstance()->getTable('Ingredient')->all(); $form_ingredient = new \App\HTML\FormIngredient($ingredients); $recette = App::getInstance()->getTable('Recette')->findWithCategory($_GET['id']); $ingredients_recette = App::getInstance()->getTable('Ingredient')->findForRecette($_GET['id']); $ingredients_html = ''; // $ingredients_html contient tout le code html pour gérer les champs select et input de chaque ingrédient foreach($ingredients_recette as $ingredient) { $ingredients_html .= $form_ingredient->getFieldRow($ingredient); }

Je te conseille d'aller jusqu'au chapitre Model/View/Controler de la formation, dans ce cas-là, le dernier bout de code est à mettre dans l'action show du controllleur RecetteController...

Zulkar, il y a 8 ans

Wahouuu ... ah oui ... tout ce code ... j'étais loin !!!

tamplan, il y a 8 ans

Dans la classe Form de Grafikart, il gére la valeur des champs, ici je l'ai codé en dur.
J'ai dû modifier la classe IngredientEntity pour gérer les getters et le cas où les propriétés Quantites et Unites sont nulles (c'est le cas par défaut car ces propriétés ne sont définies que par la liaison avec les tables concernées).
Je n'est pas utilisé la méthode avec des [] mais directement avec les idenfiants des ingrédients pour avoir des clés dans la variable $_POST mieux définies car uniques (ingredient_123, quantite_123 par exemple, on pourra gérer plus facilement la relation entre ingrédient et quantité comme ça).

Zulkar, il y a 8 ans

Je m'y perds dans le chapitre Model/View/Controler de la formation, car moi depuis le début, je ne fais pas tout et j'adapte car je ne pensais pas avoir besoin de tout ou fonctionner de la même façon :(

tamplan, il y a 8 ans

Je te conseille et ça reste un conseil de suivre ce chapitre car tout ton code sera bien mieux organisé.
Ici, je t'ai quand même écrit du code pour que tu puisses l'utiliser dans lire ce chapitre.
A toi de voir pour la suite...

Sinon, tu as eu le temps de tester ce que je t'ai filé ? J'ai oublié de préciser que j'avais englobé toute ta partie design dans mon code.

tamplan, il y a 8 ans

Et si tu as testé, tu as pu remarquer que j'ai utilisé les unités sous le champ input pour la quantité :)

Zulkar, il y a 8 ans

Ah non, je n'ai même pas essayé du tout !
Je me suis jeté directement sur la suite de la formation lol

tamplan, il y a 8 ans

Ok, je te laisse faire à ton rhytme, fais moi signe en cas de besoin :)

Zulkar, il y a 8 ans

Donc ton dernier bout de code, je dois l'intégrer dans ma page recette.edit.php

<?php // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { //Pour débogage echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); // UPDATE des données récupérées $result = $recetteTable->update($_GET['id'], [ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); // Trouver le code pour INSERT et UPDATE des ingrédients et quantités if ($result) { // Redirection et/ou Message } } // On récupère l'id de la recette $recette = $recetteTable->find($_GET['id']); // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $familles = App::getInstance()->getTable('Famille')->extract('id', 'familles'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); // On reprend le formulaire de la recette $form = new \Core\HTML\BootstrapForm($recette); $form2 = new \Core\HTML\IngredientForm($_POST); ?>
tamplan, il y a 8 ans

Modifies comme ceci :

<?php // Connexion à la table $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { //Pour débogage echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); // UPDATE des données récupérées $result = $recetteTable->update($_GET['id'], [ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); // Trouver le code pour INSERT et UPDATE des ingrédients et quantités if ($result) { // Redirection et/ou Message } } // On récupère l'id de la recette $recette = $recetteTable->find($_GET['id']); // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $familles = App::getInstance()->getTable('Famille')->extract('id', 'familles'); $ingredients = App::getInstance()->getTable('Ingredient')->extract('id', 'ingredients'); // On reprend le formulaire de la recette $form = new \Core\HTML\BootstrapForm($recette); $ingredients = App::getInstance()->getTable('Ingredient')->all(); $form_ingredient = new \App\HTML\FormIngredient($ingredients); $recette = App::getInstance()->getTable('Recette')->findWithCategory($_GET['id']); $ingredients_recette = App::getInstance()->getTable('Ingredient')->findForRecette($_GET['id']); $ingredients_html = ''; // $ingredients_html contient tout le code html pour gérer les champs select et input de chaque ingrédient foreach($ingredients_recette as $ingredient) { $ingredients_html .= $form_ingredient->getFieldRow($ingredient); } /* tu affiches ton formulaire mais à la place de <div class="inline"> ... </div> tu écris echo $ingredients_html; */ ?>
Zulkar, il y a 8 ans

Je ne retrouve pas la fonction qui a été faite findWithCategory() car il y a une erreur avec à la ligne 32

tamplan, il y a 8 ans

Au temps pour moi, c'est dans la classe App\Table\RecetteTable.php :

<?php namespace App\Table; use Core\Table\Table; class RecetteTable extends Table{ protected $table = 'recettes'; /** * Récupère les derniers article * @return array */ public function last(){ return $this->query(" SELECT recettes.id, recettes.recettes, categories.categories as categorie FROM recettes LEFT JOIN categories ON categories_id = categories.id ORDER BY recettes.id DESC"); } /** * Récupère une recette en liant la catégorie associée * @param $id int * @return \App\Entity\RecetteEntity */ public function findWithCategory($id){ return $this->query(" SELECT recettes.id, recettes.recettes, categories.categories as categorie FROM recettes LEFT JOIN categories ON categories_id = categories.id WHERE recettes.id = ?", [$id], true); } }

Du coup avec le bootstrap normal, ça donne un truc comme ça :

Zulkar, il y a 8 ans

J'obtiens ceci :

tamplan, il y a 8 ans

Regarde le code source de la page, je te prie autour du second bloc d'actions.
Oublies les boutons sur ma capture d'écran, j'ai modifié ma page entre temps.

Zulkar, il y a 8 ans

Je rajoute ces lignes pour le bouton +

$html .= '<button class="btn btn-default" data-role="add"> '; $html .= '<span class="glyphicon glyphicon-plus"></span></button>';
tamplan, il y a 8 ans

Normalement, le code que je t'ai donné gère également les boutons (des boutons + pour le coup qu'il faudra changer en -), je t'invite à regarder mon code plus en détails.

Zulkar, il y a 8 ans

Oui, dans FormIngredient, tu gères la modification des quantités, j'ai testé et le $_POST le prend bien en compte.
Le changement d'ingrédient ne change rien !
Tu gères aussi la suppression d'un ingrédient ... que je n'ai pas testé !
Et si j'ajoute le bouton + comme je l'ai indiqué, l'ajout n'est pas pris en compte.

tamplan, il y a 8 ans

Attends, c'est normal, mon code ne gère "que" la partie formulaire pour les ingrédients liés à une recette.
Le changement de quantités donctionne en effet mais pas le changement d'ingrédient.
Décommentes la ligne de debug pour afficher le contenu de la variable $_POST je te prie.
Pour le bouton + non géré, c'est normal également, il va falloir le gérer en ajax.

Zulkar, il y a 8 ans
Array ( [categories_id] => 5 [recettes] => Crème de champignons [nbpersonnes] => 4 [marge] => 4.5 [observations] => Test observations crème de champignons [recette_id] => 3 [ingredient_145] => 0.400 [ingredient_124] => 0.250 )
tamplan, il y a 8 ans

Ah, je pensais que l'on aurait des clés 'quantite_145' et 'quantite_124' aussi mais c'est pas grave.
Le temps pour moi de te coder ça en te donnant les explications...

tamplan, il y a 8 ans

Modifies ton code comme ceci :

// Trouver le code pour INSERT et UPDATE des ingrédients et quantités $recette_id = $_POST['recette_id']; $compositionTable = App::getInstance()->getTable('CompositionRecette'); // Suppresion des ingrédients déjà ajoutés (sinon on aura des doublons) //$compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]); // Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variavle $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST[$k] ]); } }

Je ne suis pas sur de cette ligne alors je l'ai commentée :

//$compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]);

Tu auras sans doute des ingrédients en double si tu la laisse commentée.
Je ne me souviens plus dans quel chapitre Grafikart aborde la suppression d'un enregistrement.

Pour le moment, tu peux modifier les ingrédients mais pas en ajouter ou en retirer...
La suite demain où on va aborder la partie ajout d'ingrédient...

tamplan, il y a 8 ans

Je t'invite à bien lire le code que je t'ai donné et recherché les fonctions utilisées...

Zulkar, il y a 8 ans

L'ajout, l'édition et la suppression, sont dans le TP: Back-end !

tamplan, il y a 8 ans

ok, je regarde ça et on corrige demain.

tamplan, il y a 8 ans

Tu peux déjà décommenté cette ligne, je viens de lire le code de la classe Core\Table\Table.php :

$compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]);
Zulkar, il y a 8 ans

Pour le moment, j'ai l'impression que modifier un ingrédient ne change rien dans $_POST
Ton code :

//$compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]);

C'est pour supprimer une recette ?
Si oui, ça je l'ai fait directement dans phpmyadmin.

tamplan, il y a 8 ans

Relis bien le code, il s'agit de la table composition_recettes, ne vas pas trop vite car tu vas mal apprendre :)
Ici, il s'agit de supprimer tous les ingrédients d'une recette avant d'enregistrer les ingrédients lorsque tu soumets le formulaire pour valider la modification de ta recette, sans ça tu auras des doublons.

Tu n'as qu'un seul bouton pour valider ton formulaire (pour modifier ta recette et ses ingrédients), on enregistre les modifications (et donc les ingrédients) en une seule fois.

Pour le moment, ça ne change rien sauf si tu modifie les ingrédients sans pouvoir changer leur nombre (ajout ou suppression).

Zulkar, il y a 8 ans

Bonsoir,
De retour après une absence imprévue, donc oui, tu as raison, je suis d'accord avec toi !!!

tamplan, il y a 8 ans

Bonsoir,
Où en es tu ? Tu es allé jusqu'au chapitre Model/Vue/Controller ou tu restes avec ta structure, histoire que j'adapte mon code au tiens ?
Je ne serais pas là demain soir mais disponible samedi.
On devrait passer à la gestion de l'ajout d'un nouveau bloc pour un ingrédient (avec select et input) en ajax...

Zulkar, il y a 8 ans

Bonjour,
Pour le moment, je garde ma structure, car il faut que j'adapte le chapitre des Controllers à mon cas et pour le moment, je ne suis pas au point.
Je visionne et re-visionne le chapitre !!
Ok pour la suite :)

tamplan, il y a 8 ans

Ok, donc de mon côté, je modifie mon code pour ne pas utiliser les contrôleurs tout comme toi.

Zulkar, il y a 8 ans

Bonsoir,
J'ai oublié, mais peut-être que tu attendais mon code qui permets de gérer les boutons + et - en JS :

// FONCTION AJOUTER LES INGREDIENTS D'UNE RECETTE // Remove button click $(document).on('click', '[data-role="dynamic-fields"] > .inline [data-role="remove"]', function(e) { e.preventDefault(); $(this).closest('.inline').remove(); } ); // Add button click $(document).on('click', '[data-role="dynamic-fields"] > .inline [data-role="add"]', function(e) { e.preventDefault(); var container = $(this).closest('[data-role="dynamic-fields"]'); new_field_group = container.children().filter('.inline:first-child').clone(); new_field_group.find('input').each(function(){ $(this).val(''); }); container.append(new_field_group); } );
tamplan, il y a 8 ans

Hello, désolé pour hier, j'ai eu des problèmes de connexion internet.
Je teste ton code sur le mien pour voir comment poursuivre...

tamplan, il y a 8 ans

Je viens de coder et tester ça :
Classe App\Entity\FamilleEntity :

<?php namespace App\Entity; use Core\Entity\Entity; class FamilleEntity extends Entity{ }

Classe App\Table\FamilleTable :

<?php namespace App\Table; use Core\Table\Table; class FamilleTable extends Table{ protected $table = 'familles'; }

Le fichier index.php modifié :

// Si a est passé en paramètre, on traite des requêtes en ajax if(isset($_POST['a'])){ $ajax = $_POST['a']; }else{ $ajax = null; } // Si a est défini if ($ajax){ // On traite la bonne requête ajax if ($ajax === 'add_ingredient'){ require '../ajax/add_ingredient.php'; } // Et on quitte le script die(); } if(isset($_GET['p'])){ ...

La page pages/recettes.show modifiée :

<?php $familleTable = App::getInstance()->getTable('Famille'); $ingredientTable = App::getInstance()->getTable('Ingredient'); $recetteTable = App::getInstance()->getTable('Recette'); $ingredients = $ingredientTable->all(); $form_ingredient = new \App\HTML\FormIngredient($ingredients); $recette = $recetteTable->findWithCategory($_GET['id']); $ingredients_recette = $ingredientTable->findForRecette($_GET['id']); $ingredients_html = ''; foreach($ingredients_recette as $ingredient) { $ingredients_html .= $form_ingredient->getFieldRow($ingredient); } $familles = $familleTable->extract('id', 'familles'); $form = new \Core\HTML\BootstrapForm(); ?> <h1><?= $recette->recettes; ?></h1> <form> <div class="row" id="liste-ingredients"> <?= $ingredients_html; ?> </div> <div class="row"> <div class="form-group"> <label>Famille d'ingredients :</label> <select class="form-control" name="famille" id="famille"> <?php foreach($familles as $k => $v): ?> <option value='<?= $k ?>'><?= $v ?></option> <?php endforeach; ?> </select> </div> <button class="btn btn-success" data-role="add" id="add-ingredient" data-famille="1"> <span class="glyphicon glyphicon-plus"></span> Ajouter un ingrédient</button> </div> </form> <script> $( document ).ready(function() { // Changement de famille d'ingrédient $( "#famille" ).change(function(e) { // On passe l'id de la famille choisie au bouton $( "#add-ingredient" ).data('famille', this.value); }); // Suppression d'un ingrédient $( "#liste-ingredients" ).on("click", "button.remove", function(e) { e.preventDefault(); var ingredient_id = $( this ).data("ingredient"); $( '#'+ingredient_id ).slideUp(); }); // Ajout d'un ingrédient $( "#add-ingredient" ).click(function(e) { e.preventDefault(); var famille_id = $( "#add-ingredient" ).data('famille'); $.ajax({ url : 'index.php', type : 'POST', data : 'a=add_ingredient&famille_id=' + famille_id, dataType : 'html', success : function(html, statut){ $( "#liste-ingredients" ).append(html); } }); }); }); </script>

Je n'ai pas adapter ton code en fin de compte.
La liste des familles des ingrédients est proposée au dessus du bouton ajouté. Un changement dans cette liste puis un ajout sur le bouton 'Ajouter un ingrédient' fait apparaître un nouveau bloc pour un nouvel élément (famille 'Boucherie' => Porc, agneau...).
Un appui sur un des boutons 'X' supprime la ligne du bloc concerné avec une petite animation (effet SlideUp), la validation du formulaire devrait permettre l'ajout et/ou la suppression des ingrédients.

Zulkar, il y a 8 ans

Pour la Classe App\Entity\FamilleEntity -> OK, je l'avais.
Pour la Classe App\Table\FamilleTable -> OK, je l'avais.

Ca, je n'ai pas cette page :

// On traite la bonne requête ajax if ($ajax === 'add_ingredient'){ require '../ajax/add_ingredient.php'; }

Et pour la page recette.show, je ne l'ai pas non plus.

tamplan, il y a 8 ans

Désolé d'avoir oublié cette page, à mettre dans le dossier ajax dans le dossier parent de public :

<?php $ingredientTable = App::getInstance()->getTable('Ingredient'); $ingredients_famille = $ingredientTable->findForFamille($_POST['famille_id']); $form_ingredient = new \App\HTML\FormIngredient($ingredients_famille); echo $form_ingredient->getFieldRow($ingredients_famille[0]); ?>

La page recette.show est la page que tu affciche quand tu modifes une recette, je ne me souviens plus du nom que tu as utilisé chez toi.

Zulkar, il y a 8 ans

Ah oui (recette.edit.php), je me disais aussi que le début du code me disait quelque chose :).
Je teste ça ce midi !!!
MERCIII

Zulkar, il y a 8 ans

J'espère ne rien avoir oublié !
J'ai essayé de placer ton code parmis ce qui avait déjà été fait.
Voici en visuel ce que cela donne :

tamplan, il y a 8 ans

Bonjour, ça semble correct en effet sauf que chez moi je n'ai qu'un seul bouton + comme déjà mentionné.
As tu essayé mon code ("mon" bouton ?) pour ajouter et tes boutons pour supprimer un ingrédient ?

Zulkar, il y a 8 ans

En effet, je me suis dit qu'avec mon code, l'ajout et la suppression de ligne fonctionnait.
Mais je voulais voir ce que donnait ton code !

tamplan, il y a 8 ans

Et donc au final, ça fonctionne ?

Zulkar, il y a 8 ans

Avec tes pages et ton code, l'action sur le '+' ou 'x' et sur 'ajouter un ingrédient' ne donnait rien dans le print_r de $_POST
Je ne suis pas sûr non plus que les changements dans index.php et la page ajax soient actifs !

Zulkar, il y a 8 ans

J'essaie de tout vérifier avec minutie, je ne trouve pas pour le moment !
Donc pour toi, dans la recette que je montre toujours comme exemple (crème de champignons, avec 2 ingrédients), tu as 2 boutons X pour supprimer les lignes et seulement ton bouton 'Ajouter un ingrédient' alors ?

tamplan, il y a 8 ans

Oui, en effet c'est exactement ça.
Si tu es sous Linux, je te propose de rentrer cette commande à la racine de ton site (dossier parent du dossier public) :

php -S 127.0.0.1:8000 -t ./public/ -d display_errors=1

En ayant pris soin de modifer la configuration de la base de données, ensuite en allant sur http://localhost:8000/index.php?p=recettes.show&id=1, tu pourras modifier la recette n°1.

Zulkar, il y a 8 ans

Ah oui, en effet, moi je n'ai pas ce résultat de fonctionnement !

tamplan, il y a 8 ans

C'est à dire, tu as testé mon code ? Il est différent du tien ?

Zulkar, il y a 8 ans

J'ai testé ton code oui, à partir du ZIP que tu as partagé !
Et j'ai du mal à voir où est le soucis avec l'adaptation dans mon code

tamplan, il y a 8 ans

Tu as testé et ça fonctionne donc ? Le comportement te convient ?

Regarde déjà mon fichier public/index.php.
Ensuite, j'ai peut-être changé la classe FormIngredient entre temps.
Je te conseille l'utilisation de ce logiciel pour comparer les fichier http://meldmerge.org/

Zulkar, il y a 8 ans

Le comportement me plaît bien. Je n'avais pas imaginé ça comme ça !
Je regarde pour tout le reste !

tamplan, il y a 8 ans

Je viens de regarder vite fait avec Meld, nous avons des noms de classes différents :

  • FamilleEntity chez moi, FamilyEntity chez toi
  • CategorieEntity chez moi, CategoryEntity chez toi

Attention, le code de Grafikart, ne gère pas les formes plurielles des noms en anglais mais en français : CategorieTable pour la table implique CategorieEntity pour l'entité retournée.
Je pense qu'une partie du problème peut venir de là.

tamplan, il y a 8 ans

Content que ça te plaise :-)

tamplan, il y a 8 ans

Dans mon code en bonus, tu trouveras la structure MVC sur laquelle tu butais, j'ai commenté une partie du code cependant (fichier public/index.php notament).
[Edit]
Je viens de voir que tu as fait pareil de ton côté pour le MVC...
[/Edit]

tamplan, il y a 8 ans

Je te laisse regarder et étudier tout ça pour ce soir, fais moi signe demain soir en cas de besoin.
Bonne soirée.

Zulkar, il y a 8 ans

Un grand MERCI.
Bonne soirée aussi !

Zulkar, il y a 8 ans

Avant d'oublier, j'indique ici ce que j'ai fait :

-> modification des Entity pour avoir les même que toi,

-> ajout de la fonction 'findForFamille' dans la table Ingredient,
que je n'avais pas,

-> j'ai enfin le design attendu avec un seul bouton 'ajouter un ingrédient' et un bouton supprimer à chaque fin de ligne.

Les actions 'supprimer' et 'ajouter' ne donnent rien (que la ligne de débogage soit commentée ou pas), donc je dois encore avoir un petit soucis quelque part !

Je pense que cela pourrait provenir de tout le code que l'on avait fait avant pour éditer les tables 'Recette' et 'CompositionRecette'. Car toi tu n'as pas tout ça dans ton code !

EDIT

J'ai "exporté" la partie JS qui est en bas de la page 'show' dans mon fichier JS et ça fonctionne mieux.

-> pour les animations, il doit avoir du mal à les prendre en compte.

-> impossible d'ajouter 2 ingrédients d'une même famille.

-> supprimer 2 ingrédients, rien ne se passe au click.

Zulkar, il y a 8 ans

Bonsoir,
Pour faire les tests, je garde la ligne de débogage décommentée.
-> supprimer un ingrédient existant déjà dans la recette (donc champ pré-rempli), ne "fonctionne" pas,
-> si j'ajoute par exemple 2 ingrédients, et que je décide de faire marche arrière, je peux en supprimer 1, ensuite les boutons "supprimer" n'ont plus d'action.

tamplan, il y a 8 ans

C'est moi qui déconne, la bonne syntaxe est :

$compositionTable->query("DELETE FROM composition_recettes WHERE recettes_id = ?", [$recette_id]);

ça devrait aller maintenant, penses à retirer la ligne die suivante...

tamplan, il y a 8 ans

Bonsoir,
Essaies de voir ce que te retourne la ligne de debug.

Zulkar, il y a 8 ans

Alors ajouter ou supprimer des ingrédients, apparemment ça fonctionne ... SAUF ... lol
Que toutes les quantités se transforment en 145.000, alors que moi je rentre 0.400 par exemple !

Zulkar, il y a 8 ans

En fait les chiffres avant le '.' correspondent aux 'id'

tamplan, il y a 8 ans

ok, c'est le bout de code avec $_POST[$k], je regarde le code...

tamplan, il y a 8 ans

Bonsoir,
Désolé pour l'attente, j'ai en déplacement loin de ma machine de dévloppement et c'était pas prévu.

Dans le code que je t'avais donné, tu as :

... // Suppression d'un ingrédient $( "#liste-ingredients" ).on("click", "button.remove", function(e) { e.preventDefault(); var ingredient_id = $( this ).data("ingredient"); $( '#'+ingredient_id ).slideUp(); }); ...

Modifies le comme suit :

... // Suppression d'un ingrédient $( "#liste-ingredients" ).on("click", "button.remove", function(e) { e.preventDefault(); var ingredient_id = $( this ).data("ingredient"); $( '#'+ingredient_id ).slideUp(); $( '#'+ingredient_id ).remove(); }); ...

Le bloc était seulement caché au lieu d'être caché puis détruit.

J'ai fait quelques tests y compris l'ajout et le retrait de 2 ingrédients, ça fonctionne chez moi, les champs sont correctment passés.

Zulkar, il y a 8 ans

Bonsoir,
Je n'ai pas trop été présent non plus !
Merci pour la modification.

Donc lorsque je prends la recette par exemple 'Crème de champignons' qui contient 2 ingrédients, je l'édite, je supprime 1 ingrédient ... lorsque je valide, la ligne de déboggage m'indique toujours les 2 ingrédients et leur quantité.

Pour le reste, c'est bon !

tamplan, il y a 8 ans

Je pense que ça vient de ton code js, essaies juste avec le mien pour voir, je viens juste de tester de mon côté et je ne rencontre aucun problème.

Zulkar, il y a 8 ans

Pardon, excuses-moi, c'est Chrome qui a du mal à rafraichir les modifications.
Sur Firefox ça fonctionne très bien !
Autant pour moi pffffff

Zulkar, il y a 8 ans

Donc dans le code qui suit, à début de ma page, on a plus qu'à prendre en compte tous les changements, modifications, addition, édition et suppression ?

<?php // Connexion aux tables $familleTable = App::getInstance()->getTable('Famille'); $ingredientTable = App::getInstance()->getTable('Ingredient'); $recetteTable = App::getInstance()->getTable('Recette'); if (!empty($_POST)) { //Pour débogage echo '<pre>' . print_r($_POST, true) . '</pre>'; die(); // UPDATE des données récupérées $result = $recetteTable->update($_GET['id'], [ 'categories_id' => $_POST['categories_id'], 'recettes' => $_POST['recettes'], 'nbpersonnes' => $_POST['nbpersonnes'], 'marge' => $_POST['marge'], 'observations' => $_POST['observations'] ]); // Trouver le code pour INSERT et UPDATE des ingrédients et quantités $recette_id = $_POST['recette_id']; $compositionTable = App::getInstance()->getTable('CompositionRecette'); // Suppression des ingrédients déjà ajoutés (sinon on aura des doublons) $compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]); // Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variable $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST[$k] ]); } } if ($result) { // Redirection et/ou Message } } // On récupère l'id de la recette $recette = $recetteTable->find($_GET['id']); // Connexion aux tables pour remplir les SELECT $categories = App::getInstance()->getTable('Categorie')->extract('id', 'categories'); $familles = $familleTable->extract('id', 'familles'); $ingredients = $ingredientTable->extract('id', 'ingredients'); // On reprend le formulaire de la recette $form = new \Core\HTML\BootstrapForm($recette); $ingredients = $ingredientTable->all(); $form_ingredient = new \App\HTML\FormIngredient($ingredients); $recette = $recetteTable->findWithCategory($_GET['id']); $ingredients_recette = $ingredientTable->findForRecette($_GET['id']); $ingredients_html = ''; // $ingredients_html contient tout le code html pour gérer les champs select et input de chaque ingrédient foreach($ingredients_recette as $ingredient) { $ingredients_html .= $form_ingredient->getFieldRow($ingredient); } ?>
tamplan, il y a 8 ans

Le code est déjà prêt, il te suffit de commenter la ligne de debug.
Prend le temps de bien lire le code avant et note toi le contenu retourné par la ligne de debug justement.

Zulkar, il y a 8 ans

Justement, si je décommente la ligne de debug, il m'indique une erreur avec 'recette_id' de cette ligne :

$recette_id = $_POST['recette_id'];
tamplan, il y a 8 ans

Je pensais que l'on avait parler de mettre un champ caché nommé recette_id avec l'identifiant de la recette.
Tu mets ça bien sûr après l'ouverture du formulaire.

Zulkar, il y a 8 ans

J'ai cette erreur :

Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '* FROM composition_recettes WHERE recettes_id = '3'' at line 1 in /srv/http/Dev/Dashboard/core/Database/MysqlDatabase.php on line 54

tamplan, il y a 8 ans

Tu as bien la table composition_recettes écrite comme ça ?

Zulkar, il y a 8 ans

Oui, j'ai vérifié justement et je n'ai rien touché à ce niveau depuis le début.

tamplan, il y a 8 ans

Modifies le code comme ceci pour tester :

$compositionTable->query("DELETE * FROM composition_recettes WHERE recettes_id = ?", [$recette_id]); die('Suppression des ingrédients de la recette n°' . $recette_id);

Afin de vérfier que la requête est correctement exécutée, attention si c'est le cas tous les ingrédients de la recette seront supprimer et plus attribués en phase de test...

Zulkar, il y a 8 ans

Même message d'erreur et rien dans la console

tamplan, il y a 8 ans

En changeant ça :

// Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variable $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST[$k] ]); } }

Par ça :

// Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variable $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST['quantite_' . $k] ]); } }

ça devrait le faire... :-)

Zulkar, il y a 8 ans

Undefined index: quantite_ingredient_145 in /srv/http/Dev/Dashboard/pages/recettes/recette.edit.php on line 38

C'est la ligne des quantités !

;)

tamplan, il y a 8 ans

Tu peux décommenter la ligne de debug et me retourner le contenu de la varaible $_POST je te prie ?

Zulkar, il y a 8 ans
Array ( [categories_id] => 5 [recettes] => Crème de champignons [nbpersonnes] => 4 [marge] => 4.5 [observations] => Test observations crème de champignons [recette_id] => 3 [ingredient_145] => 145 [quantite_145] => 0.250 [ingredient_124] => 124 [quantite_124] => 0.200 [ingredient_144] => 144 [quantite_144] => 0.060 [famille] => 5 )
tamplan, il y a 8 ans

Je n'ai pas les yeux en face des trous ce soir...
En changeant ça :

// Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variable $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST[$k] ]); } }

Par ça :

// Analyse des clés des varaibles postées foreach(array_keys($_POST) as $k) { // Si la clé commence par 'ingredient' if (strpos($k, 'ingredient') === 0) { // La variable $_POST[$k] contient la quantité // On décompose la chaîne 'ingredient_xxx' en deux variables // $dummy = 'ingredient' (qui ne sert à rien) et $ingredient_id = 'xxx' (l'identifiant de l'ingrédient) list($dummy, $ingredient_id) = explode('_', $k); $compositionTable->create([ 'recettes_id' => $recette_id, 'ingredients_id' => $ingredient_id, 'quantites' => $_POST['quantite_' . $ingredient_id] ]); } }

ça devrait ENFIN le faire... :-)

Zulkar, il y a 8 ans

Juste une ',' en trop à la fin de '$ingredient_id', mais ça m'a l'air de fonctionner.
Je vais faire différents tests !

J'ai juste un truc dans ma page 'recettes.php', elle affiche la liste des recettes et TOUS les ingrédients de toutes les recettes.
Avec ce code, lorsque je clique sur une recette pour afficher le détail correspondant, je récupère bien l'id de la recette dans la barre d'adresse mais il ne me sélectionne pas seulement les ingrédients de la recette en question.

<table id="recettes-table" class="table table-bordered table-striped" width="100%"> <thead> <tr> <th>Recettes</th> <th width="25%">Actions</th> </tr> </thead> <tbody> <?php foreach (App::getInstance()->getTable('Recette')->all() as $recette): ?> <tr> <td onclick="location.href='index.php?p=recettes&id=<?= $recette->id; ?>'"><?= $recette->recettes; ?></td> <td> <!-- Bouton Editer --> <a href="?p=recette.edit&id=<?= $recette->id; ?>" class="btn btn-xs btn-default btn-flat"><span class="glyphicon glyphicon-pencil"></span></a> <!-- Bouton Imprimer --> <a href="#" class="btn btn-xs btn-default btn-flat"><span class="glyphicon glyphicon-print"></span></a> <!-- Bouton Supprimer --> <form action="?p=recette.delete" method="post" style="display: inline;"> <input type="hidden" name="id" value="<?= $recette->id ?>"> <button type="submit" class="btn btn-xs btn-default btn-flat"><span class="glyphicon glyphicon-trash"></span></button> </form> </td> </tr> <?php endforeach; ?> </tbody> </table>
tamplan, il y a 8 ans

J'ai corigé ma coquille...

tamplan, il y a 8 ans

Je n'ai pas bien compris, normalement quand tu édites une recette, tu ne devrais avoir que la liste des ingrédients liés à cette recette.

Zulkar, il y a 8 ans

Oui oui, tu as raison.
Je parlais de ma page 'recettes.php', ma page qui affiche toutes mes recettes avec le détail et les calculs, la page où je clique sur le bouton EDITER.
Mais ça sera un autre post je pense.

tamplan, il y a 8 ans

Je penche aussi pour un autre sujet dans le forum.

Zulkar, il y a 8 ans

Bonjour,
As-tu essayé d'ajouter 2 ingrédients de la même famille ?
Pour ma part, il n'en prend qu'un en compte et si j'insiste en saisissant le 2ème ingrédient qui n'est pas passé, il va simplement changer la quantité du premier.

Tackacoder, il y a 8 ans

Salut,
Juste par souci d'efficacité. Je vois beaucoup de App::getInstance() dans ton code.
Tu pourrai faire ceci, quelque part.

function app() { return App::getInstance(); } app()->getTable('Recette');
Zulkar, il y a 8 ans

Merci pour ta contribution ;)

Zulkar, il y a 8 ans

Bonjour,
Hier soir, j'ai commencé à remplir un peu plus ma base de données afin de mieux me rendre compte de tout le fonctionnement.
J'ai voulu faire des oublis ... volontairement !
J'ai donc créé une recette.
Après la validation, je me rends compte que j'ai oublié un ingrédient.
J'édite donc la recette.
Je choisi la famille, puis l'ingrédient et la quantité ... je valide.
Mais au bout du compte, il affiche le premier ingrédient qui est dans la famille.
Je souhaite quand même le modifier, j'ouvre le SELECT et je vois qu'il me donne les 100 ingrédients que j'ai dans ma base.
Bref, je choisi l'ingrédient que je souhaite depuis le début, je valide.
Mais cela ne change rien, il garde l'ingrédient qu'il avait enregistré.

Je ne vois pas où se trouve le problème en examinant le code !

Zulkar, il y a 8 ans

Bonsoir,
Par exemple, je prends la recette de 'Confit d'oignons' :
beurre 100 gr
oignon 1 kg
sel fin 10 gr

J'édite la recette.
1 - Pour le test, je choisi la famille 'Crèmerie' comme pour le beurre.
Mais je choisi d'ajouter 200 gr de lait.
Après validation, il n'a pas validé le lait, mais à modifier le beurre pour enregistrer 200 gr à la place des 100 gr de départ.

2 - Un autre test, je choisi la famille 'Légumes' comme pour oignon.
Je choisi d'ajouter 200 gr d'échalotes.
Ca fonctionne apparemment

Après 3 tests, sur cette recette, le problème ne concerne que la famille du 1er ingrédient.

Ca, c'est le beug du jour ... j'ai l'impression d'avoir des comportements différents à chaque fois, mais là, c'est ce qu'il me fait.

Zulkar, il y a 8 ans

Une nouvelle recette :

Array ( [categories_id] => 1 [recettes] => Cookies Balls aux pignons de pin [nbpersonnes] => 30 [marge] => 3 [observations] => Cuisson : 190°C / 15 mn Réalisation : Former des boules de 10 gr [recette_id] => 18 [ingredient_1] => 1 <--- Farine [quantite_1] => 0.090 [ingredient_2] => 2 <--- Levure chimique [quantite_2] => 0.001 [ingredient_10] => 10 <--- Pignons de pin [quantite_10] => 0.050 [ingredient_17] => 17 <--- Beurre [quantite_17] => 0.050 [ingredient_20] => 20 <--- Parmesan [quantite_20] => 0.030 [ingredient_113] => 113 <--- Basilic [quantite_113] => 0.001 [ingredient_15] => 15 <--- Oeuf [quantite_15] => 1.000 [famille] => 4 )

Pour le test, je supprime l'ingrédient 10 'Pignons de pin'.
Je vérifie dans ma liste de recette et l'ingrédient a bien été supprimé.
J'édite la recette pour l'ajouter à nouveau.
Je choisi la famille 'Epicerie' qui me donne tous les ingrédients figurant dans cette famille.
Je choisi 'Pignons de pin' avec la quantité 0.050 gr. Je valide.

Array ( [categories_id] => 1 [recettes] => Cookies Balls aux pignons de pin [nbpersonnes] => 30 [marge] => 3 [observations] => Cuisson : 190°C / 15 mn Réalisation : Former des boules de 10 gr [recette_id] => 18 [ingredient_1] => 10 [quantite_1] => 0.050 [ingredient_2] => 2 [quantite_2] => 0.001 [ingredient_17] => 17 [quantite_17] => 0.050 [ingredient_20] => 20 [quantite_20] => 0.030 [ingredient_113] => 113 [quantite_113] => 0.001 [ingredient_15] => 15 [quantite_15] => 1.000 [famille] => 4 )

On voit que l'ingrédient 10 'Pignons de pin' n'apparaît pas MAIS que l'ingrédient 1 'Farine' a changé de quantité : 0.050 au lieu de 0.090 précédemment.
Et l'id de l'ingrédient 1 a changé également. Il est affiché 10, ça c'est l'id de 'Pignons de pin'.
L'explication, lorsque j'ai choisi la famille 'Epicerie', le premier ingrédient figurant dans cette famille est 'Farine de blé', donc c'est lui qui a été pris en compte.

J'espère que cette exemple est plus parlant.
Je ne vois pas d'où vient le problème.

Si tu veux te rendre compte, je peux fournir tous les fichiers et le code, avec la base de données !