Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 06-12-2007 18:36:52

SweedyMick
Nouveau membre
Date d'inscription: 06-12-2007
Messages: 9

[résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

Bonjour,

Voici un petit problème que j'ai avec les modules de Zend_Db. Cela me semble être un bug, mais je préfère demander votre confirmation.

J'ai un objet de mapping avec une table de base de données (c'est-à-dire un objet étendant Zend_Db_Table_Abstract) pour lequel je fais une insertion et je souhaite récupérer le lastInsertId de cette insertion.

Or, le lastInsertId retourné vaut toujours 0 (malgré la clé primaire bien définie, ainsi que tous les autres paramètres).

La table (MySQL, MyISAM) définit bien sûr une clé primaire, qui est incrémentée à chaque insertion.
En gros, voici l'opération :

Code:

// users est une classe étendant Zend_Db_Table_Abstract
$users = new users();

 // Insertion d'un nouvel utilisateur dans la table users
$lastUserId = $users->insert(array('name' => 'Jean'));

// $lastUserId vaut 0, ce qui ne devrait pas être le cas

Après quelques recherches, voici la cause de ce retour valant 0 :
- la fonction insert de Zend_Db_Table_Abstract fait appel à la fonction insert de Zend_Db_Adapter_Abstract (sachant que la classe Mysqli ne la redéfinit pas)
- la fonction insert de Zend_Db_Adapter_Abstract exécute la requête avec un $this->query après avoir généré la requête
- puis cette même fonction insert exécute $result = $stmt->rowCount() , rowCount étant défini dans Zend_Db_Statement_Mysqli

C'est cette dernière opération (celle du rowCount) qui occulte la valeur du lastInsertId. Si je supprime l'appel à rowCount dans Zend_Db_Adapter_Abstract, je peux récupérer le dernier Id inséré.

M'y prends-je mal, ou est-ce un cas qui n'avait pas été prévu pour l'adapteur Mysqli ?

Bien sûr je peux étendre les classes de Zend et résoudre le problème, mais j'aurais aimé avoir vos avis sur ce problème.

Merci !

Dernière modification par SweedyMick (07-12-2007 11:10:30)

Hors ligne

 

#2 06-12-2007 20:10:36

2mx
Membre
Lieu: Grenoble
Date d'inscription: 06-08-2007
Messages: 125

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

Je viens de faire un test avec msqli et pdo_mysql et je ne reproduis pas ce bug.

J'utilise la version SVN du framework.

Hors ligne

 

#3 06-12-2007 21:48:39

Julien
Membre
Date d'inscription: 16-03-2007
Messages: 501

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

Je viens de tester ceci :

Code:

<?php
$db = new Zend_Db_Adapter_Mysqli(array(
    'host'     => '127.0.0.1',
    'username' => 'julien',
    'password' => 'password',
    'dbname'   => 'test'));
    
$db->getConnection(); // pour le fun

class test extends Zend_Db_Table_Abstract { }

$t = new test($db);
echo $t->insert(array('champ'=>'valeur'));

Tout fonctionne très bien, sur une table 'test' très basique, avec clé primaire autoincrémentée... ?

Version SVN aussi, je n'ai pas creusé plus, mais il existe actuellement quelques bugs pour cette classe (ZF-2175 par exemple)

Hors ligne

 

#4 07-12-2007 07:32:33

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

de plus

Code:

// users est une classe étendant Zend_Db_Table_Abstract
$users = new users();
$user = $users->createRow(array('usr_name' => 'Jean'));
$user->save();
//$user est l'enregistrement ajouté à la base mais il est au passage 
//complété de toutes les valeur par défaut qui n'ont pas été renseigné lors de l'enregistrement.
$lastUserId = $user->usr_id;

la méthode suivante est alors appelée de façon automatique et donc l'objet user est à jour par rapport à ce qui est dans la base

Code:

    protected function _refresh()
    {
        $where = $this->_getWhereQuery();
        $row = $this->_getTable()->fetchRow($where);
        if (null === $row) {
            require_once 'Zend/Db/Table/Row/Exception.php';
            throw new Zend_Db_Table_Row_Exception
                               ('Cannot refresh row as parent is missing');
        }

        $this->_data = $row->toArray();
        $this->_cleanData = $this->_data;
    }

pour faire vraiment de l'ORM avec ZF ne suivez pas les exemples de la doc avec une classe table qui porte le nom de la table mais créez une classe User_Table et une classe User_Row et utilisez à fond les mécanismes d'ORM qui s'offre alors. manipulez des objet user instance de User_Table et non plus de simple tableau sans capacité.

ce n'est peut être pas toujours plus efficace question SQL mais c'est beaucoup plus cohérent coté PHP.
par exemple sur un insert ou un update cette approche fait deux requête (insert ou update et select) mais en contre partie si on ne change qu'un champs dans son objet lui seul est mis à jour en non tout l'enregistrement.

A+JYT

Dernière modification par sekaijin (07-12-2007 07:34:33)

Hors ligne

 

#5 07-12-2007 11:09:42

SweedyMick
Nouveau membre
Date d'inscription: 06-12-2007
Messages: 9

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

Merci à tous pour vos réponses qui m'ont bien été utiles.

J'utilise actuellement le ZF 1.0.2, mais de ce point de vue ça ne change rien, j'ai fais une comparaison de répertoires et de fichiers avec la version du SVN et il n'y a aucune modification sur les objets concernés.

Et le fait que ça marche chez vous m'a permis d'essayer de comprendre quelle pouvait être la différence entre votre cas et le mien.

Et finalement je l'ai trouvée : c'est que je fais un mysqli_set_charset sur l'objet _connection lors de sa création (via une extension de la classe Zend_Db_Adapter_Mysqli, mais je n'en avais pas précisé les détails par souci de simplicité). Et l'encodage était redéfini plusieurs fois d'affiliée, et bien que la fonction mysqli_set_charset retournait true à chaque fois, ça faisait que ça ne marchait pas. Désormais l'appel à mysqli_set_charset ne se fait qu'une seule fois et mon lastInsertId fonctionne !!

Oui sekaijin tu as très certainement raison. Je déteste utiliser aussi directement Zend_Db_Table. Surtout pour la représentation objet (je ne veux pas qu'une clé étrangère soit représentée par la valeur de l'identifiant de l'autre base, mais par l'objet de cette autre base).
De manière générale je trouve que ça n'offre pas vraiment de souplesse au niveau des objets et ça alourdit plutôt que de simplifier à mon goût.
Mais j'essaierai ta méthode en tout cas.

Merci de votre réactivité et de m'avoir aidé à trouver cette erreur

Hors ligne

 

#6 07-12-2007 12:06:05

SweedyMick
Nouveau membre
Date d'inscription: 06-12-2007
Messages: 9

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

sekaijin a écrit:

ce n'est peut être pas toujours plus efficace question SQL mais c'est beaucoup plus cohérent coté PHP.
par exemple sur un insert ou un update cette approche fait deux requête (insert ou update et select) mais en contre partie si on ne change qu'un champs dans son objet lui seul est mis à jour en non tout l'enregistrement.

Peux-tu donner quelques détails sur ce dernier point ? Je n'ai pas compris en quoi tu faisais 2 requêtes et comment tu fais pour n'updater que le donnés qui ont changées (si c'est sans maintenir un tableau des valeurs modifiées, que l'on pourrait mettre à jour avec la magic function __set).

Si tu as une URL d'un blog ou d'un wiki qui donne une bonne structure pour exploiter au maximum les méchanismes ORM (en utilisant le Zend Framework), je suis preneur.
Apparemment tout simplement ton blog que j'ai trouvé en faisant quelques recherches !

Dernière modification par SweedyMick (07-12-2007 12:11:29)

Hors ligne

 

#7 07-12-2007 13:33:54

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [résolu]Zend_Db_Table : lastInsertId renvoie 0 à cause d'un rowCount

SweedyMick a écrit:

Peux-tu donner quelques détails sur ce dernier point ? Je n'ai pas compris en quoi tu faisais 2 requêtes et comment tu fais pour n'updater que le donnés qui ont changées (si c'est sans maintenir un tableau des valeurs modifiées, que l'on pourrait mettre à jour avec la magic function __set).

Si tu as une URL d'un blog ou d'un wiki qui donne une bonne structure pour exploiter au maximum les méchanismes ORM (en utilisant le Zend Framework), je suis preneur.
Apparemment tout simplement ton blog que j'ai trouvé en faisant quelques recherches !

je n'utilise pas directement Zend_Db_Table_Abstract en donnant le nom de la table sur laquelle travailler
mais je lui fournis en plus une classe qu'elle doit utiliser pour lire les données.
cette classe dérive de Zend_Db_Table_Row
lorsque je veux inséré un élément au lieu de donner le tableau à la table pour faire un insert ou update
je demande à la table une instance de ma classe par
$userTable->createRow en lui donnant le tableau pour un insert
ou $userTable->find dans lequel je modifie les valeurs pour un update
ensuite sur cet objet je fais un simple $user->save();

Zend_Db sait seul décider s'il faut faire update ou insert et dans le cas de l'update ne mettre à jour que les valeurs modifiées.


en contre partie après le insert ou l'update Zend_Db fait un refrech automatique de mon objet $user
j'ai donc nécessairement deux requêt puisque après la première insert ou update zend_db en ajoute un select pour le refresh

je n'ai pas à maintenir de tableau pour géré les modifs car Zend_db_Table_Row le fait pour moi.

A+JYT

Dernière modification par sekaijin (07-12-2007 13:36:20)

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages