Zend Framework et les modèles

On continue dans la série Zend Framework (je suis à fond dessus en ce moment, donc il y aura surement d'autres articles) avec les modèles de données. Beaucoup d'articles parle déjà de la mise en place de Zend_Db_Table, je passerais donc rapidement dessus. Ce billet sera plus focalisé sur la création d'un helper (pour action) pour faciliter l'accès aux modèles. Dans le fichier de bootstrap (ou dans un module si vous utilisez la classe App du billet précédent) commençons par initialiser la connexion.
require_once 'Zend/Db.php';
$db = Zend_Db::factory('pdo_mysql', array(
    'host' => 'localhost',
    'username' => 'root',
    'password' => '',
    'dbname' => 'db'
));
Il est évidemment conseiller de transférer les paramètres de connexion dans un fichier de configuration... Il nous faut à présent configurer Zend_Db_Table pour utiliser cette connexion
require_once 'Zend/Db/Table.php';
Zend_Db_Table::setDefaultAdapter($db);
On peut maintenant créer nos classes. Dans le dossier /application/models créez par exemple le fichier MaTable.php avec:
<?php
class MaTable extends Zend_Db_Table
{
}
Je vous laisse lire la doc très complète de ZF pour plus d'info. Créons à présent le helper. Le but de ce dernier est de faciliter l'accès aux modèles. Il permettra depuis le contrôleur de faire quelque chose comme:
$this->models->MaTable;
Pour créer ce helper, nous devons créer une classe héritant de Zend_Controller_Action_Helper_Abstract
<?php
require_once 'Zend/Controller/Action/Helper/Abstract.php';
class App_Helper_Models extends Zend_Controller_Action_Helper_Abstract
{
}
Le constructeur va être en charge de trouver le dossier où sont stockés les modèles.
<?php
require_once 'Zend/Controller/Action/Helper/Abstract.php';
class App_Helper_Models extends Zend_Controller_Action_Helper_Abstract
{
    protected $_modelDirectory = null;

    protected $_loadedModels = null;

    public function __construct()
    {
         $module  = $this->getRequest()->getModuleName();
         $dirs    = $this->getFrontController()->getControllerDirectory();
         if (empty($module) || !isset($dirs[$module])) {
             $module = $this->getFrontController()->getDispatcher()->getDefaultModule();
         }
         $baseDir = dirname($dirs[$module]) . DIRECTORY_SEPARATOR . 'models';

         if (!file_exists($baseDir) || !is_dir($baseDir)) {
             throw new Zend_Controller_Exception('Missing model directory ("' . $baseDir . '")');
         }

         $this->_modelDirectory = $baseDir;
         $this->_loadedModels = array();
    }
}
Ici, on récupère d'abord le module courant ainsi que les dossiers où sont stockés les contrôleurs. Remarquez qu'il faut gérer le cas où c'est le module par défaut. A partir de cela on détermine le chemin du dossier de stockage des modèles. Finalement, ont utilise la méthode magique __get() pour charger un modèle:
public function __get($name)
    {
         if (!array_key_exists($name, $this->_loadedModels)) {
            if (!class_exists($name)) {
                require_once 'Zend/Loader.php';
                Zend_Loader::loadClass($name, $this->_modelDirectory);
            }

            $this->_loadedModels[$name] = new $name();
        }

        return $this->_loadedModels[$name];
    }
}
Dans cette méthode, on vérifie d'abord que le modèle n'est pas déjà chargé. Si ce n'est pas le cas, on charge éventuellement la classe à l'aide de Zend_Loader puis on créer une instance. Finalement, il ne nous reste plus qu'a charger le helper dans le broker. Pour cela, la meilleure méthode consiste probablement à créer une classe App_Controller. Tous les contrôleurs devront hériter de celle-ci.
<?php
require_once 'Zend/Controller/Action.php';
abstract class App_Controller extends Zend_Controller_Action
{
    protected $models = null;

    public function init()
    {
        require_once 'App/Helper/Models.php';
        Zend_Controller_Action_HelperBroker::addHelper(new App_Helper_Models());

        $this->models = $this->_helper->getHelper('Models');
    }
}
Dans notre contrôleur:
<?php
require_once 'App/Controller.php';
class IndexController extends App_Controller
{
    public function indexAction()
    {
        $this->view->data = $this->models->MaTable->fetchAll();
    }
}
Vous pouvez aussi améliorer la classe pour ajouter le support de dossier de modèles multiples par exemple... Voili voilou

comments powered by Disqus

11/02/2008