如何在不在 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 中被弃用并被认为是一种不好的做法。