zfconf 2010: zend framework & mvc, model implementation (part 2, dependency injection)

29
Dependency Injection (Внедрение Зависимостей) ZF, Zend_Application, DI Container, Symfony DI 27 марта 2010 г. Санкт- Петербург

Upload: zfconf-conference

Post on 17-May-2015

5.023 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Dependency Injection(Внедрение Зависимостей)

ZF, Zend_Application, DI Container, Symfony DI

27 марта 2010 г.

Санкт-Петербург

Page 2: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Кирилл Чебунин

• Ведущий PHP разработчик Equelli, ltd.

• Около 4 лет опыта PHP

• Более 2х лет использования ZendFramework

О Докладчике

Page 3: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Выбор классов

• Адаптеры• Плагины/Хелперы• Интерфейсы и Реализация

Page 4: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Хранилище

 

Page 5: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

$GLOBALS

$logger = new Zend_Log();$writer = new Zend_Log_Writer_Stream('/var/log/myapp.log');$logger->addWriter($writer);

$GLOBALS['log'] = $logger;

class UserController extends Zend_Controller_Action{    public function indexAction()    {        /* @var $log Zend_Log */        $log = $GLOBALS['log'];        $log->log('Index Action', Zend_Log::INFO);    }

    public function secondAction()    {        /* @var $log Zend_Log */        $log = $GLOBALS['log'];        $log->log('Second Action', Zend_Log::INFO);    }

}

Page 6: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Zend_Registry

$logger = new Zend_Log();$writer = new Zend_Log_Writer_Stream('/var/log/myapp.log');$logger->addWriter($writer);

Zend_Registry::set('log', $logger);

class UserController extends Zend_Controller_Action{    public function indexAction()    {        /* @var $log Zend_Log */        $log = Zend_Registry::get('log');        $log->log('Index Action', Zend_Log::INFO);    }

    public function secondAction()    {        /* @var $log Zend_Log */        $log = Zend_Registry::get('log');        $log->log('Second Action', Zend_Log::INFO);    }

}   

Page 7: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Zend_Application

[production]resources.log.file.writerName = "Stream"resources.log.file.writerParams.stream = "/var/log/myapp.log"

class UserController extends Zend_Controller_Action{    public function indexAction()    {        /* @var $log Zend_Log */        $log = $this->getInvokeArg('bootstrap')->getResource('log');        $log->log('Index Action', Zend_Log::INFO);    }

    public function secondAction()    {        /* @var $log Zend_Log */        $log = $this->getInvokeArg('bootstrap')->getResource('log');        $log->log('Second Action', Zend_Log::INFO);    }

}

Page 8: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Zend_Application             & Dependency Injection

class My_Application_Resource_Service_UserService     extends Zend_Application_Resource_ResourceAbstract{    //[.....]}

class My_Application_Resource_Service_PostService     extends Zend_Application_Resource_ResourceAbstract{    //[.....]}

class My_Application_Resource_Service_ArticleService     extends Zend_Application_Resource_ResourceAbstract{    //[.....]}

class My_Application_Resource_Service_RoleService     extends Zend_Application_Resource_ResourceAbstract{    //[.....]}//[.....]//[.....]//[.....]

Page 9: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Zend_Application             & Dependency Injection

class Zend_Application_Resource_Log    extends Zend_Application_Resource_ResourceAbstract{    //[.....]    /**     * Defined by Zend_Application_Resource_Resource     *     * @return Zend_Log     */    public function init()    {        return $this->getLog();    }

    //[.....]     public function getLog()    {        if (null === $this->_log) {            $options = $this->getOptions();            $log = Zend_Log::factory($options);            $this->setLog($log);        }        return $this->_log;    }}

Page 10: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Конфигурация вместо кода

<service id="log" class="Zend_Log" constructor="factory"> <argument type="collection">                <argument key="file" type="collection">                        <argument key="writerName">Stream</argument>                        <argument key="writerParams" type="collection">                                <argument key="stream">/var/log/myapp.log</argument>                        </argument>                </argument>        </argument></service>

<service id="log" class="Zend_Log">        <call method="addWriter">                <argument type="service">                        <service class="Zend_Log_Writer_Stream">                                <argument>/var/log/myapp.log</argument>                        </service>                </argument>         </call></service>

Page 11: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Dependency Injection —  

A specific form of Inversion of Control (IOC)

Взято из ®Wikipedia, the free encyclopedia

Внедрение зависимости —  

    Специфическая форма «обращения контроля»

Page 12: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Inversion Of Control (IOC)

Page 13: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

PHP DI Containers

• Symfony Dependency Injection• Yadif_Container• Seasar DI Container (S2Container)• Phemto• Xyster_Container• TYPO3 • ...........

Page 14: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Symfony DI Container

• Поддержка XML, YAML, PHP и INI конфигураций• Ленивая загрузка• Constructor and Method Injection• Shared/NotShared ресурсы• Конфигураторы• Алиасы

Page 15: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Замена контейнера

require_once 'Zend/Application.php';require_once 'sfServiceContainerBuilder.php';require_once 'sfServiceContainerLoaderFileXml.php';

//Create Container and load configuration from file$container = new sfServiceContainerBuilder();$loader = new sfServiceContainerLoaderFileXml($container);$loader->load(APPLICATION_PATH . '/configs/dependencies.xml');

// Create application, bootstrap, and run$application = new Zend_Application(    APPLICATION_ENV,    APPLICATION_PATH . '/configs/application.ini');$application->getBootstrap()->setContainer($container);$application->bootstrap()            ->run();

Page 16: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Dependencies.xml <?xml version="1.0" encoding="UTF-8"?><container xmlns="http://symfony-project.org/2.0/container">

        <services>            <service id="userMapper" class="UserMapperImpl"/>                <service id="PostMapper" class="PostMapperImpl"/>                <service id="CommentMapper" class="CommentMapperImpl" />

                <service id="postService" class="PostServiceImpl">                        <call method="setUserMapper">                                <argument type="service" id="userMapper" />                        </call>                        <call method="setPostMapper">                                <argument type="service" id="postMapper" />                        </call>                        <call method="setCommentMapper">                                <argument type="service" id="commentMapper" />                        </call>                </service>         <service id="userService" class="UserServiceImpl">                        <call method="setUserMapper">                                <argument type="service" id="userMapper" />                        </call>                </service>        </services> </container>

Page 17: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)
Page 18: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

//[..................] /**  * Inject properties on Pre-Dispatch  */public function preDispatch(){        $actionController = $this->getActionController();

        $class = new Zend_Reflection_Class($actionController);        $properties = $class->getProperties();

        /* @var $property Zend_Reflection_Property */        foreach ($properties as $property) {                if ($property->getDocComment()->hasTag('Inject')) {                        $injectTag = $property->getDocComment()->getTag('Inject');                        $serviceName = $injectTag->getDescription();                         if (empty($serviceName)) {                                $serviceName = $this->_formatServiceName(                                        $property->getName());          }           if (isset($this->_сontainer->$serviceName)) {                                $this->_injectProperty(                                        $property,                                         $this->_container->$serviceName              );          }       }    }

}

Page 19: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Инъекция через аннотацииclass UserController extends Zend_Controller_Action{    /**     * Logger     * @var Zend_Log     * @Inject     */    private $_log;

    public function setLog($log)  {        $this->_log = $log;    }

    public function indexAction()    {        $this->_log->log('Index Action', Zend_Log::INFO);    }

    public function secondAction()    {        $this->_log->log('Second Action', Zend_Log::INFO);    }

}

Page 20: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Проблемы, советы, размышления

Транзакции, сквозная функциональность

Page 21: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Транзакции

• Транзакции недоступны в сервисном слое в нашей реализации

• Транзакции это уровень сервисов.

• Может быть несколько источников данных.

Page 22: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Общий интерфейс транзакций

interface TransactionManager{    /**     * Start a new transaction     * @return unknown_type     */    public function beginTransaction();     /**     * Commit the current transaction     * @return unknown_type     */    public function commit();     /**     * Rollback the current transcation     * @return unknown_type     */    public function rollback(); }

Page 23: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Использование нескольких менеджеров транзакций

class MultipleTransactionManager implements TransactionManager{    private $tms = array();     public function setTransactionManagers(array $tms)    {        $this->tms = $tms;        return $this;    }     public function beginTransaction()    {        /* @var $tm TransactionManager */        foreach ($this->tms as $tm) {            $tm->beginTransaction();        }    }     //[.....] }

Page 24: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Сквозная функциональность

Page 25: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)
Page 26: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Аспектно-ориентированное программирование (АОП)

Page 27: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Динамические прокси

class SomeClass{    public function someMethod() {}}

class __GeneratedDynamicProxy__ extends SomeClass{    private $proxyManager;     public function someMethod()    {        return $this->proxyManager->invoke(new ReflectionMethod(            get_parent_class($this),            __FUNCTION__        ));    }}

Page 28: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Добавим Аннотаций

public function someMethod(){    $this->log(__METHOD__ . ' start');    if ($this->user->role != 'ROLE_ADMIN') {        throw new SecuredException($this->user->role);    }    $tm = $this->tm;    $tm->beginTransaction();    try {        doBusiness();        $tm->commit();    } catch (Exception $e) {        $tm->rollback(); throw $e;    }    $this->log(__METHOD__ . ' end');}

/**  * Some business method   * @Transactional  * @Log  * @Secured ROLE_ADMIN  */public function someMethod(){    doBusiness();}

Page 29: ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)

Хорошая архитектура —                Простота конфигурации<service id="actionHelperStack"          class="Zend_Controller_Action_HelperBroker"         constructor="getStack">    <call method="push">        <argument type="service">                <service class="Zend_Controller_Action_Helper_ViewRenderer">                 <argument type="service" id="view"/>             </service>        </argument>    </call>    <call method="push">        <argument type="service">                <service class="My_Controller_Action_Helper_DI"/> </argument>    </call></service>