Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 10-02-2011 14:27:21

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

Zend_Application_Module_Bootstrap et Zend_Navigation

Bonjour,

Je rencontre un problème en essayant de mettre une navigation propre à chacun de mes modules dans mon projet.

J'arrive à mettre une navigation dans mes modules grâce au Zend_Application_Module_Bootstrap que j'étends dans chacun de mes modules, mais j'ai toujours le même menu qui s'affiche.

J'ai cru comprendre que c'était normal, étant donné le processus d'initialisation, mais je ne vois pas trop comment faire.

Merci d'avance pour votre aide !

Hors ligne

 

#2 11-02-2011 10:47:26

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Hello,

Une solution serait d'identifier tes éléments de navigation, et ensuite de les importer spécifiquement, exemple :

## navigation.xml

Code:

<?xml version="1.0" encoding="UTF-8"?>
<navigation>
    <nav>
        <!-- Module::Frontend -->
        <frontend id="frontend" controller="" action="">
            <pages>
                <!-- home -->
                <home id="frontend.home" label="frontend.nav.home.label" class="menu-tab" route="frontend_index" />
        
                <!-- about -->
                <about id="frontend.about" label="frontend.nav.about.label" class="menu-tab" route="frontend_about" />
            
                <!-- contact -->
                <contact id="frontend.contact" label="frontend.nav.contact.label" class="menu-tab" route="frontend_contact" />
            </pages>
        </frontend>

        <!-- Module::Backend -->
        <backend id="backend" controller="" action="">
            <pages>
                <!-- dashboard -->
                <dashboard id="backend.dashboard" label="backend.nav.dashboard.label" route="backend_dashboard" />
        
                <!-- users -->
                <users id="backend.users" label="backend.nav.users.label" route="backend_users" />
            
                <!-- settings -->
                <settings id="backend.settings" label="backend.nav.settings.label" route="backend_settings" />
            </pages>
        </backend>
    </nav>
</navigation>

Ici j'utilise des routes, mais tu peux très bien définir le triplet : module="frontend" controller="index" action="index"

Ensuite depuis une vue :

Code:

<nav class="menu">
    <?php
    $nav = $this->navigation()->findBy('id', 'frontend');
    echo $this->navigation()
        ->menu()
        ->renderMenu($nav, array(
            'maxDepth' => 0,
            'renderParents' => false
        ));
    ?>
</nav>

ou biensûr :

Code:

<nav class="menu">
    <?php
    $nav = $this->navigation()->findBy('id', 'backend');
    echo $this->navigation()
        ->menu()
        ->renderMenu($nav, array(
            'maxDepth' => 0,
            'renderParents' => false
        ));
    ?>
</nav>

Bonus : comme c'est un peu répétitif tu peux écrire une petite aide de vue, genre GetMenuHtml :

Code:

class App_View_Helper_GetMenuHtml extends Zend_View_Helper_Abstract
{

    public function getMenuHtml($id, $depth = 0, $className = '')
    {
        $nav = $this->view->navigation()->findBy('id', $id);
        return $this->view->navigation()
                ->menu()
                ->renderMenu($nav, array(
                    'maxDepth' => $depth,
                    'renderParents' => false,
                    'ulClass' => $className
                ));
    }

}

Et ensuite :

Code:

<nav class="menu">
    <?php echo $this->getMenuHtml('frontend'); ?>
</nav>

<!-- ou -->

<nav class="menu">
    <?php echo $this->getMenuHtml('backend'); ?>
</nav>

A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#3 11-02-2011 16:46:44

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

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Merci pour ta réponse rapide et très complète !

Par contre, dans cette solution, il n'existe toujours qu'un seul fichier xml pour gérer la navigation, alors que j'aurais aimé en créer un par module de sorte à tout mettre dans le dossier modules/nom_du_module/.

Saurais-tu si il existe une solution pour ça ?

Hors ligne

 

#4 11-02-2011 20:54:04

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Je me trompe peut-être mais nativement tu ne peux pas éclater le fichier de conf par module.

Mais comme rien n'est impossible, avec ZF, et Zend_Config, il est relativement simple de merger plusieurs fichiers de config. Quelque soit l'adapter utilisé pour la config (ini, xml, yaml, ...), la config est normalisée dans un objet Zend_Config. Tu peux par exemple jeter un coup d'oeil dans la classe "Zend_Application_Bootstrap_BootstrapAbstract" dans laquelle ZF merge les options des plugins de ressources de Zend_Application (pour permettre d'éclater la config en plusieurs fichiers ini/xml ou autre).


Une autre solution pourrait être d'utiliser Zend_Application de cette manière :

Code:

$application = new Zend_Application(
    APPLICATION_ENV,
    array(
        'config' => array(
            APPLICATION_PATH . '/../etc/app/app.xml',
            APPLICATION_PATH . '/../etc/app/database.xml', 
            APPLICATION_PATH . '/../etc/app/routes.xml',
            APPLICATION_PATH . '/../chemin/vers/module1/etc/navigation.xml',
            APPLICATION_PATH . '/../chemin/vers/module2/etc/navigation.xml',
        )
    )
);

En émettant de grosses réserves sur la faisabilité de la chose smile
C'est à tester, je ne peux pas te garantir que ça va fonctionner. Et cette solution sera peut-être un peu rigide selon ce que tu veux faire.

* ATTENTION * : Si tu utilises les fichiers ini, il faut que TOUTES les sections (prod, dev, test, ...) soient présentes dans chaque fichier de configuration, même si elles sont vides.


Si tu m'en dis un peu plus je pourrai peut-être mieux te mettre sur la voie.


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#5 12-02-2011 01:57:38

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

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Merci beacoup pour ton aide !

Alors l'idée complète est de réaliser un CMS pour les associations, auquel il serait possible d'ajouter très simplement des modules.

Comme je suis encore étudiant et que nous réalisons (nous sommes 5) cela dans le cadre d'un projet universitaire, j'ai proposé d'utiliser Zend Framework qui m'a semblé correspondre à nos besoins (j'apprends Zend depuis deux ans, et je commence à peine à bien envisager le système smile).

Je pensais de fait que pour faciliter l'intégration des modules en proposant une gestion individuelle de la navigation.

Au niveau de la structure du projet, je mets donc les différents models, vues, controllers, et formulaires dans les dossiers des modules et tout va bien.
Comme je viens de découvrir le bootstrap de module, j'ai imaginé rajouter un simple dossier config avec un navigation à chaque fois, mais malheureusement pour moi ça ne se passe pas comme ça.

L'architecture de fichier ressemble à ça :
http://img713.imageshack.us/img713/1518/assoboardfilestructure.png

Voilà, c'est à peu près tout ce que je vois de bon à en dire, mais si tu as des questions, je serais heureux d'apprendre tout ce que tu peux m'enseigner !

Hors ligne

 

#6 23-02-2011 20:19:23

Delprog
Administrateur
Date d'inscription: 29-09-2008
Messages: 670

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Hello,

Il n'est jamais trop tard smile

Donc si je comprend bien, tu veux pouvoir configurer la navigation que pour ton module et que cette navigation viennent s'insérer automatiquement dans la navigation principale ?

Admettons que ça soit pour le backoffice. L'idéal serait d'avoir un fichier XML (ou ini, ou PHP, whatever :p) qui contient la navigation juste pour ce module, nouvelle entrée de menu qui viendrait s'ajouter au menu du back office par ex.

Ce genre de fonctionnement implique que tu as déjà prévu un système pour qu'un module soit auto-découvert ou qu'il soit ajouté d'une manière ou d'une autre à une liste de modules à considérer au moment de l'initialisation de l'application. Tout simplement parce que le fonctionnement n'est pas vrai seulement pour la navigation mais aussi pour tout autre configuration spécifique au module j'imagine.

Pour ça il y a plusieurs solutions, et toutes sont à faire from scratch, je pense pas que ZF va beaucoup t'aider dans cette tâche.


Solution 1 : Scan des dossiers et laisser faire Zend_Application

Au moment de l'initialisation de l'environnement, scanner tous les dossiers "modules", et ajouter la configuration de chaque module actif (j'imagine une valeur dans la configuration du module, genre active = 1 :p) à Zend_Application.

Ex:

Code:

require_once 'My/FileLocator.php';

$finder = new FileLocator();
$finder->setOnlyFiles(true);
       ->setIn('/path/to/modules/dir')
       ->setNameFilter('*.xml');

$configs = array();
foreach ($finder->getResults() as $file) {
    $configs[] = $file->getRealpath();
}

/** Zend_Application */
require_once 'Zend/Application.php';  

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    array(
        'config' => $configs
    )
);

FileLocator serait une classe à toi qui reposerait sur des iterateurs PHP (voir doc Spl) et getResults() renverrait par ex. un tableau d'instances de SplFileInfo (qui permet d'obtenir toutes sortes d'informations sur un fichier, ici on a besoin du chemin).

Pour pas ré-inventer la roue, tu peux t'inspirer du Finder qu'introduit Symfony 2 par ex : http://docs.symfony-reloaded.org/master … inder.html (à recoder pour PHP < 5.3 donc...).

Maintenant est-ce que Zend_Application va être capable de merger tout ça correctement ? Aucune idée ! Il faut tester. A priori oui.


Solution 2 : même chose sauf que tu ne scannes pas les dossiers mais tu charges un fichier de configuration global qui contient une liste de modules actifs pour lesquels l'application doit aller charger les fichiers de configuration. Les chemins sont donc explicites, pas besoin d'itérer sur les dossiers.


Solution 3 : Tu veux mettre en place ta propre gestion de configuration et là tu peux utiliser une des deux premières solutions et en plus faire du merge toi même avec Zend_Config et envisager un tout autre fonctionnement pour ton système.


Attention ces réflexions sont peut être un peu légères, si tu envisages vraiment de créer un CMS flexible, la gestion des modules et de leurs configurations est un point critique. Je te donne seulement des solutions (1 et 2) envisageables qui ne "cassent" à priori pas le fonctionnement natif de Zend_Application.


A+ benjamin.


http://www.anonymation.com/ - anonymation - Studio de création.
http://code.anonymation.com/ - anonymation - blog - développement et architecture web

Hors ligne

 

#7 25-02-2011 15:02:34

fhebert
Membre
Date d'inscription: 30-11-2010
Messages: 20

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Bonjour,

j'ai voulu implémenter un système identique à la solution 1 mais en surchargeant la classe Zend_Application_Module_Bootstrap.

La logique est d'utiliser un RecursiveDirectoryIterator filtré par une implémentation de FilterIterator. Ces itérateurs récupèrent tous les fichiers '*.ini'/'*.yml'/etc. présents dans le dossier et les sous-dossiers de configuration (quelque soit son nom) du module "en cours de bootstraping".

Là où je bloque c'est pour merger les options obtenues dans la Zend_Application initiale (seule la méthode setOptions le permet et elle redéclare certaines classes notamment Bootstrap).

Voici ma classe Local_Application_Module_Bootstrap

Code:

<?php
/** 
 * @author fhebert
 * 
 * Boostrap class extending Zend's bootstraping module logic.
 * 
 * The rational is :
 *  
 * Zend_Application_Module_Boostrap class get current module's
 * configuration from Zend_Application main class as passed to it 
 * from __construct method. So there is no way to load 'at module's bootstrap
 * time' a modular configuration set (typically from module's config subdir).
 * 
 * So we load all .ini files found in the config subdir and set the result 
 * in the main Zend_Application class.  
 */
class Local_Application_Module_Boostrap extends Zend_Application_Module_Bootstrap
{
    /**
     * 
     * Enter description here ...
     * @param Zend_Application $application
     */
    function __construct ($application)
    {
        $applicationConfig = $application->getOption('applicationConfig');
        if (empty($applicationConfig['filesLayout']['configDirectoryName'])) {
            $configDirName = 'config';
        } else {
            $configDirName = $applicationConfig['filesLayout']['configDirectoryName'];
        }
        /* @var $fc Zend_Controller_Front */
        $fc = $application->getBootstrap()->getResource('FrontController');
        $configPath = $fc->getModuleDirectory() . DIRECTORY_SEPARATOR . $this->getModuleName() . 
            DIRECTORY_SEPARATOR . $configDirName;
        /* @var $cpInfo SplFileInfo */    
        $cpInfo = new SplFileInfo($configPath);
        if (!($cpInfo->isDir() || $cpInfo->isExecutable())) {
            throw new Local_Application_Module_Bootstrap_Exception(
                $configPath . ' is not a directory or is not executable !'
            );
        }
            
        $it = new Local_Iterator_Filter_Extension(
            new RecursiveDirectoryIterator($configPath, RecursiveDirectoryIterator::CURRENT_AS_FILEINFO)
            , '.ini'
        );
        
        $configFiles = array();
        $configFiles['config'] = array();
        foreach ($it as $k => $splFileInfo) {
            /* @var $splFileInfo SplFileInfo */
            if ($splFileInfo->isFile() && $splFileInfo->isReadable()) {
                $configFiles['config'][] = $splFileInfo->getRealPath();
            }
        }
        $application->setOptions(
                     $application->mergeOptions(   
                         $configFiles,
                         $application->getOptions()
                     )
                );
        
        parent::__construct($application);

    }
}
?>

Avez une solution possible à ce problème ?

Frédéric

Hors ligne

 

#8 26-02-2011 13:24:14

fhebert
Membre
Date d'inscription: 30-11-2010
Messages: 20

Re: Zend_Application_Module_Bootstrap et Zend_Navigation

Voici une version modifiée à tester pour ceux que cela intéresse ; la question
reste toujours de savoir si cela n'apporte des effets de bord négatifs ???

Code:

<?php
/** 
 * @author fhebert
 * 
 * Bootstrap class extending Zend's bootstraping module logic.
 * 
 * The rational is :
 *  
 * Zend_Application_Module_Boostrap class get current module's
 * configuration from Zend_Application main class as passed to it 
 * from __construct method. So there is no way to load 'at module's bootstrap
 * time' a modular configuration set (typically from module's config subdir).
 * 
 * So we load all .ini files found in the config subdir and set the result 
 * in the main Zend_Application class.  
 */
class Local_Application_Module_Bootstrap extends Zend_Application_Module_Bootstrap
{
    /**
     * 
     * Enter description here ...
     * @param Zend_Application $application
     */
    function __construct ($application)
    {
        $applicationConfig = $application->getOption('applicationConfig');
        if (empty($applicationConfig['filesLayout']['configDirectoryName'])) {
            $configDirName = 'config';
        } else {
            $configDirName = $applicationConfig['filesLayout']['configDirectoryName'];
        }
        
        /* @var $fc Zend_Controller_Front */
        if (!$application instanceof Zend_Application_Bootstrap_BootstrapAbstract) {
//            $application->getBootstrap()->bootstrap('frontcontroller');
            $fc = $application->getBootstrap()->frontController;
        } else {
//            $this->bootstrap('frontController');
            $fc = $application->frontController;
        }
        
        $configPath = $fc->getModuleDirectory($this->getModuleName()) . 
            DIRECTORY_SEPARATOR . $configDirName;
        /* @var $cpInfo SplFileInfo */    
        $cpInfo = new SplFileInfo($configPath);
        if (!$cpInfo->isDir() || !$cpInfo->isExecutable()) {
            throw new Local_Application_Module_Bootstrap_Exception(
                $configPath . ' is not a directory or is not executable !'
            );
        }
            
        $it = new Local_Iterator_Filter_Extension(
            new RecursiveDirectoryIterator($configPath, RecursiveDirectoryIterator::CURRENT_AS_FILEINFO)
            , '.ini'
        );
        
        $options = array();
        $options = $application->getOptions();
        foreach ($it as $k => $splFileInfo) {
            /* @var $splFileInfo SplFileInfo */
            if ($splFileInfo->isFile() && $splFileInfo->isReadable()) {
                $ext = substr($splFileInfo->getFileName(), strrpos($splFileInfo->getFileName(), '.'));
                
                switch ($ext) {
                    case '.ini':
                        $cfg = new Zend_config_Ini($splFileInfo->getRealPath());
                        break;
                    case '.xml':
                        $cfg = new Zend_config_Xml($splFileInfo->getRealPath());
                        break;
                    default:
                        break 2;
                }
                
                $options = $application->mergeOptions(
                    $options,
                    $cfg->toArray()
                );
            }
        }
        
        $application->setOptions($options);
            
        parent::__construct($application);

    }
}
?>

frédéric

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