Этот вопрос явно не касается ZF2, но я часто беру вопросы от ZF2 для своего кода. Тем не менее, большинство примеров ZF2, которые я видел, вводили в процесс внутри действия контроллера.
Пример:
class YourController extends AbstractActionController
{
public function doStuffAction()
{
// ZF2's way to get input from $_GET variable
$product = $this->getEvent()->getRouteMatch()->getParam('product');
// Process
$processor = (new ProcessorFactory())->getProcessor($product);
$output = $processor->processInput($data);
}
}
Теперь я бы лайк ввести Processor
в мой контроллер. Не создавайте его внутри контроллера, как я делаю выше. Но с тех пор Processor
зависит от знания $product
который получен только от $_GET
Я не вижу другого пути.
Если я хочу ввести Processor
в контроллер, я должен переместить строку, которая заполняет $product
переменная вне контроллера.
Как я могу сделать это, не нарушая ООП, ZF2, шаблонов дизайна? Как и у меня сложилось впечатление, что что-либо делать с $_GET
должно быть сделано внутри Controller
а не внутри ControllerFactory
, Разве возможно я смогу сломать этот паттерн?
Если вы просто хотите применить принцип инверсии зависимости. Применяя D из SOLID акроним, только несколько изменений необходимы.
class YourController
{
/**
* @var ProcessorFactory
*/
protected $processorFactory;
public function __construct(ProcessorFactory $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function doStuffAction()
{
$product = $this->getEvent()->getRouteMatch()->getParam('product');
$processor = $this->processorFactory->getProcessor($product);
}
}
Вы могли бы улучшить, напечатав на яnterface (SOLяD)
class YourController
{
/**
* @var ProcessorFactoryInterface
*/
protected $processorFactory;
public function __construct(ProcessorFactoryInterface $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function doStuffAction()
{
$product = $this->getEvent()->getRouteMatch()->getParam('product');
$processor = $this->processorFactory->getProcessor($product);
}
}
Теперь, если вы не хотите, чтобы ваш контроллер отвечал за запуск процесса создания (SOLID), вы можете разделить его еще немного.
class YourController
{
/**
* @var ProcessorInterface
*/
protected $processor;
public function __construct(ProcessorInterface $processor)
{
$this->processor = $processor;
}
public function doStuffAction()
{
$processor = $this->processor;
}
}
class ControllerFactory
{
/**
* @var ProcessorFactory
*/
protected $processorFactory;
public function __construct(ProcessorFactory $processorFactory)
{
$this->processorFactory = $processorFactory;
}
public function create()
{
return new YourController($this->processorFactory->getProcessor());
}
}
class ProcessorFactory
{
/**
* @var RouteMatch
*/
protected $routeMatch;
public function __construct(RouteMatch $routeMatch)
{
$this->routeMatch = $routeMatch;
}
public function getProcessor()
{
$processor = $this->createProcessor();
// do stuff
return $processor;
}
protected function createProcessor()
{
$product = $this->routeMatch->getParam('product');
// create processor
return $processor;
}
}
Следующий код даст вам ваш контроллер.
$controllerFactory = new ControllerFactory(new ProcessorFactory(new RouteMatch()));
$yourController = $controllerFactory->create();
Теперь приведенный выше код является более общим кодом и не адаптирован для ZF2. В таком случае хорошим шагом было бы привлечь менеджера по обслуживанию ZF2.
class YourController extends AbstractActionController
{
/**
* @var ProcessorInterface
*/
protected $processor;
public function __construct(ProcessorInterface $processor)
{
$this->processor = $processor;
}
public function doStuffAction()
{
$processor = $this->processor;
}
}
class YourControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $controllers)
{
$services = $controllers->getServiceLocator();
$processorFactory = $services->get('ProcessorFactory');
return new YourController($processorFactory->getProcessor());
}
}
class ProcessorFactory
{
/**
* @var RouteMatch
*/
protected $routeMatch;
public function __construct(RouteMatch $routeMatch)
{
$this->routeMatch = $routeMatch;
}
public function getProcessor()
{
$processor = $this->createProcessor();
// do stuff
return $processor;
}
protected function createProcessor()
{
$product = $this->routeMatch->getParam('product');
// create processor
return $processor;
}
}
class ProcessorFactoryFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $services)
{
return new ProcessorFactory($services->get('RouteMatch'));
}
}
Выше сервисы / контроллеры и их фабрики должны быть зарегистрированы в их ServiceManager / ControllerManager
$config = [
'controllers' = [
'factories' [
'YourController' => 'YourControllerFactory',
],
],
'service_manager' = [
'factories' [
'ProcessorFactory' => 'ProcessorFactoryFactory',
],
],
];
Когда запрос отправляется в YourController, ControllerManager возвращает экземпляр YourController с введенным процессором. Какой процессор он получит, зависит от запроса (параметр внутри RouteMatch).
Других решений пока нет …