Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 22-09-2013 18:31:30

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

utilisation de findParentRow

Bonjour,

je suis entrain d'apprendre zend 1.12 via le learning du site (http://www.framework.zend.com/manual...ate-model.html)
Maintenant j'aimerai faire une mini app avec une relation ONE TO MANY.
J'ai donc créé 2 tables
auteur (id,name)
book (id,title,auteur_id) qui contient une foreign key

Au moment où je veux récupérer l'auteur lié au livre, je me retrouve avec une erreur:
Fatal error: Call to a member function getAdapter() on a non-object in /Library/WebServer/Documents/ZendFramework-1.12.3/library/Zend/Db/Table/Row/Abstract.php on line 936

Voici mes 2 modèles ainsi que le happer et dbtable

Code:

[lang=php]
<?php
 
    class Application_Model_BookMapper
    {
        protected $_dbTable;
 
        public function setDbTable($dbTable)
        {
            if (is_string($dbTable)) {
                $dbTable = new $dbTable();
            }
            if (!$dbTable instanceof Zend_Db_Table_Abstract) {
                throw new Exception('Invalid table data gateway provided');
            }
            $this->_dbTable = $dbTable;
            return $this;
        }
 
        public function getDbTable()
        {
            if (null === $this->_dbTable) {
                $this->setDbTable('Application_Model_DbTable_Book');
            }
            return $this->_dbTable;
        }
 
        public function find($id, Application_Model_Book $book)
        {
            $result = $this->getDbTable()->find($id);
            if (0 == count($result)) {
                return;
            }
            $row = $result->current();
            $book->setId($row->id)
                      ->setTitle($row->title)
                      ->setAuteur($row->auteur_id);
        }
 
        public function fetchAll()
        {
            $resultSet = $this->getDbTable()->fetchAll();
            $entries   = array();
            foreach ($resultSet as $row) {
                $entry = new Application_Model_book();
                $entry->setId($row->id)
                      ->setTitle($row->title)
                      ->setAuteur($row->auteur_id);
                $entries[] = $entry;
            }
            return $entries;
        }
 
        public function findAuteur($id, Application_Model_Book $book)
        {
            $result = $this->getDbTable()->find($id);
            if (0 == count($result)) {
                return;
            }
            $row = $result->current();
 
            //hydratation de l'objet book
            $book->setId($row->id)
            ->setTitle($row->title);
 
            //Utilisation d'une methode pour récupérer l'auteur u livre
            $rowAuteur=$row->findParentRow('Auteur');      
            $auteur= new Application_Model_Auteur();
            //hydratation de l'objet Auteur
            $auteur->setId($rowAuteur->id)
            ->setName($rowAuteur->name);
 
            //Attacher l'auteur à l'article
            $book->setAuteur($auteur);
            return $book;
        }
 
    }

Code:

[lang=php]
    <?php
 
    class Application_Model_AuteurMapper
    {
        protected $_dbTable;
 
        public function setDbTable($dbTable)
        {
            if (is_string($dbTable)) {
                $dbTable = new $dbTable();
            }
            if (!$dbTable instanceof Zend_Db_Table_Abstract) {
                throw new Exception('Invalid table data gateway provided');
            }
            $this->_dbTable = $dbTable;
            return $this;
        }
 
        public function getDbTable()
        {
            if (null === $this->_dbTable) {
                $this->setDbTable('Application_Model_DbTable_Auteur');
            }
            return $this->_dbTable;
        }
 
        public function find($id, Application_Model_Auteur $auteur)
        {
            $result = $this->getDbTable()->find($id);
            if (0 == count($result)) {
                return;
            }
            $row = $result->current();
            $auteur->setId($row->id)
                      ->setName($row->name);
        }
 
        public function fetchAll()
        {
            $resultSet = $this->getDbTable()->fetchAll();
            $entries   = array();
            foreach ($resultSet as $row) {
                $entry = new Application_Model_Auteur();
                $entry->setId($row->id)
                      ->setName($row->name);
                $entries[] = $entry;
            }
            return $entries;
        }
 
    }

Code:

[lang=php]
    <?php
 
    class Application_Model_DbTable_Book extends Zend_Db_Table_Abstract
    {
 
        protected $_name = 'book';
        protected $_referenceMap    = array(
            'Auteur' => array(
                'columns'           => 'auteur_id',
                'refTableClass'     => 'Application_Model_DbTable_Auteur',
                'refColumns'        => 'id'
            )
        );
 
    }

Code:

[lang=php]
    <?php
 
    class Application_Model_DbTable_Auteur extends Zend_Db_Table_Abstract
    {
 
        protected $_name = 'auteur';
        protected $_dependentTables = array('Application_Model_DbTable_Book');
 
    }

Code:

[lang=php]
    <?php
 
    class Application_Model_Book extends Zend_Db_Table_Row_Abstract
    {
        protected $_id;
        protected $_title;
        protected $_auteur;
 
        public function __construct(array $options = null)
        {
            if (is_array($options)) {
                $this->setOptions($options);
            }
        }
 
        public function __set($title, $value)
        {
            $method = 'set' . $title;
            if (('mapper' == $title) || !method_exists($this, $method)) {
                throw new Exception('Invalid guestbook property');
            }
            $this->$method($value);
        }
 
        public function __get($title)
        {
            $method = 'get' . $title;
            if (('mapper' == $title) || !method_exists($this, $method)) {
                throw new Exception('Invalid guestbook property');
            }
            return $this->$method();
        }
 
        public function setOptions(array $options)
        {
            $methods = get_class_methods($this);
            foreach ($options as $key => $value) {
                $method = 'set' . ucfirst($key);
                if (in_array($method, $methods)) {
                    $this->$method($value);
                }
            }
            return $this;
        }
 
        public function settitle($title)
        {
            $this->_title = (string) $title;
            return $this;
        }
 
        public function gettitle()
        {
            return $this->_title;
        }
 
        public function setId($id)
        {
            $this->_id = (int) $id;
            return $this;
        }
 
        public function getId()
        {
            return $this->_id;
        }
 
        public function setAuteur($auteur)
        {
            $this->_auteur = (string) $auteur;
            return $this;
        }
 
        public function getAuteur()
        {
            //if (!$this->_auteur) {
                //$this->_auteur = $this->findParentRow('Application_Model_DbTable_Book');
            //}
            return $this->_auteur;
        }
    }

Code:

[lang=php]
    <?php
 
    class Application_Model_Auteur extends Zend_Db_Table_Row_Abstract
    {
        protected $_id;
        protected $_name;
 
        public function __construct(array $options = null)
        {
            if (is_array($options)) {
                $this->setOptions($options);
            }
        }
 
        public function __set($name, $value)
        {
            $method = 'set' . $name;
            if (('mapper' == $name) || !method_exists($this, $method)) {
                throw new Exception('Invalid guestbook property');
            }
            $this->$method($value);
        }
 
        public function __get($name)
        {
            $method = 'get' . $name;
            if (('mapper' == $name) || !method_exists($this, $method)) {
                throw new Exception('Invalid guestbook property');
            }
            return $this->$method();
        }
 
        public function setOptions(array $options)
        {
            $methods = get_class_methods($this);
            foreach ($options as $key => $value) {
                $method = 'set' . ucfirst($key);
                if (in_array($method, $methods)) {
                    $this->$method($value);
                }
            }
            return $this;
        }
 
        public function setName($name)
        {
            $this->_name = (string) $name;
            return $this;
        }
 
        public function getName()
        {
            return $this->_name;
        }
 
        public function setId($id)
        {
            $this->_id = (int) $id;
            return $this;
        }
 
        public function getId()
        {
            return $this->_id;
        }
 
        public function getBooks(){
 
        }
    }

Ci joint le controller où je tente de récupérer l'auteur lié:

Code:

[lang=php]
public function indexAction()
    {
        $book = new Application_Model_BookMapper();
        //$name = $t->findParentRow('Application_Model_DbTable_Book');
        $this->view->entries = $book->fetchAll();//findAuteur(1,new Application_Model_Book());
        foreach ($this->view->entries as $b){
            echo gettype($b)."&&class=".get_class($b);
                if ($b instanceof Zend_Db_Table_Row_Abstract) {
                echo 'okkk';
            }
            $name = $b->findParentRow('Application_Model_DbTable_Book');//findDependentRowset
        }
    }

En lisant la doc je m'apperçois que je dois avoir un type: Zend_Db_Table_Row_Abstract (donc j'hérite mes modèles de cette classe)
je reçois ceci en retour: type==object&&class=Application_Model_Book
De plus il rentre bien dans le IF

:-s merci de votre aide parce que ça fait 2 jours que je bloque sur un problème qui à première vue semble facile.

Dernière modification par bender86 (22-09-2013 21:26:28)

Hors ligne

 

#2 23-09-2013 09:44:08

tdutrion
Administrateur
Lieu: Dijon, Paris, Edinburgh
Date d'inscription: 23-12-2009
Messages: 614
Site web

Re: utilisation de findParentRow

Bonjour,

Merci d'utiliser la balise [ code ] lors de l'affichage d'un code, ça rends le message beaucoup plus lisible...

Je ne comprends pas le problème en fait, j'ai du louper un épisode... Qu'est-ce qui ne va pas là ? On est dans un objet et on veut l'objet associé. Le fait de récupérer un Application_Model_Book, c'est pas ce qu'on veut ?

J'avoue ne pas comprendre le but de la manip en lisant le controlleur, et encore pire en lisant les lignes commentées...

Sinon, un Application_Model_Book est en effet un Zend_Db_Table_Row_Abstract du fait de l'héritage, c'est juste un type légèrement plus spécifique, mais instanceof ou is_a répondront true.


J'avais complètement loupé les lignes suivantes :

Au moment où je veux récupérer l'auteur lié au livre, je me retrouve avec une erreur:
Fatal error: Call to a member function getAdapter() on a non-object in /Library/WebServer/Documents/ZendFramework-1.12.3/library/Zend/Db/Table/Row/Abstract.php on line 936

Pourrait-on avoir la trace complète ?
A quel moment cette exception est lancée ? (probablement lors du chargement d'une ligne associée)
D'où les modèles tirent-ils leur adaptateur de db ? De la config contenue dans application.ini ?

Hors ligne

 

#3 23-09-2013 11:09:31

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

Merci de passer sur ce problème.
où puis-je voir la trace complète parce que dans les log je n'ai rien :-s

En fait si je fais ceci dans la classe BookMapper, il me retrouve bien l'auteur associé.

Code:

public function fetchAll()
    {
        $resultSet = $this->getDbTable()->fetchAll();
        $entries   = array();
        foreach ($resultSet as $row) {
            $entry = new Application_Model_book();
            $auteur = $row->findParentRow('Application_Model_DbTable_Auteur');
            $entry->setId($row->id)
                  ->setTitle($row->title)
                  ->setAuteur($auteur);
            $entries[] = $entry;
        }
        return $entries;
    }

LE soucis est si ej ne veux pas le récupérer là mais par exemple à la méthode getAuteur() de l'objet Book

Code:

$auteur = $this->findParentRow('Application_Model_DbTable_Auteur');

alors là je me retrouve avec cette erreur:
Fatal error: Call to a member function getAdapter() on a non-object in /Library/WebServer/Documents/ZendFramework-1.12.3/library/Zend/Db/Table/Row/Abstract.php on line 936

J'ai 2 questions plus de logique que de programmation.
-Dans ma classe Auteur, dois-je mettre une instance books avec accesseur où je pourrai y définir les livres lié à cet auteur avec : findDependentRowset

-Dans ma classe Book, dans le setAuteur, devrais-je mettre juste l'id désignant l'auteur ou alors l'objet auteur?

MErci de votre aide

Hors ligne

 

#4 23-09-2013 11:10:36

us2rn4m2
Membre
Date d'inscription: 07-05-2011
Messages: 104

Re: utilisation de findParentRow

Bonjour,

l'erreur est declenchée par la ligne 936 de Zend_Db_Table_Abstract::findParentRow()
$db = $this->_getTable()->getAdapter();

donc $this->_getTable() n'est pas un objet !

Hors ligne

 

#5 23-09-2013 12:12:05

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

Merci mais malheureusement ça m'aide pas beaucoup.

En fait ma méthode fetchAll() retourne une liste d'objet Book

Code:

public function fetchAll()
    {
        $resultSet = $this->getDbTable()->fetchAll();
        $entries   = array();
        foreach ($resultSet as $row) {
            $entry = new Application_Model_book();
            //$auteur = $row->findParentRow('Application_Model_DbTable_Auteur');
            $entry->setId($row->id)
                  ->setTitle($row->title)
                  ->setAuteur($row->auteur_id);
            $entries[] = $entry;
        }
        return $entries;
    }

Je ne vais pas récupérer automatiquement l'auteur associé, je suppose que ça peut vite devenir lourd. Donc je voulais le fire dans le controlleur si besoin en est.

Code:

$this->view->entries = $book->fetchAll();
        foreach ($this->view->entries as $b){
            $name = $b->findParentRow('Application_Model_DbTable_Auteur');
                //c'est avec cette ligne que j'ai un problème
        }

J'espère que je suis assez clair :-s

Hors ligne

 

#6 23-09-2013 12:20:13

tdutrion
Administrateur
Lieu: Dijon, Paris, Edinburgh
Date d'inscription: 23-12-2009
Messages: 614
Site web

Re: utilisation de findParentRow

Pour moi tu mets les choses au bon endroit. Par contre essaye d'installer xdebug par exemple, histoire d'avoir la stack trace (d'ailleurs normalement ZF te donne la stack trace avec les bons paramètres de dev... Comment gères-tu les erreurs ? (application.ini, error controller et error view).

Je ne comprends pas ton fetchAll()... Normalement une méthode fetchAll existe déjà dans les Zend_Db_Table, et il te donneras en retour un Zend_Db_Table_Rowset qui se parcours comme un tableau. Tu économiseras beaucoup en l'utilisant directement.

Sinon, la stack trace nous donnerait vraiment plus d'informations. Essaye aussi de voir si tu as pas une meilleur trace dans les logs...

Hors ligne

 

#7 23-09-2013 13:06:37

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

C'est avec le tuto de zend qu'ils te font récrire une méthode find, fetchAll dans l'objet mapper.
Pour ainsi récupérer directement des objets au lieu de rows avec les méthodes de Zend_Db_Table

Du moins si j'ai bien compris. :-P

J'utilise application.ini mais comment et où je vois la trace complète?
J'ai l'habitude d'utiliser le framework Yii et il est beaucoup plus facile à prendre en main que zend je trouve.

Concernant cette réflexion, quelle est selon toi la meilleure façon de faire?
-Dans ma classe Auteur, dois-je mettre une instance books avec accesseur où je pourrai y définir les livres lié à cet auteur avec : findDependentRowset
Ou alors définir une méthode getBooks et pouvoir récupérer tous les livres liés mais on revient au problème avec cette fichue erreur

-Dans ma classe Book, dans le setAuteur, devrais-je mettre juste l'id désignant l'auteur ou alors l'objet auteur?

Hors ligne

 

#8 23-09-2013 13:13:48

us2rn4m2
Membre
Date d'inscription: 07-05-2011
Messages: 104

Re: utilisation de findParentRow

Voici ce que je comprends:

le constructeur de la classe Application_Model_Book ecrase celui de Zend_Db_Table_Row_Abstract
du coup lorsque tu demande Application_Model_Book::findParentRow() ( ce qui équivaut à Zend_Db_Table_Row_Abstract::findParentRow()) celui ci te retourne une erreur parce que $this->_table que tu récuperes avec $this->_getTable() a la ligne 936 n'a pas été initialisé dans le constructeur

Dernière modification par us2rn4m2 (23-09-2013 13:16:57)

Hors ligne

 

#9 23-09-2013 13:20:51

tdutrion
Administrateur
Lieu: Dijon, Paris, Edinburgh
Date d'inscription: 23-12-2009
Messages: 614
Site web

Re: utilisation de findParentRow

J'avoue que j'utilise personnellement Zend_Db sans faire de mappers... De toutes façons tu es obligé de faire une methode fetchAll dans ton mapper, mais pour moi elle pourrait directement mapper sur la methode fetchAll de ton objet table.

Pour sortir des objets "correct" avec ton table fetchAll, il faut utiliser la propriété _rowClass dans ton table :

Code:

[lang=php]
<?php
class Application_Model_DbTable_Administrateurs extends Zend_Db_Table_Abstract {    
        
        protected $_name = 'test';
        protected $_primary = 'id';
        protected $_rowClass = 'Application_Model_DbRow_Test';  
}

Sinon je suis d'accord avec la dernière analyse de us2rn4m2 concernant les instanciations. Lors de la définition d'une méthode __construct (notamment) dans une classe fille, il faut ajouter la ligne parent::__construct() en début de méthode pour initialiser en utilisant la méthode de la classe mère. Je crois par ailleur qu'il existe une méthode init() dans les classes zend_db pour ne pas surcharger le constructeur et avoir ce genre d'erreurs.

Ton application.ini peut contenir ce genre de paramètres pour ta dev:

Code:

phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

Hors ligne

 

#10 23-09-2013 13:25:42

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

Dans ma classe Mapper :

Code:

protected $_dbTable;
public function setDbTable($dbTable)
    {
        if (is_string($dbTable)) {
            $dbTable = new $dbTable();
        }
        if (!$dbTable instanceof Zend_Db_Table_Abstract) {
            throw new Exception('Invalid table data gateway provided');
        }
        $this->_dbTable = $dbTable;
        return $this;
    }
 
    public function getDbTable()
    {
        if (null === $this->_dbTable) {
            $this->setDbTable('Application_Model_DbTable_Book');
        }
        return $this->_dbTable;
    }

J'ai essaié de changé _dbTable par _table mais rien n'a changé :-(

Dernière modification par bender86 (23-09-2013 13:27:17)

Hors ligne

 

#11 23-09-2013 15:13:51

us2rn4m2
Membre
Date d'inscription: 07-05-2011
Messages: 104

Re: utilisation de findParentRow

Tu dis

bender86 a écrit:

En fait si je fais ceci dans la classe BookMapper, il me retrouve bien l'auteur associé.
...
LE soucis est si ej ne veux pas le récupérer là mais par exemple à la méthode getAuteur() de l'objet Book

dans ce cas dans ton indexAction remplace $book->fetchAll() par $book->getDbTable()->fetchAll()

oui, non ?

Hors ligne

 

#12 23-09-2013 16:01:40

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

Super réponse merci ça fonctionne comme ça

Code:

$book = new Application_Model_BookMapper();
        $result = $book->getDbTable()->fetchAll();
        $this->view->entries = array();
        foreach ($result as $b){
            $entry = new Application_Model_book();
            $entry->setId($b->id)
                  ->setTitle($b->title)
                  ->setAuteur($b->findParentRow('Application_Model_DbTable_Auteur'));
            $this->view->entries[] = $entry;
        }

Je voudrais faire un formulaire où tu ajoutes l'auteur et ajouter automatiquement les x livres associé. (avec un bouton + et X pour ajouter et supprimer des input text)

j'ai donc le form

Code:

<?php

class Application_Form_Auteur extends Zend_Form
{

    public function init()
    {
        // Set the method for the display form to POST
        $this->setMethod('post');
 
        // Add a name element
        $this->addElement('text', 'name', array(
            'label'      => 'Auteur:',
            'required'   => true,
            'filters'    => array('StringTrim')
        ));
        //add champ cachŽ avec l'id
        $this->addElement('hidden', 'id');
 
        $this->addElement('button', 'addBook', array(
            'label' => 'Ajouter livre',
        ));
        $this->addElement('button', 'removeBook', array(
            'label' => 'Supprime livre',
        ));
 
        // Add the submit button
        $this->addElement('submit', 'submit', array(
            'ignore'   => true,
            'label'    => 'Ajouter',
        ));
 
        // And finally add some CSRF protection
        $this->addElement('hash', 'csrf', array(
            'ignore' => true,
        ));
        //echo '<pre>';print_r($this);echo '</pre>';
    }


}

et dans le contrôlleur j'ajoute dynamiquement les input

Code:

$books = $bm->getBookByAuteur($id);
            foreach($books as $book){
                $form->addElement('text', 'test', array(
                    'label'      => 'test:',
                    'required'   => true,
                    'filters'    => array('StringTrim'),
                            'value'         => $book->title
                ));
            }

Le soucis est qu'il me les ajoute à la fin du form et pas où je voudrais :-s (par exemple dans une div spécifique)
merci

Hors ligne

 

#13 23-09-2013 16:49:48

us2rn4m2
Membre
Date d'inscription: 07-05-2011
Messages: 104

Re: utilisation de findParentRow

Ca marche ok cool !

Pour la suite j'te renvoie vers la doc du coté de Zend Form diplayGroup http://framework.zend.com/manual/1.12/f … playgroups

plus un tuto
http://zendgeek.blogspot.fr/2009/07/zen … ators.html

C'est en anglais..

Voir aussi setOrder(), la doc dit;
Les éléments sont bouclés dans l'ordre dans lequel ils sont ajoutés, ou, si votre élément possède un attribut "order", celui-ci sera alors utilisé pour gérer sa place dans la pile des éléments : $element->setOrder(10);

Dernière modification par us2rn4m2 (24-09-2013 04:55:34)

Hors ligne

 

#14 23-09-2013 17:18:32

bender86
Nouveau membre
Date d'inscription: 22-09-2013
Messages: 7

Re: utilisation de findParentRow

Merci de ton aide

On me reverra surement pour de nouveaux problèmes :-P

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