Pull to refresh

Создание простого доступа к ресурсам из ZF контроллера

Reading time5 min
Views501
Было бы очень хорошо иметь возможность доступа к загружаемым в bootstrap ресурсам из контроллеров приложения. Например, я хотел бы получить доступ к «DB» ресурсу из контроллера следующим образом $this->db;
Для этого напишем Action Helper, который будет загружать определенные ресурсы в контроллер приложения:
class My_ResourceInjector extends Zend_Controller_Action_Helper_Abstract
{
  protected $_resources;

  public function __construct(array $resources = array())
  {
    $this->_resources = $resources;
  }

  public function preDispatch()
  {
    $bootstrap = $this->getBootstrap();
    $controller = $this->getActionController();
    foreach ($this->_resources as $name) {
      if ($bootstrap->hasResource($name)) {
        $controller->$name = $bootstrap->getResource($name);
      }
    }
  }

  public function getBootstrap()
  {
    return $this->getFrontController()->getParam('bootstrap');
  }
}


* This source code was highlighted with Source Code Highlighter.


и инициализируем его в bootstrap:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
  protected function _initResourceInjector()
  {
    Zend_Controller_Action_HelperBroker::addHelper(
      new My_ResourceInjector(array(
        'db',
        'layout',
        'navigation',
      ));
    );
  }
}


* This source code was highlighted with Source Code Highlighter.

Код выше, создаст ссылки на ресурсы: db, layout и navigation. Это значит, что теперь вы можете получить к ним прямой доступ из контроллеров.
class FooController extends Zend_Controller_Action
{
  public function barAction()
  {
    $this->layout->disableLayout();
    $model = $this->getModel();
    $model->setDbAdapter($this->db);
    $this->view->assign(
      'model'   => $this->model,
      'navigation' => $this->navigation,
    );
  }

  // ...
}


* This source code was highlighted with Source Code Highlighter.

Этото решение ведет к некоторому упрощению — теперь нет необходимости вытягивать bootstrap из объекта инициализации, а потом вытягивать ресурс.
Но, у этого решения есть несколько проблем: Откуда мы знаем, какие ресурсы были связаны с контроллером? Как мы можем это контролировать?
Отсюда, вытекает решение создать пул необходимых ресурсов для контроллера.

Новый Action Helper загрузки ресурсов теперь будет выглядеть так:
class My_ResourceInjector extends Zend_Controller_Action_Helper_Abstract
{
  protected $_resources;

  public function preDispatch()
  {
    $bootstrap = $this->getBootstrap();
    $controller = $this->getActionController();

    if (!isset($controller->dependencies)
      || !is_array($controller->dependencies)
    ) {
      return;
    }

    foreach ($controller->dependencies as $name) {
      if ($bootstrap->hasResource($name)) {
        $controller->$name = $bootstrap->getResource($name);
      }
    }
  }

  public function getBootstrap()
  {
    return $this->getFrontController()->getParam('bootstrap');
  }
}


* This source code was highlighted with Source Code Highlighter.

Вы все еще должны зарегистрировать его в bootstrap, но теперь уже без указанаия списка ресурсов:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
  protected function _initResourceInjector()
  {
    Zend_Controller_Action_HelperBroker::addHelper(
      new My_ResourceInjector();
    );
  }
}


* This source code was highlighted with Source Code Highlighter.

Вместо этого, необходимый список ресурсовы вы теперь определяете в самом контроллере:
class FooController extends Zend_Controller_Action
{
  public $dependencies = array(
    'db',
    'layout',
    'navigation',
  );

  public function barAction()
  {
    $this->layout->disableLayout();
    $model = $this->getModel();
    $model->setDbAdapter($this->db);
    $this->view->assign(
      'model'   => $this->model,
      'navigation' => $this->navigation,
    );
  }

  // ...
}


* This source code was highlighted with Source Code Highlighter.

Это создает более четкое понимание какие ресурсы необходимы контроллеру, а также, каждый контроллер получает именно те ресурсы, которые он будет использовать.

Еще одно улучшение, которое мы можем добавить к загрузчику ресурсов — это, если зависимый ресурс не был найден, будет вызвано исключение:
class My_ResourceInjector extends Zend_Controller_Action_Helper_Abstract
{
  protected $_resources;

  public function preDispatch()
  {
    $bootstrap = $this->getBootstrap();
    $controller = $this->getActionController();

    if (!isset($controller->dependencies)
      || !is_array($controller->dependencies)
    ) {
      return;
    }

    foreach ($controller->dependencies as $name) {
      if (!$bootstrap->hasResource($name)) {
        throw new DomainException("Unable to find dependency by name '$name'");
      }
      $controller->$name = $bootstrap->getResource($name);
    }
  }

  public function getBootstrap()
  {
    return $this->getFrontController()->getParam('bootstrap');
  }
}


* This source code was highlighted with Source Code Highlighter.


Это дает нам лучшение понимание и отслеживания зависимых ресурсов. Ресурсы определяются объектом, который в них нуждается, а недостающие ресурсы будут вызывать исключение.

Одно потенциальное улучшение, которое можно сделать, это указание списока ресурсов загружаемых автоматически для каждого контроллера. Для реализации этого, необходимо будет объеденить список по умолчанию с ресурсами определенными в контроллрере. Эту задачу я оставляю для моих читателей.

Область Action Helpers является слабо исследованной ZF пользователями. Надеюсь, этот пост покажет как сильно Action Helpers могут автоматизировать повторяемые и общте задачи.

Эта статья является частичным перевод статьи Matthew Weier O'Phinney A Simple Resource Injector for ZF Action Controllers.
Tags:
Hubs:
Total votes 12: ↑6 and ↓60
Comments19

Articles