Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 20-01-2009 15:33:27

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

[resolu][1.7.0]Améliorations

Bonjour à tous!

Je viens de me mettre à ZF! Beaucoup de choses à assimiler.. Mais je commencer à comprendre les bases! Cependant, faces aux centaines de tutoriels et documentations présents sur le net, je suis un peu perdu!
J'aurais prochainement des applications web à développer, et j'aimerais utiliser ZF. Je m'y suis donc mis, et j'essaye de créer une "base" fiable, évolutive, et bien faite.
Au programme, ce que je souhaite :
- Un bon bootstrap
- Systeme d'authentification & ACL
- Systeme de modules
- Systeme de templating

J'aimerais vous montrer ce que j'ai déja fait, afin d'avoir vos conseils pour améliorations! (Ca marche, mais ca me semble un peu fouillis? améliorable?). En même temps, j'espère que ca pourras aider les débutants!

Mon arborescence :

Code:

application
---admin
------controllers
---------IndexController.php
------layout
---------admin.phtml
------views
---------script
------------index
---------------index.phtml
---bootstrap.php
---config.ini
---default
------controllers
---------AuthController.php
---------ErrorController.php
---------IndexController.php
---------PersonController.php
------forms
---------LoginForm.php
---------PersonForm.php
------layout
---------layout.phtml
------views
---------script
------------mesviews (je ne detaille pas, vous avez compris)
index.php
library
---Mycompany
------Acl.php
------Controller
---------Plugin
------------Acl.php
------Layout
---------Controller
------------Plugin
---------------Layout.php
---Zend
models
---Person.php
---PersonRow.php
public
---css,images

mon index.php

Code:

<?php

//TO DO : use absolute path, it's said to be better for cache stuff

set_include_path('.'
    . PATH_SEPARATOR . './library'
    . PATH_SEPARATOR . './library/Mycompany'
    . PATH_SEPARATOR . './application'
    . PATH_SEPARATOR . './models'
    . PATH_SEPARATOR . './application/default/forms'
    . PATH_SEPARATOR . get_include_path());
    
    
require_once 'Bootstrap.php';

$controllers_path = array(
                                'default' => './application/default/controllers',
                                'admin'   =>  './application/admin/controllers'
                          );

$layout_path = array('layoutPath'=>'./application/default/layouts');



Bootstrap::run($controllers_path, $layout_path);

mon bootstrap :

Code:

<?php

require_once 'Zend/Loader.php';

class Bootstrap
{

    public static $frontController = null;
    private static $registry = null;
    private static $auth = null, $acl = null;
   
    
    /*
     * On lance le bootsrap
     */
    public static function run($controllers_path, $layout_path)
    {
        self::setupEnvironment();
        self::prepare($controllers_path, $layout_path);
        try {
            $response = self::$frontController->dispatch();
            self::sendResponse($response);
        } catch(Exception $e) {
            //TO DO -> LOG SYSTEM
            exit($e->getMessage());
        }
    }
   
    /*
     * Configuration de l'environnement
     */
    public static function setupEnvironment()
    {
        error_reporting(E_ALL | E_STRICT);
        ini_set('display_errors', 1);
        date_default_timezone_set('Europe/Paris');
    }
   
    
    public static function prepare($controllers_path, $layout_path)
    {
        Zend_Loader::registerAutoload();
        self::setupRegistry();
        self::setupConfig();
        self::setupDatabase();
        self::setupFrontController($controllers_path);
        self::setupLayout($layout_path);
        self::setupView();
        self::setupActionStack();
        self::setupAcl();
        self::setupLogger(); 
    }
    
    
    
    public static function setupRegistry()
    {
        self::$registry = new Zend_Registry(array(), ArrayObject::ARRAY_AS_PROPS);
        Zend_Registry::setInstance(self::$registry);
    }
    
    /*
     * Charge le fichier de configuration. La config est placée dans le registre sous la clé 'config'
     * @param config_file_path chemin absolu ou relatif vers le fichier de configuration, par defaut : ./application/config.ini
     * @param section section a charger dans le fichier de configuration, par defaut : general
      */
    public static function setupConfig($config_file_path='./application/config.ini', $section='general')
    {
        $config = new Zend_Config_Ini($config_file_path, $section);
        self::$registry->set('config', $config);
    }
    
    public static function setupDatabase() 
    {
        $db = Zend_Db::factory(Zend_Registry::get('config')->db);
        Zend_Db_Table::setDefaultAdapter($db);
    }
   
    public static function setupAcl() {
        $auth = Zend_Auth::getInstance();
        $acl = new Winwinweb_Acl($auth);
        self::$frontController->setParam('auth', $auth);
        self::$frontController->setParam('acl', $acl);
        self::$frontController->registerPlugin(
            new Winwinweb_Controller_Plugin_Acl($auth, $acl)
        );
    }
    
    
    /**
     * Enter description here...
     *
     * @param Array|String $controller_directories chemin vers les controllers
     */
    public static function setupFrontController($controllers_path)
    {
        self::$frontController = Zend_Controller_Front::getInstance();
        //self::$frontController->registerPlugin(new AutocheckAuth(self::$auth, self::$acl));
        self::$frontController->setRequest(new Zend_Controller_Request_Http());
        self::$frontController->throwExceptions(true);
        self::$frontController->returnResponse(true);
        self::$frontController->setControllerDirectory($controllers_path);
        self::$frontController->setParam('registry', self::$registry);
    }
    
    public static function setupActionStack() {
        $actionStack = Zend_Controller_Action_HelperBroker::getStaticHelper("actionStack");
        $actionStack->actionToStack('footer', 'index', 'default');
        $actionStack->actionToStack('header', 'index', 'default');
    }
    
    public static function setupLayout($layout_path) {
        $layout_path['pluginClass'] = 'WinWinweb_Layout_Controller_Plugin_Layout';
        Zend_Layout::startMvc($layout_path);
    }
   
    public static function setupView()
    {
        $view = new Zend_View;
        $view->setEncoding('UTF-8');
        $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer($view);
        Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
    }
   
    public static function sendResponse(Zend_Controller_Response_Http $response)
    {
        $response->setHeader('Content-Type', 'text/html; charset=UTF-8', true);
        $response->sendResponse();
    }

    
    public static function setupLogger() 
    {
        $logLevel = intval(Zend_Registry::get('config')->logLevel); 
        
        $db = Zend_Db_Table::getDefaultAdapter();
        
        $columnMapping = array( 
            'timestamp' => 'timestamp', 
            'lvl' => 'priorityName', 
            'msg' => 'message' 
        ); 
         
        $writer = new Zend_Log_Writer_Db($db, 'log', $columnMapping); 
         
        $writer->addFilter(new Zend_Log_Filter_Priority($logLevel)); 
 
        $log = new Zend_Log($writer);
       /*
        * EMERG      0 : Urgence : le système est inutilisable
        * ALERT     1 : Alerte: une mesure corrective doit être prise immédiatement
        * CRIT         2 : Critique : états critiques
        * ERR         3 : Erreur: états d'erreur
        * WARN         4 : Avertissement: états d'avertissement
        * NOTICE     5 : Notice: normal mais état significatif
        * INFO         6 : Information: messages d'informations
        * DEBUG     7 : Debug: messages de déboguages
        */
        //$log->setEventItem('Memory used', memory_get_usage());
        Zend_Registry::set('logger', $log); 
        
        
    }
}

mon layout principal :

Code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  
    <title><?php echo $this->escape($this->title); ?></title>
        <link rel="stylesheet" type="text/css" media="screen"
             href="<?php echo $this->baseUrl();?>/public/css/site.css" />

</head>
<body>
<?php echo $this->layout()->header; ?>

<div id="content">
    <h1><?php echo $this->escape($this->title); ?></h1>
    <?php echo $this->layout()->content; ?>
</div>

<?php echo $this->layout()->footer; ?>
</body>
</html>

Code:

<?php


/**
 * Permet de définir un layout pour chaque module
 *
 */
class Mycompany_Layout_Controller_Plugin_Layout extends Zend_Layout_Controller_Plugin_Layout
{
   
    public function preDispatch(Zend_Controller_Request_Abstract $request)
    {
        $this->_moduleChange($request->getModuleName());
        
    }

    protected function _moduleChange($moduleName)
    {
        $layoutPath = dirname(dirname($this->getLayout()->getLayoutPath())) . DIRECTORY_SEPARATOR . $moduleName . '/layouts';
        
        if(!file_exists($layoutPath . DIRECTORY_SEPARATOR . $moduleName.".phtml")) return;
        $this->getLayout()->setLayoutPath($layoutPath);
        $this->getLayout()->setLayout($moduleName);
    }
   
}

IndexController du module default :

Code:

<?php

class IndexController extends Zend_Controller_Action 
{
    /*
    Appelée une seule fois à l'instanciation
    */
    public function init()
    {
        Zend_Registry::get('logger')->debug('Controller default/index'); 
    }
    
    /*
    Appelée avant un appel automatique d'une méthode d'action
    */
    public function preDispatch()
    {
    
    }
    
    public function indexAction()
    {
    }
    
    public function headerAction() {
        $this->_helper->viewRenderer->setResponseSegment('header');
    }
    
    public function footerAction() {
        $this->view->test = "Coucou";
        $this->_helper->viewRenderer->setResponseSegment('footer');
    }
    
    
    /*
    Appelée après un appel automatique d'une méthode d'action
    */
    public function postDispatch()
    {
    
    }
}

Je vous dispense des autres classes, je pense que le plus important est la.
Est-ce que ca vous semble bien dans l'ensemble ? (bootstrap)
En fait je bloque surtout sur le systeme de templating.

Pour l'instant, je peux avoir un layout par module. J'utilise le MVC push (actionStack) qui me permet de mettre en place un header et un footer...

Quelques questions :

Quelle differences entre cette méthode (actionStack) et la méthode de l'actionHelper (echo $this->action('action', 'controller') ou encore la méthode des placeholder ($this->partial(..)) et dans quels cas utiliser l'une ou l'autre ?

J'aimerais faire un systeme de gestion de design (par exemple un design noel, un design halloween, etc...). Pour ca il me faudrait rassembler mes vues et layout dans un dossier de design. Je pense qu'il s'agit juste de configuration du frontController, non?

Je place mes models à la racine de l'arborescence (voir arbo ci-dessus), afin d'y avoir accès depuis tout mes modules/controllers. Est-ce un problème? J'aimerais faire de même pour mes formulaires! Bonne idée ou pas?



Voila.. C'est un peu confus, et c'est bien pour ca que je fais ce post.. En fait c'est surtout pour etre sur d'être parti sur la bonne voie.

Dernière modification par nuranto (22-01-2009 22:08:52)

Hors ligne

 

#2 21-01-2009 14:34:26

Mr.MoOx
Administrateur
Lieu: Toulouse
Date d'inscription: 27-03-2007
Messages: 1444
Site web

Re: [resolu][1.7.0]Améliorations

Pour ce qui est header et footer, je ne te conseille pas d'utiliser des actions pour ça à part s'ils sont très dynamique.
S'ils sont générés mais qu'ils changent pas souvent, mieux faut faire un petit système de cache de ton rendu, ou utiliser le helper partial, histoire de perfomances.

La différence entre l'actionStack et du helper action c'est (dit simplement) l'ordre. Avec l'actionStack tu peux faire des actions avant l'action principal ou après, alors que le helper appelle l'action depuis la vue, donc pendant le rendu de ton action principal ou pendant le rendu du layout.
Le helper partial n'est qu'une sorte de require qui permet d'utiliser la syntaxe de Zend_View (en gros)

Et pour ce qui est du design, je vais te dire que ca n'a rien a voir avec ton mvc. Vois ca avec les CSS, ca te permet de ne pas toucher à tes vues, (j'insiste  sur le rôle des CSS, c'est fait pour).

Après pour ce qui est de l'architecture, cherche sur le forum, plusieurs discussions en parlent.

Hors ligne

 

#3 22-01-2009 11:50:32

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

Re: [resolu][1.7.0]Améliorations

Merci pour ta réponse, je vais rectifier ca pour les headers & footer!

En revanche, pour le design, je reste dubitatif! Je connais le role des CSS, mais je ne suis pas à l'origine des designs (sinon ca suffirait). Souvent l'intégration d'un nouveau design nécessite des retouches dans le HTML.

En fait j'aimerais me rapprocher de l'architecture prise par Magento (Vous devez connaitre : nouvelle plateforme e-commerce basée sur ZF).

Donc je voudrais qqch du genre :

Code:

application/module1/controllers/...
application/module2/controllers/...
models/
designs/nom_design/layouts/module1.phtml
designs/nom_design/views/module1/controller1/actions.phtml
designs/nom_design/views/module2/controller1/actions.phtml

En cherchant un peu, j'ai trouvé des gens qui essaye de faire pareil, mais aucune solution.
Est-il possible de spécifier le dossier de vues ?

Question bcp moins importante : Ou stockez vous vos classe de formulaires ? Je pensais soit les mettres dans le dossier models, soit créer un nouveau dossier forms a la racine?

Hors ligne

 

#4 22-01-2009 11:54:49

Mr.MoOx
Administrateur
Lieu: Toulouse
Date d'inscription: 27-03-2007
Messages: 1444
Site web

Re: [resolu][1.7.0]Améliorations

Est-il possible de spécifier le dossier de vues ?

Tout à fait. Je sais pas comment car j'ai jamais eu besoin, mais je suis certain que ça se fait, le ZF est presque entièrement adaptable sur tous les niveaux smile

Pour les classes de Form, en général je les mets dans mon dossier models. Ex:

Code:

models/
    User/
        Form/
            Login.php
            CreateEdit.php
        Table.php 
        etc...

Hors ligne

 

#5 22-01-2009 18:49:25

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

Re: [resolu][1.7.0]Améliorations

Voici ma nouvelle arborescence qui commence à marcher :

Code:

app/
---Bootstrap.php
---code/
------core/
---------module_name/
------------controllers/
------------views/helpers
---design/
------design_name/
---------layouts/
------------layout.phtml (layout par defaut)
------------module_name/module_name.phtml
---------templates
------------module_name/controller_name/action_name.phtml
---etc/
------config.ini
index.php
library/ (ne change pas)
models/ (j'y ai ajouté les formulaires, merci Mr.MoOx ;)  
public/
---design_name/
------css/images/js
var/
---logs/

Pour spécifier le dossier de views, deux solutions :

Code:

$view->addScriptPath($scriptPath);
$view->setBasePath($basePath);

Dans le premier cas, ca ajoute le $scriptPath directement.
Dans le deuxieme cas, ca ajoute $scriptPath."/scripts". (en gros)
Bref, ca revient plus ou moins au meme! Mais j'ai un probleme.

J'ai plusieurs modules, avec plusieurs controller Index (et leur action index évidemment).

Donc si j'ajoute toutes mes paths :
./app/design/nom_design/templates/admin
./app/design/nom_design/templates/default

Ca pose probleme. Car je vais toujours tomber sur le index/index.phtml du module admin!
Je voulais au départ créer un plugin afin d'ajouter seulement le path du bon module.

Mais je pense qu'on peut mieux faire. Le probleme se situe dans le ViewRenderer :

Code:

protected $_viewScriptPathSpec = ':controller/:action.:suffix';

Y-a-t-il un moyen de changer cette variable en :

Code:

':module/:controller/:action.:suffix';

Ce qui résoudrait mon problème.

Y-a-t-il un moyen de changer cette variable via une fonction quelque part ? Sinon je pensais la surcharger, mais ca me fait un peu mal pour seulement ca.
Bref, si vous avez une idée!

Hors ligne

 

#6 22-01-2009 20:48:15

etaty
Membre
Date d'inscription: 16-10-2008
Messages: 49

Re: [resolu][1.7.0]Améliorations

Regarde du coté de Zend controller router
http://framework.zend.com/manual/fr/zen … troduction

Hors ligne

 

#7 22-01-2009 21:49:43

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

Re: [resolu][1.7.0]Améliorations

Merci de ta réponse etaty!

Mais non, la route est bonne!

Quand je suis sur http://mydomain/ ou http://mydomain/default ou http://mydomain/default/index ou http://mydomain/default/index/index  c'est bien l'action index de  default/controllers/IndexController qui est appelé!
Mais lors du rendu, il appelle le script admin/index/index.phtml

Ce qui est normal, puisque j'ai mis manuellement toutes les paths de script et qu'il recherche le script uniquement avec les noms du controller et de l'action!

Ce que j'aimerais c'est juste spécifier la base de l'url, et qu'il cherche en utilisant le nom du module en plus.

Bon je me trouve pas clair donc :

Résumé :
Si je fais :

Code:

foreach($modules as $module)
    $view->addScriptPath('./app/design/' . $design . '/templates/' . $module);

Alors il rechercheras les vus dans :
./app/design/nom_design/templates/admin
./app/design/nom_design/templates/default

Donc lorsqu'on appelle default/index/index , Il recherche le fichier index/index.phtml et le trouve d'abord dans :
./app/design/nom_design/templates/admin

Ce qui n'est pas bon...

Ce que je voudrais c'est faire :

Code:

$view->setBasePath('./app/design/' . $design . '/templates/');

Seulement il ne trouveras rien en cherchant index/index.phtml. Il faut qu'il prenne en compte le module..... D'ou ma question du post précedent.

Donc en changeant directement dans Zend_Controller_Action_Helper_ViewRenderer :

Code:

    protected $_viewScriptPathSpec = ':controller/:action.:suffix';

par

Code:

    protected $_viewScriptPathSpec = ':module:controller/:action.:suffix';

Ca marche, mais on sera tous d'accord pour dire que ce n'est pas une bonne solution!

En regardant un peu plus le code de cette classe, j'ai vu :

Code:

 protected $_viewScriptPathNoControllerSpec = ':action.:suffix';

et

Code:

    /**
[...]
     * If {@link $_noController} is set, uses {@link $_viewScriptPathNoControllerSpec};
     * otherwise, uses {@link $_viewScriptPathSpec}.
[...]
     */
    public function getViewScript($action = null, array $vars = array())

Ce qui me laisse penser qu'il n'y pas de methode pour modifier cette variable... Je vais devoir surcharger.. Si vous voyez autre chose...

Hors ligne

 

#8 22-01-2009 22:08:26

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

Re: [resolu][1.7.0]Améliorations

Code:

$viewRenderer->setViewScriptPathSpec(":module/:controller/:action.:suffix");

Je n'ai absolument aucune excuse.

Pas de commentaires svp :'(

Bref, j'espere que ca servira à quelqu'un smile

Hors ligne

 

#9 06-02-2009 13:52:03

dev21
Membre
Date d'inscription: 06-01-2009
Messages: 23

Re: [resolu][1.7.0]Améliorations

ça reviens à la hiérarchie de Magento , sans vouloir faire de pub;

Hors ligne

 

#10 06-02-2009 14:04:43

nuranto
Membre
Date d'inscription: 20-01-2009
Messages: 24

Re: [resolu][1.7.0]Améliorations

nuranto a écrit:

[...]
En fait j'aimerais me rapprocher de l'architecture prise par Magento (Vous devez connaitre : nouvelle plateforme e-commerce basée sur ZF).
[...]

wink

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