Сервисный локатор в Zend Framework 2

В контроллере я создаю и использую свою модель так

public function getAlbumTable()
{
    if (!$this->albumTable) {
        $sm = $this->getServiceLocator();
        $this->albumTable = $sm->get('Album\Model\AlbumTable');
    }
    return $this->albumTable;
}

Как мне использовать этот глобальный Service Locator в другом месте моего проекта, например, в другой модели, а не только в каком-либо контроллере?

Настройка подключения к базе данных определяется в файле: my_project / config / autoload / global.php

Спасибо.

Ответы на вопрос(3)

реализующий Zend \ ServiceManager \ ServiceLocatorAwareInterface. Простая реализация для таблицы моделей выглядит следующим образом:

<!--?php
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class UserTable extends AbstractTableGateway implements ServiceLocatorAwareInterface {
  protected $serviceLocator;

  public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
    $this--->serviceLocator = $serviceLocator;
  }

  public function getServiceLocator() {
    return $this->serviceLocator;
  }

  // now instance of Service Locator is ready to use
  public function someMethod() {
    $table = $this->serviceLocator->get('Album\Model\AlbumTable');
    //...
  }
}
 Eremite08 окт. 2012 г., 13:44
Я понял суть вашего метода. Непонятно, как заставить ServiceManager автоматически вызывать метод setServiceManager при создании экземпляра формы, расширяющего класс Form, который вы описываете в своем блоге. Вы пишете необходимость использовать массивinvokables' для ServiceManager, не могли бы вы подробно рассказать, как это сделать. Спасибо.
 Eremite07 окт. 2012 г., 20:57
Ну, спасибо, это действительно работает! А как быть с классами, отличными от class extends AbstractTableGateway, например с классами форм (extends Zend \ Form), классами элементов (extends Zend \ Form \ Element)? Как использовать ServiceLocator там? Или использовать это есть плохая идея? ..
 DrBeza08 окт. 2012 г., 12:07
Если класс создается с помощью ServiceManager, который реализует осведомленный интерфейс, то ServiceManager внедряется после создания класса. Для Zend \ Form это может представлять проблему, так как большая часть настройки элементов обычно выполняется в конструкторе (SM вставляется после этой точки). Об этом есть сообщение в блоге -michaelgallego.fr/blog/?p=205
Решение Вопроса

ализовать интерфейс ServiceLocatorAwareInterface. Так что инъекция ServiceManager произойдет в вашей модели автоматически. Смотрите предыдущий пример.

Для форм и других объектов вашего приложения подходит метод, предложенный здесьhttp://michaelgallego.fr/blog/?p=205 Вы можете создать форму базового класса, расширяет BaseForm и реализует ServiceManagerAwareInterface, от которого вы будете наследовать его формы в приложении.

namespace Common\Form;

use Zend\Form\Form as BaseForm;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;

class Form extends BaseForm implements ServiceManagerAwareInterface
{
    /**
     * @var ServiceManager
     */
    protected $serviceManager;

    /**
     * Init the form
     */
    public function init()
    {
    }

    /**
     * @param ServiceManager $serviceManager
     * @return Form
     */
    public function setServiceManager(ServiceManager $serviceManager)
    {
        $this->serviceManager = $serviceManager;

        // Call the init function of the form once the service manager is set
        $this->init();

        return $this;
    }
}

Чтобы внедрение объекта ServiceManager было автоматически в файле module.config.php, в разделе service_manager необходимо написать

'invokables' => array(
    'Album\Form\AlbumForm' => 'Album\Form\AlbumForm',
),

Затем в вашем контроллере вы можете создать форму так

$form = $this->getServiceLocator()->get('Album\Form\AlbumForm');

Форма будет содержать объект ServiceManager, который разрешит другие зависимости.

Спасибо всем за вашу помощь.

getServicelocator() делает ошибку. Так что нужен альтернативный путь. И расширяетсяAbstractTableGateway или жеServiceLocatorAwareInterface есть ошибки.

Фабричная реализация поможет Controller получить объекты.

* Пример кода пользователя будет похож на альбом.

1) фабричный класс (RegisterControllerFactory.php) * скопированная функция createUser в контроллере

namespace Users\Controller\Factory;

use Users\Controller\RegisterController;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;


class RegisterControllerFactory   
{

    public function __invoke($serviceLocator)
    {  
    $sm = $serviceLocator;
    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');

    $resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(new \Users\Model\User);
    $tableGateway       = new \Zend\Db\TableGateway\TableGateway('user' /* table name  */, $dbAdapter, null, $resultSetPrototype);

    $user = new \Users\Model\User();  
    $userTable = new \Users\Model\UserTable($tableGateway);

    $controller = new RegisterController($userTable, $serviceLocator );
    return $controller;

   }
} 

2) пространство имен контроллера (RegisterController) Users \ Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

use Users\Form\RegisterForm;
use Users\Form\RegisterFilter;

use Users\Model\User;
use Users\Model\UserTable;

use Zend\ServiceManager\ServiceLocatorInterface;

class RegisterController extends AbstractActionController
{
    protected $userTable;
    protected $serviceManager;

    public function __construct(UserTable $userTable, ServiceLocatorInterface     $serviceManager)
{
    $this->userTable = $userTable;
    $this->serviceManager = $serviceManager;
}

public function indexAction()
{
    $form = new RegisterForm();
    $viewModel  = new ViewModel(array('form' => $form)); 
    return $viewModel; 
}

public function processAction()
{
    if (!$this->request->isPost()) {
        return $this->redirect()->toRoute(NULL , array( 
                    'controller' => 'register', 
                    'action' =>  'index' 
                ));
    }

    $post = $this->request->getPost();

    $form = new RegisterForm();
    $inputFilter = new RegisterFilter();
    $form->setInputFilter($inputFilter);

    $form->setData($post);
    if (!$form->isValid()) {
        $model = new ViewModel(array(
            'error' => true,
            'form'  => $form,
        ));
        $model->setTemplate('users/register/index');
        return $model;
    }

    // Create user
    $this->createUser($form->getData());

    return $this->redirect()->toRoute(NULL , array( 
                    'controller' => 'register', 
                    'action' =>  'confirm' 
                ));
}

public function confirmAction()
{
    $viewModel  = new ViewModel(); 
    return $viewModel; 
}

protected function createUser(array $data)
{  /*able to delete or modify */
    $sm = $this->serviceManager;
    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');

    $resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(new \Users\Model\User);
    $tableGateway       = new \Zend\Db\TableGateway\TableGateway('user' /* table name  */, $dbAdapter, null, $resultSetPrototype);

    $user = new User();
    $user->exchangeArray($data);

    $userTable = new UserTable($tableGateway);
    $userTable->saveUser($user);

    return true;
    }
}

3) module.config.php

return array(   
    'controllers' => array(
    'invokables' => array(
        'Users\Controller\Index' => 'Users\Controller\IndexController', 
        'Users\Controller\login' => 'Users\Controller\LoginController', 
        //delete 'Users\Controller\Register'
    ),
    'factories' => array(
            'Users\Controller\Register' =>     'Users\Controller\Factory\RegisterControllerFactory',
   ),       
),

Ваш ответ на вопрос