Consultez la FAQ sur le ZF avant de poster une question
Vous n'êtes pas identifié.
Pages: 1
Bonjour,
Je suis actuellement en train de réalisé mon premier projet avec le framework de zend et je suis bloqué sur le problème suivant:
<?php require_once ('Zend/Db/Table/Row/Abstract.php'); class Rem_Db_Row extends Zend_Db_Table_Row_Abstract { public function toStdClass() { return (object)$this->toArray(); } public function save($srcData = null) { if ($srcData) { $this->_cleanData = $srcData; } return parent::save(); } protected function _refresh(){ } } ?>
Si je ne surcharge pas _refresh, l'erreure suivante m'est renvoyée:
Cannot refresh row as parent is missing
Je ne sais pas trop d'où cela peut provenir.
Merci
Hors ligne
Hello,
Un trigger ou une séquence ou un champs auto-incrémenté ?
A+
Hors ligne
Un champs auto-incrémenté,
je joins par la même occasion la méthode _refresh()
/** * Constructs where statement for retrieving row(s). * * @param bool $useDirty * @return array */ protected function _getWhereQuery($useDirty = true) { $where = array(); $db = $this->_getTable()->getAdapter(); $primaryKey = $this->_getPrimaryKey($useDirty); $info = $this->_getTable()->info(); $metadata = $info[Zend_Db_Table_Abstract::METADATA]; // retrieve recently updated row using primary keys $where = array(); foreach ($primaryKey as $column => $value) { $tableName = $db->quoteIdentifier($info[Zend_Db_Table_Abstract::NAME]); $type = $metadata[$column]['DATA_TYPE']; $columnName = $db->quoteIdentifier($column, true); $where[] = $db->quoteInto("{$tableName}.{$columnName} = ?", $value, $type); } return $where; } /** * Refreshes properties from the database. * * @return void */ 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; $this->_modifiedFields = array(); }
Dernière modification par squall6969 (22-01-2009 16:04:35)
Hors ligne
Hello,
Je dirais donc que tu n'as pas déclaré :
protected $_sequence = true;
dans la définition de ta Zend_Db_Table associée.
A+
Hors ligne
mikaelkael a écrit:
Hello,
Je dirais donc que tu n'as pas déclaré :Code:
protected $_sequence = true;dans la définition de ta Zend_Db_Table associée.
A+
J'ai essayé de rajouter ce que tu m'as dis mais le problème persiste, d'autant plus que $_sequence = true par défault.
En fait j'ai l'impression qu'il n'arrive pas à retrouver la clé primaire de la table... et que du coups il ne retrouve pas le row inséré.
Ma clé primaire est pourtant bien déclarée et est un première position de colonne, donc $_identity n'a pas besoin d'être touché.
Voici mon modèle
<?php class Model_Client { private $_db; public function __construct() { $this->_db = Zend_Registry::get('dbAdapter'); } public function getClientList(){ $client = new Model_Client_Table; return $client->getList(); } public function getClientById($id){ $client = new Model_Client_Table; return $client->getById($id); } public function newClient($Client=null){ $client = new Model_Client_Table; return $client->newRow($Client); } public function saveClient($Client=null){ $client = new Model_Client_Table; return $client->save($Client); } public function deleteClientById($id){ $client = new Model_Client_Table; return $client->deleteById($id); } } ?>
Ma table/row associée
<?php require_once ('Rem/Db/Table.php'); class Model_Client_Table extends Rem_Db_Table{ protected $_name = 'client'; protected $_primary = 'cli_id'; protected $_rowClass = 'Model_Client_Row'; protected $_rowsetClass = 'Model_Client_Rowset'; } ?> <?php //require_once ('Rem/Db/Row.php'); class Model_Client_Row extends Rem_Db_Row{ } ?>
J'espère que avec cela vous pourrez m'aider plus facilement.
Je vous remercie !!!
Hors ligne
J'ai résolu mon problème de la manière suivante:
<?php require_once ('Zend/Db/Table/Row/Abstract.php'); class Rem_Db_Row extends Zend_Db_Table_Row_Abstract { public function toStdClass() { return (object)$this->toArray(); } public function save($srcData = null) { $this->_primary = array($srcData[0]);//J'ai du rajouter cette ligne, je pense initialiser cette propriété dans la classe fille Model_Client_Table_Row, à voir... if ($srcData) { $this->_cleanData = $srcData; } return parent::save(); } } ?>
Hors ligne
squall6969 a écrit:
Bonjour,
Je suis actuellement en train de réalisé mon premier projet avec le framework de zend et je suis bloqué sur le problème suivant:Code:
<?php require_once ('Zend/Db/Table/Row/Abstract.php'); class Rem_Db_Row extends Zend_Db_Table_Row_Abstract { public function toStdClass() { return (object)$this->toArray(); } public function save($srcData = null) { if ($srcData) { $this->_cleanData = $srcData; } return parent::save(); } protected function _refresh(){ } } ?>Si je ne surcharge pas _refresh, l'erreure suivante m'est renvoyée:
Code:
Cannot refresh row as parent is missingJe ne sais pas trop d'où cela peut provenir.
Merci
il ne faut pas modifier _cleanData
mais _data
Fait par Zend
le processus est le suivant lecture des données dans la base
Données placées dans _cleanData et _data
Puis par toi
Travail sur les données dans _data
puis lorsque tu sauve par Zend
comparaison des donnée de _clean_Data et _Data
mise à jour des données de _data qui ne sont pas identique à celle de _cleanData dans la base
donc si tu touche à _cleanData Zend ne saura plus ce qu'il faut faire et tu vas dans le mur
A+JYT
Hors ligne
Exact, ton problème c'est ça :
$this->_cleanData = $srcData;
Il y a une méthode setFromArray() qui permet de définir les valeurs d'une ligne dans l'objet. Toucher aux membres protégés, c'est très dangereux, surtout quand on ne maîtrise pas la totalité du code de Zend.
Normalement, Zend est assez bien fait pour que tu n'ai jamais à le faire.
Quand tu sauves ta ligne, Zend fait ça :
public function save()
{
/**
* If the _cleanData array is empty,
* this is an INSERT of a new row.
* Otherwise it is an UPDATE.
*/
if (empty($this->_cleanData)) {
return $this->_doInsert();
} else {
return $this->_doUpdate();
}
}
Donc en fait, tu fais un update, Zend tente ensuite de récupérer la ligne mais ne la trouve pas vu que la ligne n'existe pas. Et il renvoi cette erreur.
Hors ligne
keilnoth a écrit:
Il y a une méthode setFromArray() qui permet de définir les valeurs d'une ligne dans l'objet. Toucher aux membres protégés, c'est très dangereux, surtout quand on ne maîtrise pas la totalité du code de Zend.
Je n'arrives pas à faire fonctionner ce "é'&('" _doUpdate !!!!!
Je vous donnes ce que j'ai fais d'après vos conseils:
<?php require_once ('Zend/Db/Table/Row/Abstract.php'); class Rem_Db_Row extends Zend_Db_Table_Row_Abstract { public function toStdClass() { return (object)$this->toArray(); } public function save($srcData = null) { //print_r($srcData);exit(); if ($srcData) { $this->setFromArray($srcData); } return parent::save(); } } ?>
Mais cela me dit que sa créer un duplicata de ma clé primaire, il essaye de faire un insert au lieu d'un update.
Comment initialiser correectement le tout.
Merci.
PS: je me suis pas mal servi des source de lesauf, que je remercie au passage.
Seulement je n'ais pas voulu faire un copié collé tout bête et j'ai donc tout repris à la base
Hors ligne
d'abord un find depuis ta table
ainsi tu récupère un Zend_Db_Table_Row avec le _clean en état
ensuite le setFromArray et enfin le save
si tu ne veux pas devoir refaire le find lors de la mise à jour
lorsque la première fois tu récupère ton objet tu le mets en session (enfin ses données clean et data)
puis lorsque tu reviens tu recrée un row avec et tu fais le setFromArray puis le save
A+JYT
Hors ligne
J'ai un soucis:
La méthode setFromArray me récupère aussi les champs submit et effacer de mon formulaire, et donc cela lève une exception en me disant que le champs "submit n'existe pas dans ma bdd".
public function saveAction($perform = true) { $this->_linkContext(); $srcData = $this->model->{$this->_getItemById}($this->context->id); echo "<pre>"; print_r($this->context->formData);exit(); echo "</pre>"; // lecture du row dans le rowset $srcData = $srcData->current(); $srcData->setFromArray($this->context->formData); $id = $srcData->save(); if ($id) { $this->_messenger->addOk($this->_messages['saved']); $redirect = $this->_to('show-list'); } else { $this->_messenger->addError($this->_messages['unsaved']); $redirect = $this->_to('show-form'); } if ($perform) { $this->_redirect($redirect); } else { return $redirect; } }
Je galère vraiment, je sais pas pourquoi, il doit y avoir quelque chose que j'ai mal saisie...
Merci sekajin tu m'es d'une aide précieuse.
Hors ligne
Re,
Voila la méthode de travail adopté pour résoudre le problème, tout détruire pour reconstruire, ET SA MARCHE !!!
Voici saveAction:
public function saveAction($perform = true) { //récupération du contexte $this->_linkContext(); //stockage de la méthode d'enregistrement $saveMethod = $this->context->saveMethod; if ("edit" == $saveMethod){ //update //récupération de l'objet en cours d'edition $dataRowset = $this->model->{$this->_getItemById}($this->context->id); // lecture du row dans le rowset $dataRow = $dataRowset->current(); }else{ //insert $dataRow = $this->model->{$this->_newItem}(); } //selection des champs à mettre à jour $this->context->formData = array_intersect_key( $this->context->formData, $dataRow->toArray()); //mise à jour du row $dataRow->setFromArray($this->context->formData); //sauvegarde de la mise à jour $id = $dataRow->save(); //gestion des redirections en fonction de la réussite de l'enregistrement/mise à jour if ($id) { //succès $redirect = $this->_to('show-list'); } else { //échec $redirect = $this->_to('show-form'); } //validation if ($perform) { $this->_redirect($redirect); } else { return $redirect; } }
Mon problème venait du fait que lorsqu l'on sérialise un objet de type row, celui ci perd la connection de la base de donnée pour des raisons de sécurité.
J'ai donc contourné le problème en communiquant l'id, puis refais un find() comme sekajin me l'a conseillé.
Je comprends mieu pourquoi lesauf surchargeait sa méthode save()...
Mais on m'a conseillé de ne jamais agir directement sur les propriétées protégé de zend sans en avoir l'expérience, et je suis plutôt pour cette idéologie.
Je vais maintenant continuer à avancer et essayer d'obtenir les résultats que je souhaites.
Je vous tiens au courant.
Merci encore pour votre aide, super forum !
Hors ligne
Pour virer les champs qui n'existent pas dans ta table, dans ton modèle :
$fields = $this->info(Zend_Db_Table_Abstract::COLS);
/* getting only the related fields */
foreach ($data as $field => $value) {
if (!in_array($field, $fields)) {
unset($data[$field]);
}
}
Il me semble que tu te compliques énormément la vie. Chez moi, ce genre d'action se résume à :
$request = $this->getRequest() ;
$db_table = new Db_Table_Model() ;
$db_table->save($request->getParams()) ;
Bien entendu, c'est grossièrement résumé...
La différence entre un update et un insert c'est la présence de la clé primaire dans ton tableau de données. Si tu fais un update, la clé primaire se trouve dans la requête GET ou POST que tu as réalisé.
Hors ligne
keilnoth a écrit:
Il me semble que tu te compliques énormément la vie. Chez moi, ce genre d'action se résume à :
$request = $this->getRequest() ;
$db_table = new Db_Table_Model() ;
$db_table->save($request->getParams()) ;
j'avais au début un fonctionnement similaire à cela mais je rencontrais des soucis par ci par là.
En tant que novice dans le framework j'ai préféré décomposer dans un premier temps pour comprendre la logique de base.
Par la suite je fournirais mes sources afin que je sois exposer à toutes les critiques qui pourrons me faire progresser.
Merci pour cette astuce, j'ai moi préféré passer par un array_intersect_key(), mais je devrais peut être me fier à ta méthode qui est plus sûre.
keilnoth a écrit:
$fields = $this->info(Zend_Db_Table_Abstract::COLS);
/* getting only the related fields */
foreach ($data as $field => $value) {
if (!in_array($field, $fields)) {
unset($data[$field]);
}
}
Je vous tiens au jus, merci de votre aide !
Hors ligne
keilnoth a écrit:
Pour virer les champs qui n'existent pas dans ta table, dans ton modèle :
$fields = $this->info(Zend_Db_Table_Abstract::COLS);
/* getting only the related fields */
foreach ($data as $field => $value) {
if (!in_array($field, $fields)) {
unset($data[$field]);
}
}
Soit vous utilisez une ancienne version du ZF, soit vous avez pas vu le changement mais c'est corriger depuis ZF 1.7.0 (issue de référence : http://framework.zend.com/issues/browse/ZF-2243)
A+
Hors ligne
Possible, ça fait un bail que je l'utilise... Je crois que je l'avais trouvée dans un tutorial ou qqch comme ça.
Hors ligne
mikaelkael a écrit:
Soit vous utilisez une ancienne version du ZF, soit vous avez pas vu le changement mais c'est corriger depuis ZF 1.7.0 (issue de référence : http://framework.zend.com/issues/browse/ZF-2243)
A+
Effectivement, merci pour l'info !
Je vais mettre à jour mon framework et tester tout sa ^^
Hors ligne
Pages: 1