Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Dependency Injection (Внедрение Зависимостей) ZF, Zend_Application, DI Container, Symfony DI 27 марта 2010 г. Санкт-Петербург
Кирилл Чебунин Ведущий  PHP  разработчик  Equelli, ltd. Около 4 лет опыта  PHP Более 2х лет использования  ZendFramework О Докладчике
Выбор классов Адаптеры Плагины/Хелперы Интерфейсы и Реализация
Хранилище  
$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);      } }
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);      } }    
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);      } }
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 {      //[.....] } //[.....] //[.....] //[.....]
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;      } }
Конфигурация вместо кода < service   id = &quot;log&quot;   class = &quot;Zend_Log&quot;   constructor = &quot;factory&quot; > < argument   type = &quot;collection&quot; >                  < argument   key = &quot;file&quot;   type = &quot;collection&quot; >                          < argument   key = &quot;writerName&quot; > Stream </ argument >                          < argument   key = &quot;writerParams&quot;   type = &quot;collection&quot; >                                  < argument   key = &quot;stream&quot; > /var/log/myapp.log </ argument >                          </ argument >                  </ argument >          </ argument > </ service > < service   id = &quot;log&quot;   class = &quot;Zend_Log&quot; >          < call   method = &quot;addWriter&quot; >                  < argument   type = &quot;service&quot; >                          < service   class = &quot;Zend_Log_Writer_Stream&quot; >                                  < argument > /var/log/myapp.log </ argument >                          </ service >                  </ argument >            </ call > </ service >
Dependency Injection —    A specific form of Inversion of Control (IOC) Взято из ®Wikipedia, the free encyclopedia Внедрение зависимости —         Специфическая форма «обращения контроля»
Inversion Of Control (IOC)
PHP DI Containers Symfony Dependency Injection Yadif_Container Seasar DI Container (S2Container) Phemto Xyster_Container TYPO3  ...........
Symfony DI Container Поддержка  XML, YAML, PHP  и  INI  конфигураций Ленивая загрузка Constructor and Method Injection Shared/NotShared  ресурсы Конфигураторы Алиасы
Замена контейнера 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();
Dependencies.xml   <? xml   version = &quot;1.0&quot;   encoding = &quot;UTF-8&quot; ?> < container   xmlns = &quot;http://symfony-project.org/2.0/container&quot; >          < services >               < service   id = &quot;userMapper&quot;   class = &quot;UserMapperImpl&quot; />                  < service   id = &quot;PostMapper&quot;   class = &quot;PostMapperImpl&quot; />                  < service   id = &quot;CommentMapper&quot;   class = &quot;CommentMapperImpl&quot;   />                    < service   id = &quot;postService&quot;   class = &quot;PostServiceImpl&quot; >                          < call   method = &quot;setUserMapper&quot; >                                  < argument   type = &quot;service&quot;   id = &quot;userMapper&quot;   />                          </ call >                          < call   method = &quot;setPostMapper&quot; >                                  < argument   type = &quot;service&quot;   id = &quot;postMapper&quot;   />                          </ call >                          < call   method = &quot;setCommentMapper&quot; >                                  < argument   type = &quot;service&quot;   id = &quot;commentMapper&quot;   />                          </ call >                  </ service >            < service   id = &quot;userService&quot;   class = &quot;UserServiceImpl&quot; >                          < call   method = &quot;setUserMapper&quot; >                                  < argument   type = &quot;service&quot;   id = &quot;userMapper&quot;   />                          </ call >                  </ service >          </ services >   </ container >
 
//[..................]  /**    * 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                );            }         }      } }
Инъекция через аннотации 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);      } }
Проблемы, советы, размышления Транзакции, сквозная функциональность
Транзакции Транзакции недоступны в сервисном слое в нашей реализации Транзакции это уровень сервисов. Может быть несколько источников данных.
Общий интерфейс транзакций 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();   }
Использование нескольких менеджеров транзакций 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();          }      }        //[.....]   }
Сквозная функциональность
 
Аспектно-ориентированное программирование (АОП)
Динамические прокси 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__          ));      } }
Добавим Аннотаций 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(); }
Хорошая архитектура  —                  Простота конфигурации < service   id = &quot;actionHelperStack&quot;              class = &quot;Zend_Controller_Action_HelperBroker&quot;            constructor = &quot;getStack&quot; >      < call   method = &quot;push&quot; >          < argument   type = &quot;service&quot; >                  < service   class = &quot;Zend_Controller_Action_Helper_ViewRenderer&quot; >                    < argument   type = &quot;service&quot;   id = &quot;view&quot; />                </ service >          </ argument >      </ call >      < call   method = &quot;push&quot; >          < argument   type = &quot;service&quot; >                  < service   class = &quot;My_Controller_Action_Helper_DI&quot; /> </ argument >      </ call > </ service >

More Related Content

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

  • 1. Dependency Injection (Внедрение Зависимостей) ZF, Zend_Application, DI Container, Symfony DI 27 марта 2010 г. Санкт-Петербург
  • 2. Кирилл Чебунин Ведущий PHP разработчик Equelli, ltd. Около 4 лет опыта PHP Более 2х лет использования ZendFramework О Докладчике
  • 3. Выбор классов Адаптеры Плагины/Хелперы Интерфейсы и Реализация
  • 5. $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);     } }
  • 6. 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);     } }    
  • 7. Zend_Application [production] resources.log.file.writerName = &quot;Stream&quot; resources.log.file.writerParams.stream = &quot;/var/log/myapp.log&quot; 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);     } }
  • 8. 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 {      //[.....] } //[.....] //[.....] //[.....]
  • 9. 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;     } }
  • 10. Конфигурация вместо кода < service id = &quot;log&quot; class = &quot;Zend_Log&quot; constructor = &quot;factory&quot; > < argument type = &quot;collection&quot; >                  < argument key = &quot;file&quot; type = &quot;collection&quot; >                          < argument key = &quot;writerName&quot; > Stream </ argument >                          < argument key = &quot;writerParams&quot; type = &quot;collection&quot; >                                  < argument key = &quot;stream&quot; > /var/log/myapp.log </ argument >                          </ argument >                  </ argument >          </ argument > </ service > < service id = &quot;log&quot; class = &quot;Zend_Log&quot; >          < call method = &quot;addWriter&quot; >                  < argument type = &quot;service&quot; >                          < service class = &quot;Zend_Log_Writer_Stream&quot; >                                  < argument > /var/log/myapp.log </ argument >                          </ service >                  </ argument >          </ call > </ service >
  • 11. Dependency Injection —   A specific form of Inversion of Control (IOC) Взято из ®Wikipedia, the free encyclopedia Внедрение зависимости —       Специфическая форма «обращения контроля»
  • 13. PHP DI Containers Symfony Dependency Injection Yadif_Container Seasar DI Container (S2Container) Phemto Xyster_Container TYPO3 ...........
  • 14. Symfony DI Container Поддержка XML, YAML, PHP и INI конфигураций Ленивая загрузка Constructor and Method Injection Shared/NotShared ресурсы Конфигураторы Алиасы
  • 15. Замена контейнера 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();
  • 16. Dependencies.xml <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < container xmlns = &quot;http://symfony-project.org/2.0/container&quot; >         < services >             < service id = &quot;userMapper&quot; class = &quot;UserMapperImpl&quot; />                 < service id = &quot;PostMapper&quot; class = &quot;PostMapperImpl&quot; />                 < service id = &quot;CommentMapper&quot; class = &quot;CommentMapperImpl&quot; />                 < service id = &quot;postService&quot; class = &quot;PostServiceImpl&quot; >                         < call method = &quot;setUserMapper&quot; >                                 < argument type = &quot;service&quot; id = &quot;userMapper&quot; />                         </ call >                         < call method = &quot;setPostMapper&quot; >                                 < argument type = &quot;service&quot; id = &quot;postMapper&quot; />                         </ call >                         < call method = &quot;setCommentMapper&quot; >                                 < argument type = &quot;service&quot; id = &quot;commentMapper&quot; />                         </ call >                 </ service >           < service id = &quot;userService&quot; class = &quot;UserServiceImpl&quot; >                         < call method = &quot;setUserMapper&quot; >                                 < argument type = &quot;service&quot; id = &quot;userMapper&quot; />                         </ call >                 </ service >         </ services >   </ container >
  • 17.  
  • 18. //[..................] /**   * 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               );           }        }     } }
  • 19. Инъекция через аннотации 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);     } }
  • 20. Проблемы, советы, размышления Транзакции, сквозная функциональность
  • 21. Транзакции Транзакции недоступны в сервисном слое в нашей реализации Транзакции это уровень сервисов. Может быть несколько источников данных.
  • 22. Общий интерфейс транзакций 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();   }
  • 23. Использование нескольких менеджеров транзакций 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();         }     }       //[.....]   }
  • 25.  
  • 27. Динамические прокси 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__         ));     } }
  • 28. Добавим Аннотаций 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(); }
  • 29. Хорошая архитектура —                 Простота конфигурации < service id = &quot;actionHelperStack&quot;            class = &quot;Zend_Controller_Action_HelperBroker&quot;            constructor = &quot;getStack&quot; >      < call method = &quot;push&quot; >          < argument type = &quot;service&quot; >                  < service class = &quot;Zend_Controller_Action_Helper_ViewRenderer&quot; >                  < argument type = &quot;service&quot; id = &quot;view&quot; />              </ service >          </ argument >      </ call >      < call method = &quot;push&quot; >          < argument type = &quot;service&quot; >                  < service class = &quot;My_Controller_Action_Helper_DI&quot; /> </ argument >      </ call > </ service >

Editor's Notes

  1. * Instead of your program running the system, the system runs your program * Controller