IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Zend Framework PHP Discussion :

Zend_Db Génération de code


Sujet :

Zend Framework PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif Avatar de magnus2005
    Profil pro
    Ingenieur SI
    Inscrit en
    Avril 2005
    Messages
    454
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingenieur SI

    Informations forums :
    Inscription : Avril 2005
    Messages : 454
    Par défaut Zend_Db Génération de code
    Bonjour à tous,

    Existe il un générateur sérieux PHP de Model en PHP pour Zend_db soit à partir d'un schéma de base existant ou bien d'un XML ?

    Si non est ce une idée pertinente d'en écrire un ?

  2. #2
    Membre chevronné

    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2003
    Messages : 253
    Par défaut
    C'est une très bonne question, que je me pose moi même depuis quelques temps. Générer un Model et un Data Mapper est quelque chose de compliqué, qu'il est impossible d'automatiser à 100%.

    Pourtant, ça prends énormément de temps à créer initialement avec beaucoup d'éléments répétitifs...

    Je ne peux pas t'aider pour ce qui est de savoir si une solution correcte existe pour générer les modèles, je n'ai pas encore cherché, même si à ma connaissance les générateurs se bornent souvent à générer des objets fortement liés à une base de données (principalement des ActiveRecords), et on s'éloigne de ce que je recherche.

    Par contre, j'ai hier soir (les grands esprits se rencontrent ) créé un petit prototype de générateur de modèle qui utilise un Zend_Db_Table_Abstract et qui donne rapidement un résultat assez satisfaisant.

    Il manque encore (au moins) deux choses fondamentales :
    - Externaliser les algorithmes de normalisation des membres du modèle par rapport aux champs de la base. L'externaliser sous forme d'une Stratégie permettrait de plus facilement personnaliser les règles de nommage et de les adapter au cas par cas.
    - Externaliser la gestion du typage, car pour ma part un modèle doit être fortement typé et forcer un cast pour les types natifs (int, string, bool...) ou une définition de méthode typée pour les objets dans ses méthodes set*. Je pense qu'il faut l'externaliser car personnellement je fournis les champs de type date d'une base de données dans un objet Zend_Date pour les modèles, ce qui facilite l’interaction application / data layer, mais ça peut ne pas convenir tout le temps, et encore moins à tout le monde (surtout sur le plan des performances).

    A mon avis ce genre d'outils n'a d'utilité qu'en création pour gagner un peu de temps : elle implique après coup tellement de réécriture (relation entre modèles, cas où les modèles et les tables ne correspondent pas 1 à 1, nommage à adapter à cause d'une base mal nommée...) qu'une fois le modèle finalisé il ne peut plus "évoluer" grâce à cet outil si la table change, il faudra tout faire à la mano.

    Voici le code de la classe, je suis preneur de tout avis bien évidemment , mais si l'outil peut être utile (et si la roue n'a pas déjà été inventée ailleurs) ça vaut le coup d'approfondir le concept et d'étendre Zend_Tool pour l'exploiter en ligne de commande.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    class ModelGenerator extends Zend_CodeGenerator_Php_Class
    {
        /**
         * 
         * @var Zend_Db_Table_Abstract
         */
        protected $_dbTable;
     
        /**
         * 
         * @var string
         */
        protected $_appNamespace = 'Application';
     
        /**
         * 
         * @return Zend_Db_Table_Abstract
         */
        public function getDbTable ()
        {
            return $this->_dbTable;
        }
     
        /**
         * 
         * @param Zend_Db_Table_Abstract $dbTable
         * @return Zend_Db_Table_Abstract
         */
        public function setDbTable ($dbTable)
        {
            $this->_dbTable = $dbTable;
            return $this;
        }
     
        /**
         * 
         * @return string
         */
        public function getAppNamespace ()
        {
            return $this->_appNamespace;
        }
     
        /**
         * 
         * @param string $appNamespace
         * @return ModelGenerator
         */
        public function setAppNamespace ($appNamespace)
        {
            $this->_appNamespace = $appNamespace;
            return $this;
        }
     
        /**
         * 
         * @return string
         * @see Zend_CodeGenerator_Php_Class::generate()
         */
        public function generate()
        {
            $dbTable = $this->getDbTable();
            $appNamespace = $this->getAppNamespace();
     
            if (null !== $dbTable) {
                $tableInfos = $dbTable->info();
                $tableName = $tableInfos['name'];
                $className = $appNamespace . '_Model_' . $tableName;
                $this->setName($className);
     
                $this->setDocblock(array(
                    'shortDescription' => "$tableName Model",
                    'tags' => array(
                        array(
                        	'name' => 'category',
                            'description' => $appNamespace
                        ),
                        array(
                        	'name' => 'package',
                            'description' => 'Default'
                        ),
                        array(
                        	'name' => 'subpackage',
                            'description' => 'Model'
                        ),
                    )
                ));
     
                foreach ($tableInfos['metadata'] as $name => $infos) {
                    $this->addProperty($name, $infos['DATA_TYPE'], $className);
                }
            }
     
            return parent::generate();
        }
     
        public function addProperty($name, $type, $className)
        {
            $this->setProperty(array(
                'docBlock' => array(
                    'tags' => array(
                        array(
                            'name' => 'var',
                            'description' => $type
                        )
                    )
                ),
                'visibility' => 'protected',
                'name' => $name
            ));
     
            $this->setMethod(array(
                'docBlock' => array(
                    'tags' => array(
                        array(
                            'name' => 'return',
                            'description' => $type
                        )
                    )
                ),
                'body' => 'return $this->_' . $name . ';',
                'visibility' => 'public',
                'name' => 'get' . ucfirst($name)
            ));
     
            $this->setMethod(array(
                'docBlock' => array(
                    'tags' => array(
                        array(
                            'name' => 'param',
                            'description' => $type . ' $value'
                        ),
                        array(
                            'name' => 'return',
                            'description' => $className
                        )
                    )
                ),
                'parameters' => array(
                    array(
                    	'name' => 'value',
                        'type' => $type
                    )
                ),
                'body' => '$this->_' . $name . ' = $value;' . "\n" . 'return $this;',
                'visibility' => 'public',
                'name' => 'set' . ucfirst($name)
            ));
        }
    }

  3. #3
    Membre très actif Avatar de magnus2005
    Profil pro
    Ingenieur SI
    Inscrit en
    Avril 2005
    Messages
    454
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingenieur SI

    Informations forums :
    Inscription : Avril 2005
    Messages : 454
    Par défaut
    Merci beaucoup pour ta réponse,

    ça prends énormément de temps à créer initialement avec beaucoup d'éléments répétitifs...
    Je suis entièrement d'accord et ce fait et celui d'avoir utiliser Hibernate pendant des années qui m'ont amener à cette réflexion. Comme c'est un processus qui est dans tous les ORM java que j'ai utilisé je suis très étonné de ne pas avoir trouvé ceci dans Zend_Db.

    Mon souhait est d'avoir quelque chose qu'y se rapproche d'Hibernate dans la génération des objets proxy. Ce type d'outils permet :
    • de gagner beaucoup de temps
    • de fortement réduire les erreurs par rapport à une écriture manuelle
    • de générer sur le même norme tous ses objets du model


    Je pense qu'il faut l'externaliser car personnellement je fournis les champs de type date d'une base de données dans un objet Zend_Date pour les modèles, ce qui facilite l’interaction application / data layer, mais ça peut ne pas convenir tout le temps, et encore moins à tout le monde
    Pour Zend_Date je fais pareil. Le but est l’intégration dans Zend Framework il faut pas commencer par quelque chose trop ambitieux.

    qu'une fois le modèle finalisé il ne peut plus "évoluer" grâce à cet outil si la table change, il faudra tout faire à la mano.
    A mon avis pas complétement si les classes générés sont exploitées seulement en héritage sans jamais y insérer de code manuel ça réduirait ce problème. Je prend pour exemple d'Hibernate. Si la Bdd change il suffit de régénérer le code.
    Si par chance ce ne sont que ajout de colonnes ça passe comme une lettre à la poste.
    Si c'est autre chose ça fera toujours du temps de gagner.

    [hors sujet]:
    Pour l'application je trouve que c'est plus pratique de lancer sous Apache pour faire des rapport Web et debugger et pas en standalone.

  4. #4
    Membre chevronné

    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2003
    Messages : 253
    Par défaut
    Citation Envoyé par magnus2005 Voir le message
    Je suis entièrement d'accord et ce fait et celui d'avoir utiliser Hibernate pendant des années qui m'ont amener à cette réflexion. Comme c'est un processus qui est dans tous les ORM java que j'ai utilisé je suis très étonné de ne pas avoir trouvé ceci dans Zend_Db.
    A tout hasard, Doctrine ne répondrais pas à tes besoins ? http://www.doctrine-project.org/

    C'est une question très "naïve", je n'ai pour ma part pas encore eut le temps de m'y "plonger" pour voir si il permettait de faire ce que je cherche, mais de loin ça ne m'a pas paru être le cas.

    Par contre pour le coup, je ne pense pas que Zend_Db puisse être considéré comme un ORM : il fournit "simplement" une interface d'accès à une base de donnée via Zend_Db_Adapter et une implémentation d'un Table Data Gateway
    avec Zend_Db_Table, laissant le développeur libre de ses propres choix en terme de mapping.

    Citation Envoyé par magnus2005 Voir le message
    Pour Zend_Date je fais pareil. Le but est l’intégration dans Zend Framework il faut pas commencer par quelque chose trop ambitieux.
    En effet, par contre je pense qu'effectuer un casting sur les types natifs et typer fortement les autres (Zend_Date...) est un minimum pour l'intérêt de la solution, sans ça il faudrait modifier à la main tous les setters...

    Citation Envoyé par magnus2005 Voir le message
    A mon avis pas complétement si les classes générés sont exploitées seulement en héritage sans jamais y insérer de code manuel ça réduirait ce problème. Je prend pour exemple d'Hibernate. Si la Bdd change il suffit de régénérer le code.
    Si par chance ce ne sont que ajout de colonnes ça passe comme une lettre à la poste.
    Si c'est autre chose ça fera toujours du temps de gagner.
    Je ne suis pas sûr de te suivre sur ce terrain... Les relations base / modèles ne sont pas toujours du 1 / 1 : il se peut qu'une seule table génère 3 ou 4 modèles sans liens de parenté les uns avec les autres.

    Dans ce contexte, ça me paraît dangereux de re-générer les modèles une fois le premier travail de mapping terminé...

    Surcharger les modèles systématiquement me paraît aussi assez "dangereux" : explosion du nombre de classes, complexité accrue et... même de perte de temps, au final.

    Mais bon, je pense que c'est une question de sensibilité personnelle plus qu'autre chose, et ça ne change pas le besoin de base : générer les modèles...

    Citation Envoyé par magnus2005 Voir le message
    [hors sujet]:
    Pour l'application je trouve que c'est plus pratique de lancer sous Apache pour faire des rapport Web et debugger et pas en standalone.
    Même si j'aime bien le "support" CLI, je pense que l'interfaçage Zend_Tool est plus un objectif secondaire qu'une finalité : il ne faut pas empêcher de piloter la création de modèles directement.

    J'essaye de bricoler un prototype plus aboutis ce week-end car je vais rapidement avoir besoin d'une solution viable pour divers projets.

  5. #5
    Membre très actif Avatar de magnus2005
    Profil pro
    Ingenieur SI
    Inscrit en
    Avril 2005
    Messages
    454
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingenieur SI

    Informations forums :
    Inscription : Avril 2005
    Messages : 454
    Par défaut
    A tout hasard, Doctrine ne répondrais pas à tes besoins ?
    J'ai beaucoup hésité entre Doctrine et Zend_DB.

    Doctrine est lui un ORM et est plus proche d'hibernate et par conséquent c'est nettement plus proche de que je voudrais. Par contre je n'ai pas trouvé de fonction de retro création à partir d'un schéma existant. Etant donné que je n'ai jamais utilisé doctrine je ne me suis pas étendu fortement en recherche sur le sujet.
    Le souci avec Doctrine c'est que dans Zend Framework 1.X n'a pas d' "adapter" pour Doctrine du coup plein de classe de Zend Framework ne peuvent l'utiliser nativement.

    Je prend l'exemple de Zend_Paginator il prend en paramètre un Select de Zend_db et pas Doctrine. A priori dans ZF2 ce sera possible (au conditionnel).

  6. #6
    Membre chevronné

    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2003
    Messages
    253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2003
    Messages : 253
    Par défaut
    Citation Envoyé par magnus2005 Voir le message
    J'ai beaucoup hésité entre Doctrine et Zend_DB.

    Doctrine est lui un ORM et est plus proche d'hibernate et par conséquent c'est nettement plus proche de que je voudrais. Par contre je n'ai pas trouvé de fonction de retro création à partir d'un schéma existant.
    C'est mon constat aussi jusqu'ici.

    J'ai travaillé un peu sur le sujet, et j'ai désormais un résultat acceptable, bien entendu à éprouver sur des conventions de nommage différentes...

    A partir de la table suivante, issue d'un projet perso :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    CREATE  TABLE IF NOT EXISTS `ActivityItem` (
      `idActivityItem` INT NOT NULL AUTO_INCREMENT ,
      `titleActivityItem` VARCHAR(255) NOT NULL ,
      `descriptionActivityItem` VARCHAR(255) NULL ,
      `linkActivityItem` VARCHAR(255) NOT NULL ,
      `externalIdActivityItem` VARCHAR(255) NOT NULL ,
      `publicationDateActivityItem` DATETIME NOT NULL ,
      `addedDateActivityItem` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
      `idActivitySourceActivityItem` INT NOT NULL
    );
    Il me génère le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    /**
     * ActivityItem Model
     * 
     * @category Application
     * @package Default
     * @subpackage Model
     */
    class Application_Model_ActivityItem
    {
     
        /**
         * @var integer
         */
        protected $_id = null;
     
        /**
         * @var string
         */
        protected $_title = null;
     
        /**
         * @var string
         */
        protected $_description = null;
     
        /**
         * @var string
         */
        protected $_link = null;
     
        /**
         * @var string
         */
        protected $_externalId = null;
     
        /**
         * @var Zend_Date
         */
        protected $_publicationDate = null;
     
        /**
         * @var Zend_Date
         */
        protected $_addedDate = null;
     
        /**
         * @var integer
         */
        protected $_idActivitySource = null;
     
        /**
         * @return integer
         */
        public function getId()
        {
            return $this->_id;
        }
     
        /**
         * @param integer $value
         * @return Application_Model_ActivityItem
         */
        public function setId($value)
        {
            $this->_id = (integer) $value;
            return $this;
        }
     
        /**
         * @return string
         */
        public function getTitle()
        {
            return $this->_title;
        }
     
        /**
         * @param string $value
         * @return Application_Model_ActivityItem
         */
        public function setTitle($value)
        {
            $this->_title = (string) $value;
            return $this;
        }
     
        /**
         * @return string
         */
        public function getDescription()
        {
            return $this->_description;
        }
     
        /**
         * @param string $value
         * @return Application_Model_ActivityItem
         */
        public function setDescription($value)
        {
            $this->_description = (string) $value;
            return $this;
        }
     
        /**
         * @return string
         */
        public function getLink()
        {
            return $this->_link;
        }
     
        /**
         * @param string $value
         * @return Application_Model_ActivityItem
         */
        public function setLink($value)
        {
            $this->_link = (string) $value;
            return $this;
        }
     
        /**
         * @return string
         */
        public function getExternalId()
        {
            return $this->_externalId;
        }
     
        /**
         * @param string $value
         * @return Application_Model_ActivityItem
         */
        public function setExternalId($value)
        {
            $this->_externalId = (string) $value;
            return $this;
        }
     
        /**
         * @return Zend_Date
         */
        public function getPublicationDate()
        {
            return $this->_publicationDate;
        }
     
        /**
         * @param Zend_Date $value
         * @return Application_Model_ActivityItem
         */
        public function setPublicationDate(Zend_Date  $value)
        {
            $this->_publicationDate = $value;
            return $this;
        }
     
        /**
         * @return Zend_Date
         */
        public function getAddedDate()
        {
            return $this->_addedDate;
        }
     
        /**
         * @param Zend_Date $value
         * @return Application_Model_ActivityItem
         */
        public function setAddedDate(Zend_Date  $value)
        {
            $this->_addedDate = $value;
            return $this;
        }
     
        /**
         * @return integer
         */
        public function getIdActivitySource()
        {
            return $this->_idActivitySource;
        }
     
        /**
         * @param integer $value
         * @return Application_Model_ActivityItem
         */
        public function setIdActivitySource($value)
        {
            $this->_idActivitySource = (integer) $value;
            return $this;
        }
     
     
    }
    Comme le projet commence à prendre en envergure (8 classes maintenant) si ça t'intéresse je peux créer un dépôt Github, ça sera plus simple que de mettre des extraits de code source ici.

Discussions similaires

  1. Génération de code & bpm4struts
    Par k4eve dans le forum BPM
    Réponses: 3
    Dernier message: 08/03/2007, 15h12
  2. Modelisation UML / Génération de code C++ sous eclipse
    Par silverhawk.os dans le forum Eclipse C & C++
    Réponses: 5
    Dernier message: 03/01/2006, 00h15
  3. [UML] génération de code avec omondo.uml
    Par RENAULT dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 31/10/2003, 13h14
  4. [Lomboz] Génération de code pour EJB
    Par paikan dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 09/07/2003, 14h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo