我有一个工厂,在我的module.config.php文件中创建一个非共享服务和一个控制器工厂。这部分配置如下所示:
"service_manager" => [
"factories" => [
Entity\User::class => Factory\Entity\UserFactory::class
],
"shared" => [
Entity\User::class => false
]
],
"controllers" => [
"factories" => [
Controller\UserAdminController::class => Factory\Controller\UserAdminControllerFactory::class
]
]
用户实体是非共享的,因为我允许管理员同时添加多个用户,因此我需要实例化User实体类的多个实例。
这是我的控制器工厂:
<?php
namespace User\Factory\Controller\Core;
use User\Controller\UserAdminController;
use Interop\Container\ContainerInterface;
use User\Entity\User;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserAdminControllerFactory implements FactoryInterface{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
*
* @return UserAdminController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null){
$serviceLocator = $container->getServiceLocator();
return new UserAdminController($serviceLocator->get(User::class));
}
/**
* @param ServiceLocatorInterface $serviceLocator
*
* @return UserAdminController
*/
public function createService(ServiceLocatorInterface $serviceLocator){
return $this($serviceLocator, UserAdminController::class);
}
}
目前,它只在控制器的构造函数中注入User实体类的单个实例。但是,根据管理员想要做的事情,我需要一定数量的新实例。
一种可能的解决方案是通过调用控制器中的$this->getServiceLocator()->get(User::class)
来传递整个服务定位器并创建新实例,但这被认为是反模式。
这里的问题是如何使用UserFactory类在控制器中创建User的新实例?
EDIT1:添加UserFactory:
<?php
namespace User\Factory\Entity\Core;
use User\Entity\User;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserFactory implements FactoryInterface{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
*
* @return User
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null){
$urlHelper = $container->get("ViewHelperManager")->get("url");
return new User($urlHelper);
}
/**
* @param ServiceLocatorInterface $serviceLocator
*
* @return User
*/
public function createService(ServiceLocatorInterface $serviceLocator){
return $this($serviceLocator, User::class);
}
}
答案 0 :(得分:0)
最好的方法是将一个User实体的新实例注入控制器。控制器工厂应如下所示:
<?php
namespace User\Factory\Controller\Core;
use User\Controller\UserAdminController;
use Interop\Container\ContainerInterface;
use User\Entity\User;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserAdminControllerFactory implements FactoryInterface{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param array|null $options
*
* @return UserAdminController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null){
$serviceLocator = $container->getServiceLocator();
return new UserAdminController($serviceLocator->get(User::class));
}
/**
* @param ServiceLocatorInterface $serviceLocator
*
* @return UserAdminController
*/
public function createService(ServiceLocatorInterface $serviceLocator){
return $this($serviceLocator, UserAdminController::class);
}
}
在控制器内部,当需要新的用户实例时,可以通过调用PHP的克隆功能简单地创建它。以下是控制器中如何执行操作的示例:
<?php
namespace User\Controller\Core;
use User\Entity\User;
use Zend\View\Model\ViewModel;
use Zend\Mvc\Controller\AbstractActionController;
class UserAdminController extends AbstractActionController {
/**
* @var User
*/
public $user;
/**
* @param User $user
*/
public function __construct(User $user){
$this->user = $user;
}
/**
* @return ViewModel
*/
public function indexAction(){
if($this->getRequest()->isPost()){
$usersData = $this->params()->fromPost("usersData");
foreach($usersData as $userData){
$newUser = clone $this->user;
$newUser->fromArray($userData);
$newUser->save();
}
}
return ViewModel();
}
}
将UserFactory注入控制器是 NOT 一个选项,因为工厂使用服务定位器来创建User类的新实例。如果将工厂注入控制器,也应注入服务定位器,但这被认为是反模式,此外,它被弃用并被认为是ZendFramework3中的不良做法。