ZF2/Doctrine2 - Fieldsets not validated, data is always valid

笑着哭i 提交于 2019-11-29 16:24:37

Since you've got all the classes set up already there is another approach (from @AlexP), by constructing and adding the InputFilters of the Fieldsets to the Forms InputFilter. Instead of using the InputFilterSpecifications.

So add the input filters to your input_filters config key:

'form_elements' => [
    'factories' => [
        CountryForm::class => CountryFormFactory::class,
        CountryFieldset::class => CountryFieldsetFactory::class,
    ],
],
'input_filters' => [
    'factories' => [
        CountryInputFilter::class => CountryInputFilterFactory::class,
        CountryFieldsetInputFilter::class => CountryFieldsetInputFilterFactory::class,
    ],
],

Factory classes:

class CountryInputFilterFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceManager = $serviceLocator->getServiceLocator();

        $inputFilter = new CountryInputFilter(
            $serviceLocator->get(CountryFieldsetInputFilter::class),
            $serviceManager()->get('Doctrine\ORM\EntityManager'),
            $serviceManager()->get('translator')
        );

        return $inputFilter;
    }
}

class CountryFieldsetInputFilterFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceManager = $serviceLocator->getServiceLocator();

        return new CountryFieldsetInputFilter(
            $serviceManager()->get('Doctrine\ORM\EntityManager'),
            $serviceManager()->get('translator')
        );
    }
}

class CountryFormFactory implements AbstractFormFactory
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceManager = $serviceLocator->getServiceLocator();

        $form = new CountryForm($this->name, $this->options);
        $form->setObjectManager($serviceManager->get('Doctrine\ORM\EntityManager'));
        $form->setTranslator($serviceManager->get('translator'));

        $form->setInputFilter($serviceManager->get('InputFilterManager')->get(CountryInputFilterFactory::class));
        return $form;
    }
}

Form:

class CountryForm extends AbstractForm
{
    const COUNTRY_FIELDSET_NAME = 'country';

    // This one added for SO, does nothing but call parent#__construct, which would happen anyway
    public function __construct($name = null, array $options)
    {
        parent::__construct($name, $options);
    }

    public function init()
    {
        //Call parent initializer.
        parent::init();

        $this->add([
            'name' => self::COUNTRY_FIELDSET_NAME,
            'type' => CountryFieldset::class,
            'options' => [
                'use_as_base_fieldset' => true,
            ],
        ]);
    }
}

InputFilters:

class CountryInputFilter extends AbstractInputFilter
{
    /** @var CountryFieldsetInputFilter  */
    protected $countryFieldsetInputFilter;

    public function __construct(CountryFieldsetInputFilter $filter, $objectManager, $translator)
    {
        $this->countryFieldsetInputFilter = $filter;
        // other dependencies
    }

    public function init()
    {
        $this->add($this->countryFieldsetInputFilter, CountryForm::COUNTRY_FIELDSET_NAME);
    }
}

class CountryFieldsetInputFilter extends AbstractInputFilter
{
    public function __construct($objectManager, $translator)
    {
        // dependencies
    }

    public function init()
    {
        $this->add([
            // configuration
        ]);
    }
}

Note that I injected the dependencies to the InputFilters per argument by instance instead of an array holding the instances.

$fieldset->setInputFilter($inputFilter); 

Assuming that $fieldset is an instance of Zend\Form\Fieldset, the method doesn't exist. This is because you need to set the input filter on the form (Zend\Form\Form).

If I was to modify your code I would do so in the following way. Modify the CountryForm to provide the input filter via the form. This can be done without needing to define a custom input filter for each form, by using the Zend\InputFilter\InputFilterProviderInterface and referencing your custom input filter under the type key.

When the form element manager creates the form, it will also inject the input filter manager which will be able to find the custom CountryInputFilter.

For example:

use Zend\InputFilter\InputFilterProviderInterface;

class CountryForm extends AbstractForm implements InputFilterProviderInterface
{

    public function init() 
    { 
        //.. add the country fieldset here
    }

    /**
     * getInputFilterSpecification
     *
     * Return the form's input filter specification array.
     *
     * @return array
     */
    public function getInputFilterSpecification()
    {
        return [
            // Refers to the country element (happens to be a fieldset)
            'country' => [

                // Tell the input filter factory what type of input filter.
                'type' => 'Country\\InputFilter\\CountryInputFilter',

                // You could even overload/change the default defined in the input filter
                // here. This is useful as sometimes the requirements of the FORM are 
                // different from what the FIELDSET expects.
                // [
                //     'name'        => 'name',
                //     'required'    => false,
                //     'allow_empty' => true,
                // ],
            ],
        ];
    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!