如何在不在 ZendFramework2 中注入 ServiceLocator 的情况下创建多个非共享实例?
How to create multiple non-shared instances without injecting the ServiceLocator in ZendFramework2?
我的 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实体是非共享的,因为我允许管理员同时添加多个用户,所以我需要实例化User实体的多个实例class。
这是我的控制器工厂:
<?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);
}
}
目前,它仅在控制器的构造函数中注入用户实体的单个实例 class。但是,根据管理员想要执行的操作,我需要未定义数量的新实例。
一个可能的解决方案是每次通过在控制器中调用 $this->getServiceLocator()->get(User::class)
来传递整个服务定位器并创建新实例,但这被认为是一种反模式。
这里的问题是如何使用 UserFactory 在控制器中创建 User 的新实例 class?
EDIT1:添加用户工厂:
<?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);
}
}
最好的方法是将用户实体的新实例注入到控制器中。控制器工厂应如下所示:
<?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 注入控制器 不是 一个选项,因为工厂使用服务定位器创建用户的新实例 class。如果工厂被注入控制器,服务定位器也应该被注入,但这被认为是一种反模式,而且,它在 ZendFramework3 中被弃用并被认为是一种不好的做法。
我的 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实体是非共享的,因为我允许管理员同时添加多个用户,所以我需要实例化User实体的多个实例class。
这是我的控制器工厂:
<?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);
}
}
目前,它仅在控制器的构造函数中注入用户实体的单个实例 class。但是,根据管理员想要执行的操作,我需要未定义数量的新实例。
一个可能的解决方案是每次通过在控制器中调用 $this->getServiceLocator()->get(User::class)
来传递整个服务定位器并创建新实例,但这被认为是一种反模式。
这里的问题是如何使用 UserFactory 在控制器中创建 User 的新实例 class?
EDIT1:添加用户工厂:
<?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);
}
}
最好的方法是将用户实体的新实例注入到控制器中。控制器工厂应如下所示:
<?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 注入控制器 不是 一个选项,因为工厂使用服务定位器创建用户的新实例 class。如果工厂被注入控制器,服务定位器也应该被注入,但这被认为是一种反模式,而且,它在 ZendFramework3 中被弃用并被认为是一种不好的做法。