Возможно ли иметь поле сбора в форме Symfony2 с различными вариантами выбора? - PullRequest
3 голосов
/ 06 января 2012

У меня есть поле коллекции с элементами выбора типа в моей форме Symfony. У каждого элемента должен быть свой список выбора. Как я могу организовать это в Symfony2? Я не могу использовать опцию choices, потому что у каждого элемента будет одинаковый выбор. Я видел опцию choice_list , которая принимает объект, который может генерировать список опций, но я не вижу, как он может создать разные варианты для разных элементов в коллекции.

Есть идеи, как с этим бороться?

1 Ответ

3 голосов
/ 10 августа 2012

Я думаю, вам нужно событие формы: http://symfony.com/doc/current/cookbook/form/dynamic_form_generation.html.

Чтобы изменить способ создания коллекции по умолчанию.

Основная форма проста:

namespace Acme\Bundle\AcmeBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

use Acme\Bundle\AcmeBundle\Form\DescriptorDumpFieldsType;

class TranscodingType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('descriptorDumpFields', 'collection', array('type' => new DescriptorDumpFieldsType()));
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'Acme\Bundle\AcmeBundle\Entity\Descriptor',
        );
    }

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

Просто простая форма с набором подформ.

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

Таким образом, первая форма создается нормально и добавляет множество DescriptorDumpFieldsType, которые создаются динамически.

namespace Acme\Bundle\AcmeBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormTypeInterface;

use Acme\Bundle\AcmeBundle\Form\EventListener\TranscodingSubscriber;

class DescriptorDumpFieldsType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $subscriber = new TranscodingSubscriber($builder->getFormFactory());
        $builder->addEventSubscriber($subscriber);
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'data_class' => 'Acme\Bundle\AcmeBundle\Entity\DescriptorDumpField',
        );
    }

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

Подписчик формы:

namespace Acme\Bundle\AcmeBundle\Form\EventListener;

use Symfony\Component\Form\Event\DataEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;

use Acme\Bundle\AcmeBundle\Entity\DumpField;

use Acme\Bundle\AcmeBundle\Form\Transcoding\DataTransformer\JsonToHumanDateTransformer;

class TranscodingSubscriber implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        return array(FormEvents::SET_DATA => 'setData');
    }

    public function setData(DataEvent $event)
    {
        $data = $event->getData();
        $form = $event->getForm();

        if (!is_null($data)) {
            $this->buildForm($data, $form);            
        }
    }

    protected function buildForm($data, $form)
    {
        switch ($data->getDumpField()->getType()) {
            case DumpField::TYPE_ENUM:
                $type = 'enum'.ucfirst($data->getDumpField()->getKey());
                $class = 'dump_field_'.strtolower($data->getDumpField()->getKey());
                $form->add($this->factory->createNamed('collection', 'transcodings', null, array('required' => false, 'type' => $type, 'label' => $data->getDumpField()->getKey(), 'attr' => array('class' => $class))));
                break;
            case DumpField::TYPE_DATE:
                $transformer = new JsonToHumanDateTransformer();
                $class = 'dump_field_'.strtolower($data->getDumpField()->getKey());
                $builder = $this->factory->createNamedBuilder('human_date', 'params', null, array('label' => $data->getDumpField()->getKey(), 'attr' => array('class' => $class)));
                $builder->prependNormTransformer($transformer);
                $form->add($builder->getForm());
                break;
        }
    }
}

Итаквы можете настроить, как вы хотите, каждую подформу формы в buildForm.

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