ZendFramework 2 - удаление InputFilter вызывает неправильное поведение в пользовательском фильтре

У меня есть форма регистрации User\UserForm, которая содержит набор полей User \ UserFieldset. В User \ UserFieldset я поместил поле с именем "passwordVerify", которое должно совпадать с другим полем в наборе полей с именем "password". Это отлично работает.

Однако, если администратор хочет изменить учетную запись пользователя в Admin \ UserForm, которая также содержит User \ UserFieldset, поле "passwordVerify" в fieldset User \ UserFieldset должно быть удалено. Поэтому я вызываю следующее в Admin \ UserForm:

$this->get('user')->remove('passwordVerify');
$this->getInputFilter()->get('user')->remove('passwordVerify')

Как и ожидалось, в форме теперь отсутствует поле "passwordVerify".

Если я сохраню форму после редактирования какого-либо материала, мой пользовательский фильтр "PasswordFilter" больше не сможет извлечь связанный объект из набора полей ($this->getOption('object'); возвращает объект User), но все свойства связанного объекта обнуляются. Если я использую Admin \ UserForm без удаления полей "passwordVerify" и "passwordVerify" -inputfilter, все работает нормально, и связанный объект передается в "PasswordFilter" с заполненными свойствами (в отношении значений, вставленных пользователем в Admin\UserForm). Линия, которая ломает все $this->getInputFilter()->get('user')->remove('passwordVerify'), Таким образом, это приводит к моему предположению, что, удаляя входной фильтр, гидратированный объект каким-то образом обнуляется / очищается. Ниже приведены некоторые выдержки из моего кода, при необходимости я могу предоставить больше информации о фабриках и т. Д.

Admin \ UserForm:

class UserForm extends Form
{

    /**
     * @var EntityManager
     */
    protected $entityManager = null;

    /**
     * @var Translator
     */
    protected $translator = null;

    public function __construct(EntityManager $entityManager, Translator $translator)
    {
        $this->entityManager = $entityManager;
        $this->translator = $translator;

        parent::__construct("userForm");
        $this->setHydrator(new DoctrineHydrator($entityManager));
    }

    public function init()
    {
        // Adding UserFieldset
        $this->add(array(
            'name' => 'user',
            'type' => \User\Form\UserFieldset::class,
            'options' => array(
                'use_as_base_fieldset' => true,
            ),
        ));

        $this->get('user')->remove('passwordVerify');
        $this->getInputFilter()->get('user')->remove('passwordVerify');

        $this->add(array(
            'type' => 'Zend\Form\Element\Csrf',
            'name' => 'csrf',
        ));

        $this->add(array(
            'type' => 'submit',
            'name' => 'submit',
            'options' => array(
                'label' => $this->translator->translate('Btn.submit.user', 'Form')
            ),
        ));
    }
}

Пользователь \ UserFieldset:

class UserFieldset extends Fieldset implements InputFilterProviderInterface
{

    /**
     * @var EntityManager
     */
    protected $entityManager = null;

    /**
     * @var Translator
     */
    protected $translator = null;

    public function __construct(EntityManager $entityManager, Translator $translator)
    {
        $this->entityManager = $entityManager;
        $this->translator = $translator;

        parent::__construct("userFieldset");
        $this->setHydrator(new DoctrineHydrator($entityManager))->setObject(new User());
    }

    public function init()
    {
        $this->add(array(
            'type' => 'text',
            'name' => 'firstName',
            'options' => array(
                'label' => $this->translator->translate('label.firstName', 'Form'),
                'label_attributes' => array(
                    'class' => 'col-sm-3',
                ),
                'column-size' => 'sm-5',
            ),
            'attributes' => array(
                'id' => 'firstName',
            ),
        ));
        /* ... */
        $this->add(array(
            'type' => 'text',
            'name' => 'password',
            'options' => array(
                'label' => $this->translator->translate('label.password', 'Form'),
                'label_attributes' => array(
                    'class' => 'col-sm-3',
                ),
                'column-size' => 'sm-5',
            ),
            'attributes' => array(
                'id' => 'password',
            ),
        ));

        $this->add(array(
            'type' => 'password',
            'name' => 'passwordVerify',
            'options' => array(
                'label_attributes' => array(
                    'class' => 'col-sm-3 control-label'
                ),
                'label' => $this->translator->translate('label.verifyPassword', 'Form'),
                'column-size' => 'sm-8',
            ),
            'attributes' => array(
                'class' => 'form-control',
                'id' => 'password'),
        ));

         /* ... */

        // Adding AddressFieldset
        $this->add(array(
            'name' => 'address',
            'type' => \User\Form\AddressFieldset::class,
        ));

         /* ... */

        $this->add(array(
            'type' => 'datetime',
            'name' => 'created',
            'options' => array(
                'label' => $this->translator->translate('label.created', 'Form'),
                'format' => 'd.m.Y H:i',
                'label_attributes' => array(
                    'class' => 'col-sm-3',
                ),
                'column-size' => 'sm-5',
            ),
            'attributes' => array(
                'id' => 'created',
            ),
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            'firstName' => array(
                'required' => true,
                'filters' => array(
                    array('name' => 'StringTrim'),
                    array('name' => 'StripTags'),
                ),
                'validators' => array(),
            ),
            /* ... */
            'password' => array(
                'required' => true,
                'filters' => array(
                    array('name' => 'StringTrim'),
                    array('name' => 'StripTags'),
                    [
                        'name' => PasswordFilter::class,
                        'options' => [
                            'object' => $this->getObject(),
                            'field' => 'password'
                        ]
                    ]
                ),
                'validators' => array(),
            ),
            'passwordVerify' => array(
                'required' => true,
                'filters' => [
                    [
                        'name' => PasswordFilter::class,
                        'options' => [
                            'object' => $this->getObject(),
                            'field' => 'password'
                        ]
                    ]
                ],
                'validators' => array(
                    array(
                        'name' => 'StringLength',
                        'options' => array(
                            'min' => 6
                        )
                    ),
                    array(
                        'name' => 'Identical',
                        'options' => array(
                            'token' => 'password'
                        )
                    )
                )
            ),
           /* ... */
            'created' => array(
                'required' => false,
                'filters' => array(
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array(
                        'name' => 'Date',
                        'options' => array('format' => 'd.m.Y H:i')
                    ),
                ),
            )
        );
    }
}

PasswordFilter:

class PasswordFilter extends AbstractFilter
{
    /** @var  EntityManager */
    protected $entityManager;

    /** @var  PasswordInterface */
    protected $passwordManager;

    /**
     * PasswordFilter constructor.
     * @param EntityManager $entityManager
     * @param PasswordInterface $passwordManager
     * @param array $options
     */
    public function __construct(EntityManager $entityManager, PasswordInterface $passwordManager, $options = [])
    {
        $this->entityManager = $entityManager;
        $this->passwordManager = $passwordManager;

        $this->options = $options;
    }

    public function filter($value)
    {
        $object = $this->getOption('object');
        $field = $this->getOption('field');
        $getter = 'get'.ucfirst($field);

        if (!$object || !$field) {
            throw new \Exception('Options "object" and "field" are required.');
        }

        if ($object->getId()) {
            $dbObject = $this->entityManager->getRepository(get_class($object))->find($object->getId());

            if ($value === $dbObject->{$getter}()) {
                return $value;
            }
        }

        // hash password here...
        return $this->passwordManager->create($value);
    }

    private function getOption($option)
    {
        if (array_key_exists($option, $this->options)) {
            return $this->options[$option];
        }
        return false;
    }
}

Есть какие-нибудь подсказки? Должен ли я вызывать удалить входной фильтр "passwordVerify" на ранней стадии процесса создания экземпляра? Я также проверил, чтобы удалить inputFilter и поле после "$this->form->bind($user)" в моем контроллере, что также работает. Почему это не работает, если я удаляю его в Admin \ UserForm, который, по моему мнению, является более чистым способом управления "passwordVerify"?

1 ответ

Если вы позвоните $this->getInputFilter(), InputProviderInterface::getInputSpecification метод в вашем UserForm называется

Если вы еще не прикрепили объект, он не сможет получить его. Но я не понимаю, зачем тебе это нужно. Вы хэшируете пароль, если значение не соответствует значению базы данных, но очевидно, что значение базы данных выглядит как простой текст в качестве входных данных или зачем сравнивать его?

ИМХО, вы просто должны хешировать пароль, независимо от текущего значения в вашей базе данных.

Если вы используете доктрину и пароль не изменится, он все равно не выполнит запрос UPDATE.

Другие вопросы по тегам