ZF2 Doctrine - 如何处理需要特定 id 的依赖注入

ZF2 Doctrine - How to handle dependency injection which requires a certain id

我不确定如何提出问题,请随时编辑。

我目前的情况是这样的: 我有一个实例化表单 class 的工厂 class。依赖注入(DI)是通过构造函数注入完成的。我的问题是,这个表单元素有一个 Doctrine ObjectMultiCheckbox,它需要一个 findby 方法。对于这个 findby 方法,我需要某个实体的 ID,但我无法通过工厂 class 将 ID 传递给表单。

我的问题是,我该如何处理这种情况?什么是最好的方法?

假设这是我的工厂class:

class CustomerFormFactory implements FactoryInterface
{
    /**
     * Create service
     *
     * @param ServiceLocatorInterface $serviceLocator
     * @return Form
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $em = $serviceLocator->get('Doctrine\ORM\EntityManager');
        return new CustomerForm($em);
    }
}

我通过这样的服务定位器获取表单:

$customerForm = $this->getServiceLocator()->get('CustomerForm');

如何将 ID 传递给服务定位器?而如果表单元素需要某个ID,那岂不是破坏了DI和服务的目的?我是否应该采用 "classic" 方式并像这样自己实例化表单元素:

$customerForm = new CustomerForm(EntityManager $em, int $id);

我真的不确定我应该做什么或者处理这个问题的最佳方法是什么。

为了将选项插入到您的表单中,您可以使用工厂 class 的 CreationOptions

所以让我们开始为 FormElementManager(我们的表单元素的 serviceLocator)设置我们的配置。

在你的 Module.php 内:

use Zend\ModuleManager\Feature\FormElementProviderInterface;

class Module implements FormElementProviderInterface 
{
    // your module code

    public function getFormElementConfig()
    {
        return [
            'factories' => [
                'myForm' => \Module\Form\MyFormFactory::class
            ]
        ];
    }
}

设置配置后,我们应该创建我们的工厂,returns 表单包括它的依赖项。我们还在表单 class.

中插入了可以重复使用的选项
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsTrait;
use Zend\ServiceManager\ServiceLocatorInterface;

class MyFormFactory implements FactoryInterface
{
    use MutableCreationOptionsTrait;

    /**
     * Create service
     *
     * @param ServiceLocatorInterface $serviceLocator
     *
     * @return mixed
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        return new MyForm(
            $serviceLocator->getServiceLocator()->get('Doctrine\ORM\EntityManager'),
            'MyForm',
            $this->getCreationOptions()
        );
    }
}

When using ZF3 it is better to use \Zend\ServiceManager\Factory\FactoryInterface instead of the \Zend\ServiceManager\FactoryInterface as this is the way ZF3 is going with using factories. In the example above I used the ZF2 (v2.7.6 zendframework/zend-servicemanager) version. See the comment on the class Zend\ServiceManager\FactoryInterface::class to replace it with the ZF3 version.

所以现在当我们在 FormElementManager class 上调用 ::get('myForm', ['id' => $id]) 时,您将获得一个 MyForm 实例并且表单的选项将包含我们已经设置的选项传了。

因此您的表单可能看起来类似:

class MyForm extends \Zend\Form\Form
{
    public function __construct(
        \Doctrine\Common\Persistence\ObjectManager $entityManager,
        $name = 'myForm',
        $options = []
    ) {
        parent::__construct($name, $options);

        $this->setEntityManager($entityManager);
    }

    public function init () { 
        /** add form elements **/
        $id = $this->getOption('id');
    }
}

您也可以创建表单并设置实体管理器,但这完全取决于您。您不需要使用构造函数注入。

你的控制器的例子:

$myForm = $this->getServiceManager()->get('FormElementManager')->get('myForm', ['id' => 1337]);
$options = $myForm->getOptions();
// your options: ['id' => 1337]

当您使用 ZF2.5+ 或 ZF3 时,您的 Controller 中可能没有 ServiceManager 或 Locator,因此您必须通过工厂将 FormElementManager 或 Form class 注入到您的 Controller 中。

如果您的表单中没有任何其他依赖项,但您想要设置选项,则不需要为每个 class 创建一个工厂。您可以重新使用 InvokableFactory::class 因为这也会注入 creationOptions.