Zend Framework 2 Service Manager Внедрение зависимостей
Мое приложение представляет собой набор POPO, и я пытаюсь подключить эти POPO с помощью Zend Framework 2 Service Manager.
Чтобы проиллюстрировать мою проблему, возьмите следующий пример:
$config = array(
'services' => array(
'my.app.serviceA' => new \My\App\Services\ServiceA(),
'my.app.serviceB' => new \My\App\Services\ServiceB(),
'my.app.manager.task' => new \My\App\Manager\TaskManager(),
),
);
Мой класс TaskManager выглядит примерно так:
class TaskManager {
protected $serviceA;
protected $serviceB;
public function setServiceA( \My\App\Service\ServiceA $serviceA )
{
$this->serviceA = $serviceA;
}
public function setServiceB( \My\App\Service\ServiceB $serviceB )
{
$this->serviceB = $serviceB;
}
}
Как видите, TaskManager
класс зависит от обоих ServiceA
а также ServiceB
, Как внедрить эти услуги в my.app.manager.task
используя конфигурацию Service Manager, используя имена сервисов, определенные для обоих ServiceA
а также ServiceB
?
ОБНОВИТЬ:
Я начинаю верить, что мне вообще не следует использовать компонент ServiceManager для своих целей, но вместо этого я должен использовать компонент Zend DI.
У меня складывается впечатление, что ServiceManager является компонентом фреймворка ZF2, в то время как Zend\DI кажется более универсальным универсальным DiC. Следовательно, это может быть причиной связанных отношений ServiceManager с компонентами MVC и ModuleManager (которые также являются компонентами "каркаса").
Может быть, кто-то мог уточнить?
3 ответа
В module.config.php Диспетчер служб можно настроить 7 различными способами:
return array(
// instantiate the class for you when needed
'invokables' => array(
'commentController' => '\Comment\Controller\CommentController';
),
// Aliasing a name to a known service name
'aliases' => array(
'Comment\Service' => 'commentService';
),
// configure the instance of the object
'factories' => array(
'commentController' => function ($sm) {
$locator = $sm->getServiceLocator();
$controller = $locator->get('commentController');
$controller->setCommentService($locator->get('Comment\Service'));
return $controller;
}
),
// register already instantiated objects
'services' => array(
'commentController' => new \Comment\Controller\CommentController(),
),
//factory instance that can create multiple services based on the name supplied to the factory.
'abstract_factories' => array(
'SomeModule\Service\FallbackFactory',
),
// initialize the service whenever service created
'initializers' => array(
function ($instance, $sm) {
if ($instance instanceof \Comment\Controller\CommentController){
$instance->setCommentService($sm->get('Comment\Service'));
}
}
),
// indicating whether or not a service should be shared
'shared' => array(
'commentController' => false,
),
);
и в Module.php
public function getControllerConfig() {
return array(
'factories' => array(
'commentController' => function ($sm) {
$controller = new \Comment\Controller\CommentController();
$locator = $sm->getServiceLocator();
$controller->setCommentForm($locator->get('commentForm'));
$controller->setCommentService($locator->get('commentService'));
return $controller;
}
)
);
}
и простое использование в контроллере:
$commentService = $this->serviceLocator->get('Comment\Service');
Вы помещаете это в метод получения или в метод init() Новый контроллер ZF2::init():: phly, boy, phly
Для меня лучший способ - создать фабрику классов и использовать factoryInterface, например так:
return array(
'service_manager' => array(
'factories' => [
'Task' => 'Application\TaskFactory',
],
'invokables' => array(
'Task'=> 'Application\Task',
'ServiceA'=> 'Application\ServiceA',
'ServiceB' => 'Application\ServiceB'
)
),
);
И заводской класс:
class TaskFactory implements FactoryInterface {
/** @var ServiceLocatorInterface $serviceLocator */
var $serviceLocator;
public function createService(ServiceLocatorInterface $serviceLocator) {
$sl = $this->serviceLocator = $serviceLocator;
// you can get your registered services
$serviceA = $sl->get('ServiceA');
$serviceB = $sl->get('ServiceB');
// You can build your class using the class loader
$task = new Application\Task();
// Or the Service Locator Again
$task = $sl->get('Task');
return $task;
}
}
Вы можете реализовать фабричный интерфейс в своем классе Task. Я предпочитаю контролировать то, что я строю.
В контроллере;
$yourService = $this->getServiceLocator()->get('your_service_alias');
в View Helper: вы должны отправить из Module.php с помощью конструктора viewHelper
public function getViewHelperConfig() {
return array(
'factories' => array(
'loginHelper' => function($sm) {
return new LoginHelper($sm);
}
)
}
в искажении
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
public class UseCaseBO 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('your_service_alias');
//...
}
}