More Related Content Similar to ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection) Similar to ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection) (20) More from ZFConf Conference More from ZFConf Conference (20) ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency Injection)1. 27 марта 2010 г.
Санкт-Петербург
Dependency Injection
(Внедрение Зависимостей)
ZF, Zend_Application, DI Container, Symfony DI
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);
}
}
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="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>
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="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>
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);
}
}
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();
}
}
//[.....]
}
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() /**
{ * Some business method
$this->log(__METHOD__ . ' start'); * @Transactional
if ($this->user->role != 'ROLE_ADMIN') { * @Log
throw new SecuredException($this->user->role); * @Secured ROLE_ADMIN
} */
$tm = $this->tm; public function someMethod()
$tm->beginTransaction(); {
try { doBusiness();
doBusiness(); }
$tm->commit();
} catch (Exception $e) {
$tm->rollback();
throw $e;
}
$this->log(__METHOD__ . ' end');
}
29. Хорошая архитектура —
Простота конфигурации
<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>