ZF2将InputFilter注入Fieldset不能自动工作

时间:2016-11-19 23:34:37

标签: php dependency-injection doctrine-orm zend-framework2

我正在使用ZF2和Doctrine2构建一个小应用程序。以这样的方式进行设置,以便拥有大量可重用的代码和技术。但是,由于我的InputFilter没有被自动注入它应该关联到的Fieldset这一事实而感到困惑。

我已确认使用Fieldset的表单有效(没有InputFilter)。在调试期间,InputFilter也可见。

那么问题是,我做错了什么以及如何修复单独的InputFilter,并与ZF2中的Fieldset相关联?

旁注:

1 - 我知道使用InputFilterInterface我可以在InputFilter类中使用Fieldset getInputFilterSpecification()函数。但是,当我试图保持DRY和可重用时,如果我要创建一个需要使用EntityInputFilter的API,则无需复制它,但是只有后者加上Fieldset

2 - 使用了很多抽象类,在使用的时候我会在片段中指出他们有什么相关的

3 - 问题行位于CustomerFieldsetFactory.php

=============================================== ==========================

实体:Customer.php

/**
 * Class Customer
 * @package Customer\Entity
 *
 * @ORM\Entity
 * @ORM\Table(name="customers")
 */
class Customer extends AbstractEntity //Contains $id
{
    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    protected $name;
}

表格:CustomerForm.php

class CustomerForm extends AbstractForm
{
    public function __construct($name = null, array $options)
    {
        parent::__construct($name, $options); // Adds CSRF
    }

    public function init()
    {
        $this->add([
            'name' => 'customer',
            'type' => CustomerFieldset::class,
            'options' => [
                'use_as_base_fieldset' => true,
            ],
        ]);

        //Call parent initializer. Check in parent what it does.
        parent::init(); //Adds submit button if not in form
    }
}

Fieldset:CustomerFieldset.php

class CustomerFieldset extends AbstractFieldset //Contains EntityManager property and constructor requirement (as we're managing Doctrine Entities here)
{
    public function init()
    {
        $this->add([ //For now id field is here, until InputFilter injection works
            'name' => 'id',
            'type' => Hidden::class,
            'attributes' => [
                'id' => 'entityId',
            ],
        ]);

        $this->add([
            'name' => 'name',
            'type' => Text::class,
            'options' => [
                'label' => _('Name'),
            ],
        ]);
    }
}

InputFilter:CustomerInputFilter.php

class CustomerInputFilter extends AbstractInputFilter
{
    public function init()
    {
        parent::init();

        $this->add([
            'name' => 'name',
            'required' => true,
            'filters' => [
                ['name' => StringTrim::class],
                ['name' => StripTags::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'min' => 3,
                        'max' => 255,
                    ],
                ],
            ],
        ]);
    }
}

在课程之上。工厂下方

FormFactory:CustomerFormFactory.php

class CustomerFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    /**
     * @var array
     */
    protected $options;

    /**
     * @param array $options
     */
    public function setCreationOptions(array $options)
    {
        //Arguments checking removed
        $this->options = $options;
    }

    /**
     * @param ServiceLocatorInterface|ControllerManager $serviceLocator
     * @return CustomerForm
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceManager = $serviceLocator->getServiceLocator();

        $form = new CustomerForm($this->options['name'], $this->options['options']);

        $form->setTranslator($serviceManager->get('translator'));

        return $form;
    }
}

FieldsetFactory:CustomerFieldsetFactory.php

class CustomerFieldsetFactory implements FactoryInterface, MutableCreationOptionsInterface
{
    /**
     * @var string
     */
    protected $name;

    public function setCreationOptions(array $options)
    {
        //Argument checking removed

        $this->name = $options['name'];
    }

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceManager = $serviceLocator->getServiceLocator();

        $fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);

        $fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
        $fieldset->setObject(new Customer());
        $fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));

        //RIGHT HERE! THE LINE ABOVE IS THE ONE THAT DOES NOT WORK!!!

        return $fieldset;
    }
}

InputFilterFactory:CustomerInputFilterFactory.php

class CustomerInputFilterFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $repository = $serviceLocator->getServiceLocator()
            ->get('Doctrine\ORM\EntityManager')
                ->getRepository(Customer::class);

        return new CustomerInputFilter($repository);
    }
}

配置:module.config.php

'controllers' => [
    'factories' => [
        CustomerController::class => CustomerControllerFactory::class,
    ],
],
'form_elements' => [
    'factories' => [
        CustomerForm::class => CustomerFormFactory::class,
        CustomerFieldset::class => CustomerFieldsetFactory::class,
    ],
],
'input_filters' => [
    'factories' => [
        CustomerInputFilter::class => CustomerInputFilterFactory::class,
    ],
],
'service_manager' => [
    'invokables' => [
        CustomerControllerService::class => CustomerControllerService::class,
    ],
],

我希望你们中的一个可以帮助我。

编辑:更新时出现实际错误

CustomerFieldset.php(上方)中的以下行会触发错误。

$fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class));

错误:

Fatal error: Call to undefined method Customer\Fieldset\CustomerFieldset::setInputFilter() in D:\htdocs\server-manager\module\Customer\src\Customer\Factory\CustomerFieldsetFactory.php on line 57

Debug snippet

如上面的代码片段所示,InputFilter(和它的工厂)已知为InputFilterManager

错误表明它不知道Fieldset上的getInputFilter()函数。哪种方式是正确的,它不存在。那么问题是,如何使函数存在以便注入InputFilter将起作用,或者如何将此InputFilter绑定到Fieldset?

编辑2:根据Wilt的回答进行更新 已将use InputFilterAwareTrait添加到抽象类AbstractInputFilter以创建以下内容(来自答案):

use Zend\InputFilter\InputFilterAwareTrait;

abstract class AbstractFieldset extends Fieldset
{
    use InputFilterAwareTrait;
    // ... Other code
}

原来我上面的(原始)代码中还有另一个错误: 在文件module.config.php中,input_filters应该是input_filter_specs。这是(使用特征后)Invalid Factory registered错误(标题为ServiceNotCreatedException)。

以下可能对某人有用,工厂用Hydrator创建一个Fieldset,Object和Inputfilter具有以下createService()功能:

public function createService(ServiceLocatorInterface $serviceLocator)
{
    /** @var ServiceLocator $serviceManager */
    $serviceManager = $serviceLocator->getServiceLocator();
    /** @var CustomerRepository $customerRepository */
    $customerRepository = $serviceManager->get('Doctrine\ORM\EntityManager')->getRepository(Customer::class);

    $fieldset = new CustomerFieldset($serviceManager->get('Doctrine\ORM\EntityManager'), $this->name);
    $fieldset->setHydrator(new DoctrineObject($serviceManager->get('doctrine.entitymanager.orm_default'), false));
    $fieldset->setObject(new Customer());
    $fieldset->setInputFilter($serviceManager->get('InputFilterManager')->get(CustomerInputFilter::class, $customerRepository));

    return $fieldset;
}

2 个答案:

答案 0 :(得分:1)

您的问题中添加了大量信息。我建议你将来尝试缩小你的问题范围。请在此处详细了解有关一个好问题的指南:How to create a Minimal, Complete, and Verifiable example

Zend框架提供TypeError: Cannot read property 'FormsModule' of undefined(…) TypeError: Cannot read property 'annotations' of undefined(…) InputFilterAwareTraitsetInputFilter方法。您可以在getInputFilter类中轻松实现/使用此特征:

CustomerFieldset

如果您希望扩展抽象use Zend\InputFilter\InputFilterAwareTrait; class CustomerFieldset extends AbstractFieldset { use InputFilterAwareTrait; //...remaining code } 类的所有类中的inputfilter,您还可以决定在那里添加特征:

AbstractFieldset

答案 1 :(得分:0)

请参阅以下问题:How to validate nested fieldsets。字段集不包含InputFilters,但您应该扩展表单的基本InputFilter。

为每个Fieldset创建一个InputFilter,并将它们与您的fieldset同名,添加到表单的InputFilter中。正如我所链接的另一个问题的回答所示。

如果您不想这样做,可以考虑使用InputSpecification。