Как отключить поле в режиме редактирования с помощью Symfony 2 FormBuilder

Я создал форму с Symfony2 FormBuilder, и я хочу отключить одно из полей в окне редактирования. Я на самом деле скрываю его с оберткой (display:none), но мне было интересно, есть ли лучший способ сделать это. Мой код выглядит следующим образом:

EntityType

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('fieldToDisabledInEditView');
    // ...

EntityController

public function newAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    // ...
}
public function editAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    // ...
}

Новый шаблон (твинг)

<form>
    {{ form_row(form.fieldToDisabledInEditView) }}
    {# ... #}

Редактировать (twig) Шаблон

<form>
    <span class="theValueOfTheHiddenField">{{ entity.fieldToDisabledInEditView }}</span>
    <div style="display:none">
        {{ form_row(form.fieldToDisabledInEditView) }}
    </div>
    {# ... #}

Ответы

Ответ 1

Я думаю, вы обнаружите, что у вас будут другие различия между create и edit, особенно с группами проверки. Поскольку ваш контроллер знает, какая операция выполняется, подумайте о создании двух типов форм EditEntity и CreateEntity, а затем с помощью общей базы, чтобы свести к минимуму дубликат кода. @cheesemackfly показывает, как добавить отключенный атрибут к элементу.

Но, конечно, вы, вероятно, чувствуете, что наличие двух форм - это отходы для такой простой разницы. В этом случае добавьте флаг намерения в свой класс и установите его в контроллере

class EntityType
{
    public function __construct($intention)
    {
        $this->intention = $intention;

     ...
    // Use $this->intention to tweak the form

    }
}

// controller
$form = $this->createForm(new EntityType('create'), $entity);
OR
$form = $this->createForm(new EntityType('edit'), $entity);

Если вы действительно хотите войти в него, используйте di, чтобы ввести намерение.

 // controller
 $formType = $this->get('entity.create.formtype');
 OR
 $formType = $this->get('entity.edit.formtype');

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

И еще одно: вы можете фактически установить отключенный атрибут непосредственно в ветке, предполагая, что вы используете разные шаблоны для редактирования/создания. Таким образом, никакой код вообще не изменяется.

{{ form_row(form.yourField, { 'attr':{'disabled':'disabled'} }) }}

=============================================== ========================= Обновление: 03 марта 2016 г.

На всякий случай кто-то споткнутся об этом, имейте в виду, что Symfony 3 больше не поддерживает, что один класс реализует несколько типов форм. В основном вы должны иметь индивидуальные классы типа, даже если они почти идентичны. И никогда не добавляйте данные экземпляра в свои типы форм.

Ответ 2

Это типичный случай, когда вы можете использовать подписчика событий для класса формы.
В вашем случае это должно быть как:

// src/Acme/DemoBundle/Form/EventListener/AddfieldToDisabledInEditViewSubscriber.php
namespace Acme\DemoBundle\Form\EventListener;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class AddfieldToDisabledInEditViewSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        // Tells the dispatcher that you want to listen on the form.pre_set_data
        // event and that the preSetData method should be called.
        return array(FormEvents::PRE_SET_DATA => 'preSetData');
    }

    public function preSetData(FormEvent $event)
    {
        $data = $event->getData();
        $form = $event->getForm();

        // check if the object is "new"
        // If you didn't pass any data to the form, the data is "null".
        // This should be considered a new object
        if (!$data || !$data->getId()) {
            $form->add('fieldToDisabledInEditView');
        }
        else
        {
            $form->add('fieldToDisabledInEditView', null, array('disabled' => true));
            //If PHP >= 5.4
            //$form->add('fieldToDisabledInEditView', null, ['disabled' => true]);
        }
    }
}

И в вашем типе формы:

// src/Acme/DemoBundle/Form/Type/EntityType.php
namespace Acme\DemoBundle\Form\Type;

// ...
use Acme\DemoBundle\Form\EventListener\AddfieldToDisabledInEditViewSubscriber;

class EntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('your_field');
        //...

        $builder->addEventSubscriber(new AddfieldToDisabledInEditViewSubscriber());
    }

    // ...
}

http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

Ответ 3

Этот подход совсем не изящный, но я использую его, потому что он прост:

EntityController

public function newAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    // ...
}
public function editAction() {
    $entity = new Entity;
    $form = $this->createForm(new EntityType, $entity);
    $form->remove('fieldToDisabledInEditView');    
    // ...
}

Ответ 4

Новый шаблон (twig) Не забывайте {{form_row (form._token)}} при визуализации полей формы индивидуально

<form>
    {{ form_row(form.fieldToDisabledInEditView) }}
    {{ form_row(form.field2) }}
    {{ form_row(form.field3) }}
    {# ... #}
    {{ form_row(form._token) }}

Редактировать (twig) Template Просто не выставляйте {{form_row (form.fieldToDisabledInEditView)}} и снова не забывайте токен.

<form>
    {{ form_row(form.field2) }}
    {{ form_row(form.field3) }}
    {# ... #}
    {{ form_row(form._token) }}

Ответ 5

Для тех, кто ищет решение в Symfony 3 без создания отдельных классов типа типов (для добавления и редактирования) и без использования событий формы, вы можете определить пользовательскую опцию и передать ее в форму при создании:

Я создал параметр is_edit со значением по умолчанию false в классе типа формы:

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => SomeEntity::class,
        'is_edit' => false
    ));
}

Вы можете получить доступ к этому параметру с помощью массива $options в методе buildForm того же класса:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('someField', TextType::class, array(
        'disabled' => $options['is_edit']
    ))
}

Наконец, вы можете переопределить значение по умолчанию, передав его при создании формы:

$someForm = $this->createForm(
    SomeEntityType::class,
    $someEntity,
    array('is_edit' => true)
);

https://symfony.com/doc/current/form/form_dependencies.html