Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 11-03-2010 12:31:58

nORKy
Membre
Date d'inscription: 06-03-2008
Messages: 1098

Container de service

Avez déjà utiliser un container de service (le plus connu étant celui de Sf) ?
Qu'en pensez-vous ?


----
Gruiiik !

Hors ligne

 

#2 11-03-2010 16:34:24

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

Re: Container de service

Salut,

Qu'entends-tu par container de service ? Un container de dépendances ?


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-03-2010 17:07:24

nORKy
Membre
Date d'inscription: 06-03-2008
Messages: 1098

Re: Container de service

oui, excuse, j'ai zappé qq mots smile ma pensée a oublié de le dire à mes doigts


----
Gruiiik !

Hors ligne

 

#4 12-03-2010 10:19:26

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

Re: Container de service

Ok smile

Ben j'avais regardé du côté du container symfony, mais ce qui me dérangeait c'est de créer une dépendance au container lui même.

Du coup, j'ai crée un petit container maison qui injecte par setters, il ne permet pas encore de passer des paramètres, mais je l'utilise de partout maintenant. C'est très simple de le plugger à Zend_Application smile

Code:

<?php
/**
 * Tight_Di - Contains all dependencies references
 *  
 * @category Tight
 * @package Tight_Di
 * @author Benjamin Dulau
 */
class Tight_Di 
{
    
    /**
     * Array of instances     
     * @var array
     */
    protected $_instances = array();
    
    /**
     * Array of registered dependencies     
     * @var array
     */
    protected $_components = array();

    /**     
     * @var Tight_Aop
     */
    protected $_aop;
    
    
    /**
     * Constructor - calls load method for each file
     * 
     * @param array $componentFiles
     * @return void
     */
    public function __construct(array $componentFiles = array())
    {
        foreach($componentFiles as $file) {
            $this->load($file);
        }
    }

    /**
     * Loads file and builds components definitions
     * 
     * @param string $componentFile
     * @return bool success
     * @throws Tight_Di_Exception if unable to load file as XML
     */
    public function load($componentFile)
    {        
        if (false === file_exists($componentFile) || false === is_file($componentFile)) {
            Throw new Tight_Di_Exception(Tight_Di_Exception::NO_SUCH_FILE . ': ' . $componentFile);
            return false;                
        } 
        
        $xml = null;
        if (false === ($xml = simplexml_load_file($componentFile))) {
            Throw new Tight_Di_Exception(Tight_Di_Exception::FILE_LOAD_FAILED . ': ' . $componentFile);
            return false;            
        };    

        // components
        foreach ($xml->component as $XMLElement) {
            $component = array();
        
            // id
            $id = (string)$XMLElement->attributes()->id;
            $component['class'] = (string)$XMLElement->attributes()->class;

            // dependencies
            $component['dependencies'] = array();
            foreach($XMLElement->property as $property) { 
                $name = (string)$property->attributes()->name;
                $refComponent = (string)$property->attributes()->ref;
                                
                $component['dependencies'][$name] = $refComponent;                                             
            }
            
            $this->addComponent($id, $component);
        }
        
        // aop : experimental
//        foreach ($xml->aop as $XMLElement) {
//            if (null === $this->_aop) {
//                $this->setAop(new Tight_Aop());
//            }
//            $this->getAop()->addConfig($XMLElement);
//        }
//        
//        if ($this->getAop()->classMatchExpression($class)) {
//            $instance = $this->getAop()->getClassInstance($class);
//        }
//        else {
//            $instance = new $class();   
//        }
        
        return true;
    }
    
    /**     
     * @param Tight_Aop $aop
     * @return Tight_Di
     */
    public function setAop(Tight_Aop $aop)
    {
        $this->_aop = $aop;
        return $this;
    }
    
    /**     
     * @return Tight_Aop
     */
    public function getAop()
    {
        return $this->_aop;
    }

    /**
     * Adds a dependency reference to container     
     *
     * @param  array $dependency config array for provided dependency     
     * @return Tight_Di
     */
    public function addComponent($key, array $component) {                
        $this->_components[$key] = $component;
        return $this;        
    }
    
    /**
     * Returns component definition
     * 
     * @param string $key
     * @return array
     */
    public function getComponent($key) {        
        return $this->_components[$key];        
    }
    
    /**
     * Returns all components definitions array
     * 
     * @return array
     */
    public function getComponents()
    {
        return $this->_components;
    }
    
    /**
     * Retrieves component instance.
     * Creates instance if none exists yet
     * 
     * @param $key
     * @return mixed
     */
    public function getInstance($key)
    {
        $component = $this->getComponent($key);
        if (false === array_key_exists($key, $this->_instances)) {
            $this->_instances[$key] = new $component['class']();            
        }
        
        return $this->_instances[$key];
    }
    
    /**
     * Injects recursively dependencies starting by $key
     *  
     * @param $key
     * @param $target
     * @return void
     */
    public function inject($key, $target)
    {        
        $component = $this->getComponent($key); 
        foreach($component['dependencies'] as $property => $ref) {
            $var = '_' . $property;
            $setter = 'set' . ucfirst($property);
            
            $instance = $this->getInstance($ref);        
            $target->$setter($instance);
            
            // recursive injection for dependency dependencies
            $this->inject($ref, $instance);
        }
    }
    
    /**
     * Sets directly an instance into instances.
     * Used by Zend_Application on resource plugin return.     
     *
     * @param string $key
     * @param mixed $instance
     * @return Tight_Di
     */
    public function __set($key, $instance)
    {
        /*$component = array();                               
        $component['class'] = get_class($instance);        
        
        // dependencies
        $component['dependencies'] = array();                        
        $this->addComponent($key, $component);*/

        $this->_instances[$key] = $instance;
        
        return $this;    
    }

    /**
     * Gets the given instance
     * Used by Zend_Application on getInvokArg()
     *
     * @param string $key
     * @return mixed instance
     */
    public function __get($key)
    {        
        return $this->getInstance($key);
    }
    
    /**
     * Tests if an object exists into instances
     * Used by Zend_Application
     *
     * @param string $key
     * @return bool
     */
    public function __isset($key)
    {        
        return array_key_exists($key, $this->_instances);
    }
}

index.php

Code:

try {
    $container = new Tight_Di(array(
        APPLICATION_PATH . '/../etc/ioc/resources.xml',
        APPLICATION_PATH . '/../etc/ioc/controllers.xml',
        APPLICATION_PATH . '/../etc/ioc/services.xml',        
        APPLICATION_PATH . '/../etc/ioc/daos.xml'
    ));
    
    $application->getBootstrap()->setContainer($container);
    $application->bootstrap()
                     ->run();
}
catch (Exception $e) {
    exit($e->getCode() . ': ' . $e->getMessage());
}

Fichiers xml de config

Code:

<!-- resources.xml -->
<components>
    <component id="doctrine" class="Doctrine_Manager" />        
    <component id="exception" class="Zend_Exception" />
    <component id="modules" class="" />
    <component id="exception" class="Zend_Exception" />
    <component id="Navigation" class="Zend_Navigation" />
    <component id="Routeur" class="Zend_Router" />
    <component id="frontcontroller" class="Zend_Controller_Front" />
    <component id="layout" class="Zend_Layout" />
    <component id="view" class="Tight_View" />
    <component id="locale" class="Zend_Locale" />
    <component id="translate" class="Zend_Translate" />
    <component id="session" class="Zend_Session" />
    <component id="config" class="Zend_Config" />            
    <component id="acl" class="App_Acl" />
    <component id="auth" class="App_AuthImpl">
        <property name="userRepository" ref="userRepository" />
        <property name="accountAssembler" ref="accountAssembler" />    
    </component>
    <component id="imagemanager" class="App_ImageManager" />
    <component id="mailer" class="Tight_Mail" />                
</components>

<!-- controllers.xml -->
<components>
    <!-- Front module -->
    <component id="authController" class="Front_AuthController">
        <property name="auth" ref="auth" />
        <property name="accountService" ref="accountService" />
    </component>
    <component id="accountsController" class="Front_AccountsController">
        <property name="auth" ref="auth" />                
        <property name="accountService" ref="accountService" />
        <property name="mailer" ref="appmailer" />
    </component>
    <component id="galleriesController" class="Front_GalleriesController">                
        <property name="auth" ref="auth" />
        <property name="galleryService" ref="galleryService" />
        <property name="imageManager" ref="imagemanager" />            
    </component>
    <component id="photosController" class="Front_PhotosController">                
        <property name="auth" ref="auth" />
        <property name="photoService" ref="photoService" />                
    </component>
    
    <component id="appmailer" class="App_Mailer">
        <property name="mailer" ref="mailer" />
        <property name="translator" ref="translate" />
    </component>
</components>

<!-- services.xml -->
<components>    
    <component id="accountService" class="Service_Impl_Account">
        <property name="auth" ref="auth" />
        <property name="userRepository" ref="userRepository" />
        <property name="accountValidator" ref="accountValidator" />
        <property name="accountAssembler" ref="accountAssembler" />
        <property name="accountDetailsAssembler" ref="accountDetailsAssembler" />
        <property name="authValidator" ref="authValidator" />
        <property name="mailService" ref="mailService" />
        <property name="recoverValidator" ref="recoverValidator" />
        <property name="editAccountValidator" ref="editAccountValidator" />
        <property name="accountDetailsValidator" ref="accountDetailsValidator" />
    </component>
    <component id="galleryService" class="Service_Impl_Gallery">        
        <property name="auth" ref="auth" />
        <property name="userRepository" ref="userRepository" />
        <property name="galleryRepository" ref="galleryRepository" />
        <property name="photoRepository" ref="photoRepository" />
        <property name="galleryAssembler" ref="galleryAssembler" />
        <property name="photoAssembler" ref="photoAssembler" />
        <property name="galleryValidator" ref="galleryValidator" />
        <property name="photoValidator" ref="photoValidator" />
        <property name="imageManager" ref="imagemanager" />
        <property name="commentAssembler" ref="commentAssembler" />
        <property name="commentValidator" ref="commentValidator" />
        <!-- <property name="galleryValidator" ref="galleryValidator" /> -->
    </component>
    <component id="photoService" class="Service_Impl_Photo">
        <property name="auth" ref="auth" />
        <property name="photoRepository" ref="photoRepository" />
        <property name="photoAssembler" ref="photoAssembler" />
        <property name="commentAssembler" ref="commentAssembler" />
        <property name="commentValidator" ref="commentValidator" />
    </component>
    <component id="mailService" class="Service_Impl_Mail">
        <property name="mailer" ref="mailer" />
    </component>
    <!-- validators -->
    <component id="accountValidator" class="Service_Validator_Account">
        <property name="userRepository" ref="userRepository" />     
    </component>
    <component id="authValidator" class="Service_Validator_Auth" />
    <component id="accountAssembler" class="Assembler_Account" />
    <component id="accountDetailsAssembler" class="Assembler_AccountDetails" />
    <component id="accountDetailsValidator" class="Service_Validator_AccountDetails" />
    <component id="galleryAssembler" class="Assembler_Gallery" />
    <component id="photoAssembler" class="Assembler_Photo" />
    <component id="galleryValidator" class="Service_Validator_Gallery" />
    <component id="photoValidator" class="Service_Validator_Photo" />
    <component id="commentAssembler" class="Assembler_Comment" />
    <component id="commentValidator" class="Service_Validator_Comment">
        <property name="userRepository" ref="userRepository" />
    </component>        
    <component id="recoverValidator" class="Service_Validator_RecoverPassword" />
    <component id="editAccountValidator" class="Service_Validator_EditAccount" >
        <property name="userRepository" ref="userRepository" /> 
    </component>
</components>

<!-- daos.xml -->
<components>
    <component id="userRepository" class="DAO_User" />    
    <component id="galleryRepository" class="DAO_Gallery" />
    <component id="photoRepository" class="DAO_Photo" />    
</components>

Voilà, j'ai copié-collé des parties, c'est un peu fourni. Bien que je soupçonne que l'impossibilité de passer des paramètres te manque fortement. On va dire que c'est en attendant que Zend propose un véritable container.
Sachant que le fait de redéclarer les ressources de Zend_Application dans le fichier "resources.xml" permet de pouvoir y faire référence, les instances dans le conteneur existent car elles sont retournées au container par Zend_Application au moment de bootstrap les ressources.


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-03-2010 13:46:34

nORKy
Membre
Date d'inscription: 06-03-2008
Messages: 1098

Re: Container de service

Que veux tu dire par dépendances de lui même ??

En fait, ce qui me repousse dans celui de Sf, c'est que la conf n'est pas "petite" :p (en gros, j'ai la flemme)

Mes classes de services étends une classe qui contient qq fonctions pour gérer les instances (partagés ou non) et donc le constructeur est capable de chargé la conf dans application.ini (il passe par le bootsrap de module donc presque rien à faire).

Mais actuellement, je suis fasse à un schéma de dépendance de classe circulaire et je me demande si je vais pas évoluer faire un gestionnaire plus efficace que mon bricolage smile

sachant que ZF 2.0 c'est pas pour tout de suite et que je pense pas qu'on aura un tel composant dans 1.X, je posais la question sur les avis de chacun à ce sujet


----
Gruiiik !

Hors ligne

 

#6 12-03-2010 14:39:14

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

Re: Container de service

Ce qui me dérange dans le container sf tout comme Zend_Application c'est de devoir invoker l'instance via le container par un getInvokArg() ou je ne sais plus comment avec le container de symfony. Du coup t'en as de partout de ces trucs là. Je préfère largement l'injection par setters.

Il me semble qu'il y a une version PHP5 de PicoContainer, mais tu auras toujours de la config à te taper ça c'est certain smile


A+ benjamin.

Dernière modification par Delprog (12-03-2010 14:39:31)


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

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