2012-10-18 15 views
6

W naszym projekcie Symfony2 mamy bardzo złożoną strukturę dla formularzy z osadzonymi formami. Teraz mamy wymóg dostarczenia danych wyjściowych formularza w określonej kolejności.Symfony 2 - przestawianie pól formularzy

I tu jest problem: używamy formularza_widok (formularz) i teraz szukamy rozwiązania w obiekcie (np. Za pomocą adnotacji) lub konstruktora, aby przenieść określone pole na koniec formularza. w Symfony 1.4 to była funkcja widget-movefield(), chyba ...

Thx ...

Odpowiedz

3

Nie ma potrzeby, aby "uporządkować" pola. Wystarczy zadzwonić pod numer form_label i/lub form_widget dla każdego pola osobno. Zakładając, że używasz Twig można na przykład zrobić:

<div>{{ form_label(form.firstName) }}</div> 
<div>{{ form_widget(form.firstName) }}</div> 

<div>{{ form_label(form.lastName) }}</div> 
<div>{{ form_widget(form.lastName) }}</div> 
+0

Dziękuję, ale to niemożliwe. Mamy bardzo złożoną strukturę i potrzebujemy funkcji form_widget (formularz), więc musimy to zrobić w backendach! – snirgel

+0

Czy próbowałeś dodać pola do instancji 'FormBuilder' w żądanej kolejności? –

+0

To nie możliwe. Mamy około 80 typów obiektów z zależnościami, spadkami itd., Więc NIE MOGĘ manipulować takimi rzeczami ręcznie ... – snirgel

0

Jak rozumiem, chcesz użyć tylko form_widget (formularz) w końcowej szablonu.

Załóżmy mamy dwa odziedziczone modele (MODELA, ModelB) oraz rodzaje formularzy do nich (ModelAType, ModelBType)

class ModelA { 
    private $A; 
    private $B; 

    // Getters and setters 
} 

class ModelB extends ModelA { 
    private $C; 

    // Getters and setters 
} 

/** 
* @DI\Service(id = "form.type.modelA") 
* @DI\Tag("form.type", attributes={ "alias":"model_a_type" }) 
*/ 
class FormAType extends AbstractType { 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
    $builder 
     ->add('A') 
     ->add('B') 
    ; 
    } 

    // getName and so on 
} 

/** 
* @DI\Service(id = "form.type.modelA") 
* @DI\Tag("form.type", attributes={ "alias":"model_b_type" }) 
*/ 
class FormAType extends AbstractType { 
    public function getParent() { 
    return "model_a_type"; 
    } 

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

    // getName and so on 
} 

Jeśli renderowanie formB, dostaniesz A, B, C porządku, ale ty chce A, C, B. Aby to zrobić, utwórz szablon formularza i dodaj odwołanie do aplikacji. plik konfiguracyjny:

#app/config/config.yml 
twig: 
    .... 
    form: 
     resources: 
      - YourAppBundle:Form:fields.html.twig 


{# src/YourAppBundle/Resources/views/Form/fields.html.twig #} 
{% block model_a_type_widget %} 
    {{ form_widget(form.A) }} 
    {{ form_widget(form.B) }} 
{% endblock model_a_type_widget %} 

{% block model_b_type_widget %} 
    {{ form_widget(form.A) }} 
    {{ form_widget(form.C) }} 

    {{ block('model_a_type_widget') }} 
{% endblock model_b_type_widget %} 

Teraz, gdy wyrenderujesz formęB, zobaczysz żądaną kolejność i utrzymasz kod w strukturze. Dzieje się tak, ponieważ każdy widget jest renderowany tylko raz, więc jeśli wyrenderujesz go przed wywołaniem bloku nadrzędnego, zmienisz ich kolejność.

9

Można zmienić kolejność pól wykorzystujące ten pakiet: https://github.com/egeloen/IvoryOrderedFormBundle

To pozwala robić rzeczy tak:

$builder 
->add('g', 'text', array('position' => 'last')) 
->add('a', 'text', array('position' => 'first')) 
->add('c', 'text') 
->add('f', 'text') 
->add('e', 'text', array('position' => array('before' => 'f'))) 
->add('d', 'text', array('position' => array('after' => 'c'))) 
->add('b', 'text', array('position' => 'first')); 

To miało być w rdzeniu, ale został odrzucony i wyciągnął do pakietu.

3

Miałem ten sam numer dzisiaj z zamawianiem elementów formularza.

skończyło się z cechą, która będzie nadpisać metodę finishView i zmienić kolejność elementów w dzieci własność FormView:

trait OrderedTrait 
{ 
    abstract function getFieldsOrder(); 

    public function finishView(FormView $view, FormInterface $form, array $options) 
    { 
     /** @var FormView[] $fields */ 
     $fields = []; 
     foreach ($this->getFieldsOrder() as $field) { 
      if ($view->offsetExists($field)) { 
       $fields[$field] = $view->offsetGet($field); 
       $view->offsetUnset($field); 
      } 
     } 

     $view->children = $fields + $view->children; 

     parent::finishView($view, $form, $options); 
    } 
} 

Następnie typu wdrożenie metody getFieldsOrder:

use OrderedTrait; 

function getFieldsOrder() 
{ 
    return [ 
     'first', 
     'second', 
     'next', 
     'etc.', 
    ]; 
} 
+1

jest to jeden w porządku, czysty rozwiązanie! Dzięki! – virtualize

+0

Łatwo jest rozszerzyć ten fragment kodu, aby dodać wagi do listy pól zwróconych przez getFieldsOrder, jeśli ktoś tego potrzebuje, proszę o kontakt. –

3

tutaj jest rozwiązanie wymyśliłem.

Stworzyłem klasę, którą rozszerzają moje typy.

namespace WF\CORE\CoreBundle\Form; 

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 

class WfBaseForm extends AbstractType 
{ 

    protected function useFields(FormBuilderInterface $builder, $fields) 
    { 
     foreach ($builder->all() as $field) { 

      if (!in_array($field->getName(), $fields)) 
       $builder->remove($field->getName()); 
     } 
    } 


    public function reorder(FormBuilderInterface $builder, $keys = array()) 
    { 
     $fields   = $builder->all(); 
     $ordered_fields = array_merge(array_flip($keys), $fields); 
     $this->useFields($builder, array()); 

     foreach($ordered_fields as $field) 
      $builder->add($field); 

    } 

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

Następnie można go używać w swoich odziedziczonych klasach.

class AddressType extends WfBaseForm 
{ 
public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     // I add as many fields as I need 
     $builder->add('…'); 
} 

Ta klasa rozszerza jeden nad

class ModifyAddressType extends BaseType 
{ 
    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     parent::buildForm($builder, $options); 

     $builder->add('title', 'text', array('constraints' => array(new NotBlank()))); 

     $this->reorder($builder, array('title', 'firstname', 'lastname')); 
    } 
} 
0

Można to zrobić bezpośrednio w sterowniku przed renderowanie szablonu:

$form = ... 

$view = $form->createView(); 

// Perform standard array operations to reorder: `$view->children` 
// Here's a very simple example: 

$firstField = $view->children['firstField']; 
unset($view->children['firstField']); 
$view->children['firstField'] = $firstField; 

return array('form' => $view); 

uasort działa tak samo, jednak usort tworzy niezespolona tablica, która później przerwie renderowanie formularza.

0
{{ form_start(form) }} 

    <div>{{ form_label(form.title) }}</div> 
    <div>{{ form_widget(form.title,{'id': 'blog_title'})}}</div> 

    <div>{{ form_label(form.tag) }}</div> 
    <div>{{ form_widget(form.tag,{'id': 'blog_tag'})}}</div> 

    <div>{{ form_label(form.category) }}</div> 
    <div>{{ form_widget(form.category,{'id': 'blog_category'})}}</div> 

    <div>{{ form_label(form.image) }}</div> 
    <div>{{ form_widget(form.image,{'id': 'blog_image'})}}</div> 

    <div>{{ form_label(form.body) }}</div> 
    <div>{{ form_widget(form.body,{'id': 'editor'})}}</div> 

    <input type="submit" class="btn btn-success" value="Create" /> 
{{ form_end(form) }}