Я пытаюсь внедрить диспетчер служб в контроллер.
Фактическая ошибка:
\ Поставщика \ ZendFramework \ Зенд-ServiceManager \ SRC \ Exception \ ServiceLocatorUsageException.php: 34
Служба «Project \ Service \ ProjectServiceInterface» была запрошена для менеджера плагинов типа «Zend \ Mvc \ Controller \ ControllerManager», но не может быть получена.
Предыдущее исключение типа «Zend \ ServiceManager \ Exception \ ServiceNotFoundException» возникло в процессе.
Кстати, служба с именем «Project \ Service \ ProjectServiceInterface» была найдена в родительском локаторе службы «Zend \ ServiceManager \ ServiceManager»: вы забыли использовать $ parentLocator = $ serviceLocator-> getServiceLocator () на своей фабрике код?
Процесс идет:
class BaseController extends AbstractActionController implements ServiceLocatorAwareInterface
{
public function __construct(\Zend\ServiceManager\ServiceLocatorInterface $sl)
{
$this->serviceLocator = $sl;
}
}
BaseController
в AdminController
AdminController => /admin
использование Module.php
public function getControllerConfig()
Используйте ближе как фабрика для создания объекта контроллера, внедряющего serviceLocator
‘Project \ Controller \ Project’ => функция ($ sm) {
$ serviceLocator = $ sm-> getServiceLocator ();
return new \ Project \ Controller \ ProjectController ($ serviceLocator);
},
$this->getServiceLocator()->get('service_name')
Теперь проблема заключается в следующем:
/**
*
* @param ServiceLocatorInterface $sl
*/
public function __construct(\Zend\ServiceManager\ServiceLocatorInterface $sl)
{
$rtn = $sl->has('Project\Service\ProjectServiceInterface');
echo '<br />in Constructor: '.__FILE__;var_dump($rtn);
$this->serviceLocator = $sl;
}
public function getServiceLocator()
{
$rtn = $this->serviceLocator->has('Project\Service\ProjectServiceInterface');
echo '<br />in getServiceLocator: '.__FILE__;var_dump($rtn);
return $this->serviceLocator;
}
В пределах __конструктор() сервис НАЙДЕН. В пределах getServiceLocator () метод службы с тем же именем НЕ НАЙДЕН….
в конструкторе: Project \ Controller \ BaseController.php
BOOL (истина)
в getServiceLocator: Project \ Controller \ BaseController.php
BOOL (ложь)
Я что-то пропустил? SharedServiceManager что-то делает здесь?
Вся цель этого упражнения была связана с этим сообщением:
Устаревший: ServiceLocatorAwareInterface устарел и будет удален в версии 3.0 вместе с ServiceLocatorAwareInitializer. …
В Zend Framework 2 есть несколько сервисных локаторов (документы здесь), один общий (в основном используется для ваших собственных служб), один для контроллеров, один для помощников представления, один для валидаторов, … Конкретные также называются менеджеры плагинов.
Сообщение об ошибке, которое вы получаете, просто говорит вам, что вы используете неправильный локатор службы, который извлекает контроллеры, а не общий. Он также предлагает вам, как решить вашу проблему:
Вы забыли использовать $ parentLocator = $ serviceLocator-> getServiceLocator () в вашем заводском коде
Вероятно, происходит (не уверен на 100%), что в конструкторе вы передаете экземпляр общего менеджера сервисов, и с ним все отлично работает. Затем, поскольку контроллер реализует ServiceLocatorAwareInterface
, локатор службы контроллера вводится в ваш контроллер, переопределяя тот, который вы определили ранее.
Более того, я думаю, что идея обойдется без решения о ServiceLocatorAwareInterface
в версии 3
в том, что вы не внедряете указатель службы в свой контроллер, а вместо этого вводите непосредственно зависимости контроллера.
Если вам действительно нужен ServiceLocator, вы должны ввести его с завода
Что-то вроде этого
контроллер:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\ServiceManager\ServiceLocatorInterface;
class BaseController extends AbstractActionController
{
protected $serviceLocator = null;
public function __construct(ServiceLocatorInterface $serviceLocator)
{
$this->setServiceLocator($serviceLocator);
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
Фабрика:
<?php
namespace Application\Controller\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Controller\BaseController;
class BaseControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator);
{
$controller = new BaseController($serviceLocator->getServicelocator());
return $controller;
}
}
?>
в module.config.php
<?php
// ...
'controllers' => [
'factories' => [
'Application\Controller\BaseController' => 'Application\Controller\Factory\BaseControllerFactory',
// ...
],
// ...
Вы должны попытаться предотвратить внедрение сервис-менеджера или сервис-локатора в контроллер. Было бы намного лучше ввести фактические зависимости (в вашем случае 'Project\Service\ProjectServiceInterface'
) прямо в __construct
метод вашего класса. Конструктор инъекций (зависимости предоставляются через конструктор класса) считается лучшей практикой в ZF2.
Этот шаблон предотвращает создание экземпляра контроллера без ваших зависимостей (он выдаст ошибку).
Если вы вводите ServiceLocator
или же ServiceManager
из которого вы будете разрешать фактические зависимости в классе, тогда неясно, что на самом деле нужно классу. Вы можете оказаться в экземпляре класса с отсутствующими зависимостями, которые никогда не должны были создаваться. Вам нужно выполнить пользовательскую проверку внутри класса, чтобы увидеть, доступна ли фактическая зависимость, и выдать ошибку, если она отсутствует. Вы можете предотвратить написание всего этого пользовательского кода, используя шаблон зависимости конструктора.
Другая проблема заключается в том, что сложнее провести юнит-тестирование вашего класса, поскольку вы не можете установить макеты для ваших индивидуальных зависимостей Так легко.
Узнайте больше о том, как внедрить ваши зависимости в моем ответе на похожий вопрос.
О проблеме, с которой вы столкнулись. Классы контроллера реализуют ServiceLocatorAwareInterface
и во время строительства ваших контроллеров классов ControllerManager
вводит ServiceLocator
внутри класса. Бывает здесь, в injectServiceLocator
метод в строке 208 в ControllerManager.php
. Как @marcosh уже упоминал в своем ответе, это может быть другой локатор службы, чем вы вводили. В этом injectServiceLocator
Кроме того, вы также найдете уведомление об устаревании, которое вы упомянули в своем вопросе.
Ваш доступен в __construct
метод, потому что в это время (сразу после создания класса) переменная еще не перезаписывается. Позже, когда вы попытаетесь получить к нему доступ в своем getServiceLocator
Метод перезаписан.