web-dev-qa-db-fra.com

prototype de plusieurs formes imbriquées symfony2

Je souhaite inclure un type de collection dans un autre type de collection. Ça devrait ressembler à ça: enter image description here

L'utilisation d'une seule collection fonctionne bien, mais je dois modifier le prototype du formulaire externe, de sorte qu'il restitue le prototype du formulaire interne pour chaque ligne.

Des idées comment pourrais-je faire ça? Quelle serait la meilleure façon d'économiser

EDIT: Maintenant, j'essaie de rendre le prototype de la forme imbriquée:

  <ul class="characteristics-container" data-prototype="{{ form_widget(form.characteristics.vars.prototype)|e }}" data-prototype-options="{{ form_widget(form.characteristics.options.vars.prototype|e ) }}">
                    {# iterate over each existing tag and render its only field: name #}
                    {% for characteristic in form.characteristics %}
                        <li>{{ form_row(characteristic.name) }}</li>

                        <div class="characteristics-options">
                            {% for opt in form.characteristics.options %}

                            {% endfor %}                     
                        </div>


                    {% endfor %}
                </ul>

Il donne une erreur dans form_widget(form.characteristics.options.vars.prototype|e

Method "options" for object "Symfony\Component\Form\FormView" does not exist in 

J'ai essayé les caractéristiques [0], et il dit que la clé n'existe pas

Voici mes classes de formulaire:

PromotionType (le formulaire de base)

$builder              
            ->add('characteristics','collection', array(
                'label'         => 'Caracteristicas',
                 'type'         => new PromotionCharacteristicType(),
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false
            ))

PromotionCharacteristicType

 $builder
            ->add('name',NULL, array('label'  => 'Nome'))
            ->add('options', 'collection', array(
                'type' => new PromotionCharacteristicOptionType(),
                'allow_add' => true,
                'allow_delete' => true,      
                'prototype' => true,
                'by_reference' => false,
            ))                       
        ;

PromotionCharacteristicOptionType

 $builder
            ->add('name',NULL, array('label'  => 'Nome')) 
        ;

Le prototype de premier niveau fonctionne très bien.

36
brpaz

formes et prototype

Vous devez conserver deux prototypes de collections différentes. Symfony propose de les stocker dans un attribut de prototype de données de la balise div, qui enveloppe la collection. Dans votre situation, c'est très inefficace. Donc, vous pouvez simplement le rendre à la main dans un div vide quelque part

Exemple de forme de caractères

class CharacterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('opts', 'collection', array(
            'type' => new OptionType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__opt_prot__'
        ));
        $builder->add('char_desc', 'text');
    }

    public function getName()
    {
        return 'char';
    }
}

Ensuite, créez un formulaire avec une collection de caractères

$form = $this->createFormBuilder()
    ->add('chars', 'collection', array(
        'type' => new CharacterType(),
        'allow_add' => true,
        'allow_delete' => true,
        'prototype_name' => '__char_prot__'
    ))
    ->getForm();

    # example data
    $form->setData(
        array(
            'chars' => array(
                array('options' => array(), 'char_desc' => 1),
                array('options' => array(), 'char_desc' => 2),
            ),
        )
    );

et obtenez des prototypes

<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.children['opts'].vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>

Et puis rendre la collection comme dans ce exemple ou remplacer le bloc collection_widget

{% for char in form.chars %}
    {{ form_row(char.char_desc) }}
    <label for="">opts</label>
    {% for opt in char.opts %}
        {{ form_row(opt.text) }}
    {% endfor %}
{% endfor %}

comment l'enregistrer

Utilisez la base de données nosql si vous le pouvez. Ou utilisez EAV modèle pour les bases de données de relations. Mais si vous n'avez pas besoin de rechercher dans les options ou de les trier, vous pouvez stocker un tableau sérialisé dans la base de données et utiliser le doctrine type array

30
Alexey B.

Ajoutant à Alexey B. réponse, je ne semble généralement pas avoir besoin d'utiliser prototype.children['opts'] afin de pouvoir accéder au prototype de la collection. J'utilise simplement prototype.<collection_name> comme suit:

<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.opts.vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>
1
kerdany