Symfony2 - Как остановить Form-> handleRequest от обнуления полей, которые не существуют в данных post

У меня есть форма, встроенная в Symfony, и при визуализации в представлении форма html может содержать или не содержать все поля в объекте формы (тип объекта имеет пару разных состояний, а не все поля в представлении).

Проблема заключается в том, что, когда форма обрабатывается в обработчике отправки, с помощью метода handleRequest() объекта формы, он сбрасывает любые свойства в сущности, которые не присутствуют в данных сообщения, до нуля, сдувая любое существующее значение.

Есть ли способ сказать Symfony не быть таким глупым и обрабатывать только поля, присутствующие в данных POST?

Или мне нужно клонировать объект перед вызовом handleRequest, а затем перебирать значения POST и копировать связанные значения из объекта post-handleRequest в клон pre-handleRequest объекта, поэтому я сохраняю поля, которые не указаны в данных POST.

уф! как вы можете видеть, это немного глупое решение, немного неприятная проблема, tbh.

Я мог бы понять, что symfony делает это, если объект был фактически созданным объектом, но он был загружен из БД, а затем вызван handleRequest - он должен быть достаточно разумным, чтобы знать, что объект уже инициализирован и заданы только поля переданные в данных POST.

Спасибо за любую помощь.

Привет

Steve.

Ответы

Ответ 1

Короче говоря, не используйте handleRequest.

Вместо этого следует использовать submit, а параметр clearMissing - false.

Symfony/Component/Form/FormInterface

/**
 * Submits data to the form, transforms and validates it.
 *
 * @param null|string|array $submittedData The submitted data.
 * @param bool              $clearMissing  Whether to set fields to NULL
 *                                         when they are missing in the
 *                                         submitted data.
 *
 * @return FormInterface The form instance
 *
 * @throws Exception\AlreadySubmittedException If the form has already been submitted.
 */
public function submit($submittedData, $clearMissing = true);

Когда вы используете handleRequest, он определяет, какие данные вы хотите отправить, а затем отправляет их с помощью $form->submit($data, 'PATCH' !== $method);, что означает, что, если вы не отправили форму с помощью метода PATCH, тогда она очистит поля.

Чтобы отправить форму самостоятельно без очистки, вы можете использовать...

$form->submit($request->get($form->getName()), false);

.. которые получают массив данных формы из запроса и отправляют его напрямую, но с параметром clear missing fields установлено значение false.

Ответ 2

Если у вашего объекта разные состояния, вы можете отразить это в своем типе формы.

Либо создайте несколько типов форм (возможно, используя наследование), содержащих различные настройки полей, и создайте требуемый файл в вашем контроллере.

Что-то вроде этого:

class YourState1FormType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('someField')
        ;
    }

}

class YourState2FormType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('someOtherField')
        ;
    }

}

Или передать параметр в один тип формы при создании в контроллере и адаптировать настройку поля в зависимости от состояния. Если вы не добавляете поля, которые не присутствуют, они не обрабатываются.

Что-то вроде этого:

class YourFormType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if($options['state'] == 'state1') {
            $builder
                ->add('someField')
            ;
        } else if($options['state'] == 'state2') {
            $builder
                ->add('someOtherField')
            ;
        }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'state' => 'state1'
        ));
    }

}

Обновление

Другой подход, который вы можете применить для изменения формы на основе представленных данных, - это зарегистрировать прослушиватели событий в форме PRE_SET_DATA и POST_SUBMIT. Эти слушатели вызывают в разные моменты процесса подачи формы и позволяют изменять форму в зависимости от объекта данных, переданного в тип формы при создании формы (PRE_SET_DATA) или данных формы, представленных пользователем (POST_SUBMIT).

В документах можно найти объяснение и примеры .