Nicolas le 26 juin 2009

Objectif

Après avoir présenté brièvement le composant Zend_Tool_Framework et avoir détaillé son installation et utilisation sous Ubuntu, intéressons nous de plus près au Zend_CodeGenerator.

Zend_CodeGenerator est un nouveau composant du Zend Framework qui permet de générer du code PHP en utilisant une interface orientée objet.

Les classes fournies permettent de générer ou mettre à jour du code et il est aisé d’étendre celles-ci afin de créer d’autres types de fichiers (HTML, Javascript, etc).

Afin d’illustrer le fonctionnement de ce composant nous allons écrire un générateur pour produire une partie du modèle de données, une classe avec ses propriétés, accesseurs, modificateurs ainsi que leurs documentations respectives.

Le modèle choisi est tiré du tutoriel Quickstart du Zend Framework et représente un message laissé sur un livre d’or possèdant des propriétés « id », « email » et « comment ».

Générer le code de la classe

Commençons par nous intéresser à l’utilisation des classes new Zend_CodeGenerator_Php_Class et Zend_CodeGenerator_Php_Docblock pour générer dynamiquement le code et la doc de notre classe Guestbook :

    // variables utilisées dans le script
    $table     = "guestbook";
    $fields    = array(
        "id"      => "int",
        "email"   => "string",
        "comment" => "string"
    );
    $className = ucfirst($table); 
 
    // initialisation de la classe PHP
    $class     = new Zend_CodeGenerator_Php_Class();
 
    // création de la documentation de la classe
    $docblock  = new Zend_CodeGenerator_Php_Docblock(array(
        'shortDescription' => "{$className} generated class",
        'longDescription'  => 'A class generated with Zend_CodeGenerator.',
        'tags'             => array(
            array(
                'name'        => 'version',
                'description' => '1',
            ),
            array(
                'name'        => 'license',
                'description' => 'GNU GPL',
            ),
            array(
                'name'        => 'author',
                'description' => 'Nicolas <libre-a-vous.fr>',
            ),
        ),
    ));
 
    // définir le nom de la classe et lui affecter la doc
    $class->setName($className)->setDocblock($docblock);
 
    // ajouter toutes les propriétés
    $properties = array();
    foreach ($fields as $fName => $fType) {
        // ajouter une propriété sous forme de tableau
        $properties[] = array(
            // son nom
            'name' => "_{$fName}",
            // sa portée
            'visibility'   => 'protected',
        );
    }
    // ajouter les propriétés à la classe
    $class->setProperties($properties);
 
    // ajouter fonctions getters et setters
    $methods = array();
    foreach ($fields as $fName => $fType) {
        $fNameUpper = ucfirst($fName); // le nom avec majuscule
        // créer la fonction accesseur sous forme de tableau
        $getter = array(
            // son nom
            'name'       => "get{$fNameUpper}",
            // ses paramètres, ici aucun
            'parameters' => array(),
            // son corps
            'body'       => 'return $this->_'.$fName.';',
            // sa documentation
            'docblock'   => new Zend_CodeGenerator_Php_Docblock(array(
	            'shortDescription' => "Get the {$fName} property",
	            'tags'             => array(
	                new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
		               'datatype'  => "{$fType}",
		            )),
	            ),
            )),
	    );
        $methods []= $getter;
        // créer la fonction modificateur
        $setter = array(
            'name'       => "set{$fNameUpper}",
            'parameters' => array(
                array('name' => "{$fName}"),
            ),
            'body'       => '$this->_'.$fName.' = '.$fName.';' . "\n" .
                'return $this;',
            'docblock'   => new Zend_CodeGenerator_Php_Docblock(array(
	            'shortDescription' => "Set the {$fName} property",
	            'tags'             => array(
	                new Zend_CodeGenerator_Php_Docblock_Tag_Param(array(
	                    'datatype'  => "{$fType}"
	                )),
	                new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
	                    'datatype'  => "{$fType}",
	                )),
	            ),
            )),
        );
        $methods []= $setter;
    }
    // ajouter les méthodes à la classe
    $class->setMethods($methods);
 
    // afficher le contenu généré de la classe
    echo $class->generate();

Code généré

Voici une partie du code généré par le script précédent :

<?php
/**
 * Guestbook generated class
 * 
 * A class generated with Zend_CodeGenerator.
 * 
 * @version 1
 * @license GNU GPL
 * @author Nicolas <libre-a-vous.fr>
 */
class Guestbook
{
 
    protected $_id = null;
 
    protected $_email = null;
 
    protected $_comment = null;
 
    /**
     * Get the id property
     * 
     * @return int
     */
    public function getId()
    {
        return $this->_id;
    }
 
    /**
     * Set the id property
     * 
     * @param int  
     * @return int
     */
    public function setId($id)
    {
        $this->_id = id;
        return $this;
    }
 
    // ... idem pour les autres propriétés ...

Ecrire le code dans un fichier

Maintenant que le code de notre classe est généré, utilisons la classe Zend_CodeGenerator_Php_File pour écrire ce résultat dans un fichier :

    // générer le fichier contenant la classe
    $file = new Zend_CodeGenerator_Php_File(array(
        // passer la classe précédente en paramètre
        'classes'  => array($class),
        // ajouter la documentation
        'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
            'shortDescription' => "This file contains {$className} class",
            'tags'             => array(
                array(
                    'name'        => 'license',
                    'description' => 'GNU GPL',
                ),
            ),
        ))
    ));
 
    // générer le code
    $code = $file->generate();
    // écrire le résultat dans le fichier data/Guestbook.php
    file_put_contents("../data/{$className}.php", $code);

Conclusion

Cette première approche du composant Zend_CodeGenerator est terminée et bien que l’illustration proposée reste basique il est possible de compléter le script afin d’obtenir un modèle complet comprenant objet métier, mapping et data gateway.

On notera également la possibilité de travailler par introspection pour ajouter du contenu à des classes existantes.

Amha, ce composant apporte beaucoup au framework et permet de créer rapidement de petits outils maintenables permettant de s’économiser des tâches fastidieuses et répétitives.

Ressources complémentaires

Mots-clefs: ,

Laisser une réponse

Vous pouvez utiliser ces mots-clés: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">