Salut, il n'affiche pas le dernier id avec cette debug?
if ($this->nomController->data) {
$this->Products->save($this->nomController->data, 'p_id', $tab);
$id = $this->Products->id;
debug($id);
}
Bonjour à tous, Voilà, cela fait 15 jours que je tourne en rond pour résoudre un problème de subquery. J'ai dévoré les tuto MVC de Grafikart sur la partie insertion en base, et j'ai voulu aller plus loin (dans la limite de mes connaissance :)). Dans le tuto, la requete PDO ne concerne que les champs d'une seule table. J'ai modifié cela pour pouvoir faire des jointures multiples. Mais j'ai un problème pour l'insertion. En effet, j'aimerai récupérer le dernier ID inscrit dans une table et l'inscrire dans une autre table. J'ai essayé avec les LAST_INSERT_ID(MAX(id)) de MYSQL, et autres que j'ai pu trouver sur les différents forums, mais là je suis à court d'idées. Ci-dessous, voici la dose de code que j'ai créé avec les explications. Si vous avez une idée, je suis preneur. Tout d'abord, voici mon controller ProductsController.php et la fonction admin_edit() (ne faites pas attention aux commentaires) [code] function admin_edit(
Salut, il n'affiche pas le dernier id avec cette debug?
if ($this->nomController->data) {
$this->Products->save($this->nomController->data, 'p_id', $tab);
$id = $this->Products->id;
debug($id);
}
Bonjour,
Le debug m'affiche '0'.
Par contre, si je mets dans ma boucle foreach $this->db->lastInsertId(); il me récupère bien le dernier id inscrit en base
Voici le code :
foreach ($insertGlobal as $ind => $val) {
$pre = $this->db->prepare($val'sql']);
/* foreach ($val'valeur-fusion'] as $kindex => $kval) {
//debug($this->db->lastInsertId());
$pre->bindValue($kindex, $kval);
debug("$kindex => $kval");
}
$pre->execute(); */
$pre->execute($val'valeur-fusion']);
$ida = $this->db->lastInsertId();
debug($ida);
//debug($pre->errorInfo());
//debug($pre);
if (Config::$debug >= 1) {
$test = $pre->errorInfo();
//$test'message'] = $pre->getMessage();
debug($test);
}
//$pre->debugDumpParams();
}
et voici la tableau
/Applications/MAMP/htdocs/cms-heatmap/core/Model.php l.636
47
/Applications/MAMP/htdocs/cms-heatmap/core/Model.php l.636
99
/Applications/MAMP/htdocs/cms-heatmap/core/Model.php l.636
88
/Applications/MAMP/htdocs/cms-heatmap/core/Model.php l.636
112
/Applications/MAMP/htdocs/cms-heatmap/core/Model.php l.636
101
/Applications/MAMP/htdocs/cms-heatmap/controller/ProductsController.php l.287
0
Du coup, je n'arrive pas à comprendre pourquoi il ne veut pas me l'inscrire dans ma table à ce moment là !!
Est-ce qu'il faut que je modifie ma requête une fois qu'elle est exécutée, afin de faire un update des champs ????
Ca semble un peu idiot de le faire ainsi non?
Fabien
Dans ma table, la requete insert à chaque fois 0.
Je viens de tester le type de chaque lasinsertid() et au final, il s'agit d'un string et pas d'un int
Forcément, ça peut pas marcher (enfin je crois)
Mais du coup, je ne sais pas comment faire pour lui dire d'inscrire un int et pas un string !!
J'espère être sur la bonne piste cette fois ci !
Salut, je crois que le problème vient quand tu as désactivé le mode autocommit.
ce que je propose de réactiver l'autocommit et d'enlever les deux fonctions PDO beginTransaction(); et commit();
J'ai essayé mais cela n'a rien changé.
J'ai essayé de modifier le type de champ product_id pour le passer en varchar et j'ai refait un test !
Là, il m'inscrit la commande SQL au lieu de m'inscrire le résultat.
Du coup, il a inscrit dans le champ "product_id" la valeur :
CONVERT(SELECT id FROM product ORDER BY id DESC LIMIT 1),UNSIGNED INTEGER)
J'ai modifié la requête pour voir :
SELECT id FROM product ORDER BY id DESC LIMIT 1
non il ne l'interprete pas.
Ce que je ne comprends pas, c'est que la requête fonctionne correctement lorsque je suis dans phpmyadmin : exemple ci-dessous
INSERT INTO product_seo SET id=NULL,product_id=SELECT id FROM product ORDER BY id DESC LIMIT 1,title=NULL,metakey=NULL,metadesc=NULL,slug=NULL
Merci pour ton aide.
Je vais essayer de creuser la piste que j'évoquais plus haut, qui est la transformation du champ en entier.
J'ai vu qu'avec bindValue() on pouvait passer un troisième paramètre.
Sans doute vais-je devoir reconstruire mon tableau en entier, en y ajouter le paramètre à passer pour chacune des valeur !
Là encore, je ne suis pas sûr que cela résolve mon problème.
Je continue à chercher.
Fabien
Du coup, j'essaie de mettre en place qui est dit dans le tuto jour 6 du mvc.
Lorsqu'on créé un nouveau formulaire, si aucun id n'est passé, on crée la fiche par défaut avec online = -1 et tous les champs à null
Ensuite, je suppose qu'il n'y aura plus qu'à exécuter la requête comme d'hab et ca devrait fonctionner.
Je te dis ça si j'ai assez de courage pour tout faire ce soir.
Fabien
ce que je propose encore, quand tu fusionnes les select avec les valeurs, tu prends la requête SQL et l'exécuter, après tu prend sa valeur et tu fusionnes après les valeurs:
if (!isset($insertGlobal$gindex]'select'])) {
$insertGlobal$gindex]'valeur-fusion'] = $insertGlobal$gindex]'quotes'];
} else {
$r = array();
foreach ($insertGlobal$gindex]'select'] as $key => $value) {
$pre = $this->db->prepare($value);
$pre->execute();
$s_result = $pre->fetchColumn(); // la première résultat = ID
if(!is_numeric( $s_result )){
$s_result = $this->db->quote($s_result);
}
$r$key] = $s_result;
}
$insertGlobal$gindex]'valeur-fusion'] = array_merge($insertGlobal$gindex]'quotes'], $r);
}
et n'oublies pas d'enlever les parenthèses de tes requêtes.
je pense que si tu sépares l’exécution des requêtes sql, et de garder le changement que je fait:
function admin_edit($id = null) {
$this->loadModel('Products');
$first = array(
'tables' => array(
'product' => 'p'
),
'fields' => array(
'p' => 'id,name,sku,shortcontent,content,online'
),
'conditions' => array(
'p.id' => isset($id) ? $id : '1'
)
);
$second = array(
'tables' => array(
'product' => 'p',
'product_seo' => 's',
'product_associated_category' => 'pac',
'product_associated_image' => 'pai',
'image' => 'i'
),
'fields' => array(
's' => 'id,title,metadesc,metakey,slug,product_id',
'pac' => 'id,category_id,product_id',
'pai' => 'id,product_id,image_id,online,default_image',
'i' => 'id,file,online,name'
),
'jointure' => array(
's.product_id' => 'p.id',
'pac.product_id' => 'p.id',
'pai.product_id' => 'p.id',
'i.id' => 'pai.image_id'
),
'conditions' => array(
'p.id' => isset($id) ? $id : '1'
)
);
if ($this->nomController->data) {
$this->Products->save($this->nomController->data, 'p_id', $first);
$this->Products->save($this->nomController->data, 'p_id', $second);
$id = $this->Products->id;
}
if ($id) {
$d'products'] = $this->Products->findFirst($tab);
$this->nomController->data = $d'products'];
$this->set($d);
}
}
Je trouve pas a quoi sert le deuxième argument de la fonction save(); mais bon tu peux te sauver la vie.
Salut
Enfin un début de quelque chose grâce à toi !
Je suis allé voir en base et maintenant je récupère bien un id.
Le problème, il me récupère l'id de l'enregistrement précédant.
Je n'ai pas encore étudié en profondeur le bout de code que tu m'as fourni, je l'ai testé direct.
Je vais essayer de comprendre ce que tu as proposé, et voir comment modifier cela pour que le dernier id enregistré soit le bon.
Merci pour ton aide
Ah oui, j'ai oublié ça.
je vais essayer de ma part :)
et pour la création d'un nouveau formulaire, Grafikart a combiné les deux actions sur un ( la création, et le changement du contenu ).
Tu pourras créer une nouvelle action (admin_create) par exemple.
Bonne chance.
Salut
Je vais étudier ce que tu proposes.
Tout d'abord, je vais essayer de faire fonctionner correctement ta première proposition.
Concernant le deuxième argument de ma fonction save, oui en effte, je pourrai le ré intégrer dans mon array global.
Pour ce qui est des deux requêtes en une, moi je trouve ça pas mal, mais je garde en tête ta proposition.
Si j'ai le temps dans la journée, je teste ce que tu m'as founi.
Je te tiens au courant.
Merci
Fabien
Salut
J'y suis enfin arrivé après deux semaines à chercher comment faire.
Je vais pouvoir continuer les tutos maintenant.
J'ai suivi ton idée qui consistait à couper mes requêtes en 2, et j'ai mixé ça avec le fait de créer une entrée en base par défaut avec online=-1
Du coup, avec un seul formulaire, je peux gérer l'update et l'insert multiples. (le delete suivra)
Pour rappel, une fiche produit fait à appel à plus d'une dizaine de tables différentes dans ma BDD.
Maintenant, quand je mets à jour une fiche produit, cela modifie toutes les entrées qui vont bien, dans les tables qu'il faut.
Voici comment j'ai procédé pour ceux que ça intéresse: (je ne mets que le contenu du contrôler, car le code insert et update sont maxi longs)
// 2. si je n'ai pas d'id je vais créer un contenu à la volée
if ($id === null) {
$produit = $this->Products->findFirst(array(
'conditions' => array('online' => -1)
));
if (!empty($produit)) {
$id = $produit->id;
debug('Nous sommes sur un contenu Ghost avec pour id : ' . $id);
} else {
$this->Products->save(array(
'conditions' => array('online' => -1)
));
$id = Products::$lastId;
$this->Products->save(array(
'tables' => 'product_seo',
'conditions' => array(
'product_id' => $id
)
));
$this->Products->save(array(
'tables' => 'product_associated_category',
'conditions' => array(
'product_id' => $id
)
));
// je mets un ghost dans la table image
$this->Products->save(array(
'tables' => 'image',
'conditions' => array('online' => -1)
));
// je n'oublie pas de récupérer le dernier id en base, qui en l'occurence sera celui du champ image
$idImg = Products::$lastId;
// je mets un ghost dans la table product_associated_image
$this->Products->save(array(
'tables' => 'product_associated_image',
'conditions' => array(
'product_id' => $id,
'image_id'=>$idImg
)
));
debug("La fiche produit existe déjà et a l'id : " . $id . "<br/> et l'id de la dernière image est : " . $idImg);
}
}
Juste, mon code n'est pas parfait et je ne maitrise pas toujours tout.
Je ne savais pas comment appeler une variable qui se trouve dans ma class Model, via mon contrôler ProductsController.
Du coup, j'ai faire de $lastId une variable statif.
Ainsi, après chaque insert en base, je récupère le dernier id inséré. Suffit de le stocker, et de le renvoyer à chaque étape de création des entrées dans la base.
Voila (je ne sais pas si c'est clair ce que je raconte, car là j'ai envie de dormir) :)
++
Fabien