如何在不在ZendFramework2中注入ServiceLocator的情况下创建多个非共享实例?

时间:2017-02-26 21:54:37

标签: php dependency-injection zend-framework2 factory service-locator

我有一个工厂,在我的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);
    }

}

1 个答案:

答案 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中的不良做法。