web-dev-qa-db-fra.com

Comment désactiver un champ en mode édition à l'aide de Symfony 2 FormBuilder

J'ai créé un formulaire avec Symfony2 FormBuilder et je souhaite désactiver l'un des champs de la vue d'édition. Je le cache en fait avec un wrapper (display:none) mais je me demandais s'il y avait une meilleure façon de le faire. Mon code ressemble à ceci:

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);
    // ...
}

Nouveau modèle (brindille)

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

Modifier (brindille) modèle

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

Je pense que vous constaterez que vous aurez d'autres différences entre créer et éditer, en particulier les groupes de validation. Étant donné que votre contrôleur sait quelle opération est effectuée, envisagez de créer deux types de formulaires EditEntity et CreateEntity, puis d'utiliser une base commune pour minimiser le code en double. @cheesemackfly montre comment ajouter un attribut désactivé à un élément.

Mais bien sûr, vous pensez probablement que le fait d'avoir deux formes est un gaspillage pour une différence aussi simple. Dans ce cas, ajoutez un indicateur d'intention à votre classe et définissez-le dans le contrôleur

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);

Si vous voulez vraiment vous lancer, utilisez di pour injecter l'intention.

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

En utilisant les services, vous pouvez commencer avec un seul type de formulaire, puis lorsque vous finirez par le diviser en deux (ce que vous ferez), vos contrôleurs fonctionneront toujours comme auparavant.

Et encore une chose, vous pouvez réellement définir l'attribut désactivé directement dans twig en supposant que vous utilisez différents modèles pour éditer/créer. Donc, aucun code ne change du tout.

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

================================================== ====================== Mise à jour: 03 mars 2016

Juste au cas où quelqu'un tomberait dessus, sachez que Symfony 3 ne prend plus en charge le fait qu'une classe implémente plusieurs types de formulaires. Vous devez essentiellement avoir des classes de type de formulaire individuelles, même si elles sont presque identiques. Et n'ajoutez jamais de données d'instance à vos types de formulaires.

26
Cerad

Il s'agit du cas typique où vous pouvez utiliser un abonné d'événements à une classe de formulaire.
Dans votre cas, ce devrait être:

// 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]);
        }
    }
}

Et dans votre type de formulaire:

// 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

16
cheesemacfly

Cette approche n'est pas élégante du tout mais je l'utilise car elle est simple:

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');    
    // ...
}
11

Pour ceux qui recherchent une solution dans Symfony 3 sans créer de classes de type de formulaire distinctes (à la fois pour ajouter et modifier) ​​et sans utiliser d'événements de formulaire, vous pouvez définir une option personnalisée et la transmettre au formulaire lors de la création:

J'ai créé un is_edit option avec la valeur par défaut false dans la classe de type de formulaire:

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

Vous pouvez accéder à cette option en utilisant le $options tableau dans la méthode buildForm de la même classe:

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

Enfin, vous pouvez remplacer la valeur par défaut en la passant lors de la création du formulaire:

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

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

3
Egon Olieux

Nouveau modèle (twig) N'oubliez pas {{form_row (form._token)}} lors du rendu individuel des champs de formulaire

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

Edit (twig) Template Ne restituez simplement pas {{form_row (form.fieldToDisabledInEditView)}} et n'oubliez pas de nouveau le jeton.

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