ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)
Upcoming SlideShare
Loading in...5
×
 

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

on

  • 837 views

 

Statistics

Views

Total Views
837
Views on SlideShare
837
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • * Instead of your program running the system, the system runs your program * Controller

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

  • 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 >