Подтвердить что ты не робот

Как использовать поле выбора, связанное с другим полем выбора?

Как использовать соответствующие флажки в Symfony?

Скажем, у меня есть список выбора, содержащий команды и другие, содержащие сотрудников выбранной компании. Как определить их в Symfony? Я уже создал весь код, связанный с Javascript, но при отправке моей формы и наличии ошибок в некоторых полях все поля выбора "под" reset равны null.

Любые идеи? Спасибо,

РЕДАКТИРОВАТЬ: Поскольку вопрос, кажется, неправильно понят, я добавлю некоторые замечания:

Описание:

  • У меня есть компания, содержащая список сотрудников, использующих отношение @OneToMany.
  • Когда я выбираю компанию в списке выбора/выпадающего списка, второй раскрывающийся список, содержащий сотрудников, обновляется через jQuery. Эта часть выполнена, отлично работает
  • При отправке формы без ошибок решение формы формы отлично работает.
  • При отправке формы, содержащей ошибки, второй раскрывающийся список содержит все возможные значения. Они не фильтруются в выбранной компании.

Пробные решения:

  • Моя первая идея заключалась в том, чтобы использовать тип form entity, считая, что компонент может быть привязан каким-то образом к другому полю. то есть. обновить список сотрудников на основе стоимости выбранной компании.

Не работает, для этого нет выхода. Даже нестандартные решения...

  • Затем я подумал о переносе вручную выбранной компании как параметр в построитель запросов второго раскрывающегося списка.

Но когда форма создана, значения пустые. Значения устанавливаются только на bindRequest.

  • Мысль об использовании типа выбора. Делегирование всей функциональности фильтра в пользовательский интерфейс через Javascript. Значение, когда загружается страница, появляется пустой список и заполняется Javascript на основе выбранной компании.

Это действительно работает, но я думаю, что здесь нет другого слова, кроме действительно действительно уродливого программирования.

PS:

Вопрос задан здесь, в рассылке Symfony2, в Twitter и на официальном форуме Symfony 2. Я, конечно, искал каждый из них несколько раз, прежде чем отправлять свои вопросы.

4b9b3361

Ответ 1

Относительно того, что вы уже пробовали, я думаю, вам следует повторить свои первые/второй идеи:

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

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

class FooType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            ->add('employee', 'entity', array(
                'class' => 'Entity\Employee',
                'query_builder' => function ($repository) use($options) {
                    return $repository
                        ->createQueryBuilder('e')
                        ->where('e.company = :company')
                        ->setParameter('company', $options['companyId'])
                    ;
                },
            ))
        ;
    }

    public function getDefaultOptions(array $options)
    {
        return array('data_class' => 'Entity\Foo', 'companyId' => null);
    }
}

Затем я подумал о том, чтобы вручную передать выбранную компанию как для конструктора запросов второго раскрывающегося списка.

Здесь приведен пример фильтра списка сотрудников на основе опции companyId. Вы можете изменить это поведение, напрямую фильтруя компанию, присутствующую в данных формы.

public function buildForm(FormBuilder $builder, array $options)
{
    $companyId = $builder->getData()->getCompanyId();
    $builder
        ->add('employee', 'entity', array(
            'class' => 'Entity\Employee',
            'query_builder' => function ($repository) use ($companyId) {
                return $repository
                    ->createQueryBuilder('e')
                    ->where('e.company = :company')
                    ->setParameter('company', $companyId)
                ;
            },
        ))
    ;
}

Вам еще нужно реализовать методы getEmployee() и setEmployee() в вашем классе Entity\Foo.

Но когда форма создана, значения пустые. Значения устанавливаются только bindRequest.

Нет. Значения задаются при создании формы с помощью формы factory (третий аргумент), ИЛИ, когда вы вызываете $form->setData($foo);. Данные изменяются, когда вы bind вводите новые формы в форму.

Может возникнуть проблема с этим подходом: возможно, что идентификатор сотрудника, связанный с формой, недоступен в списке выбора формы, поскольку вы изменили компанию (и, следовательно, сотрудников).

Ответ 2

У меня была та же проблема. Вы должны использовать события формы. Мой пример кода с указанием страны, региона, города.

namespace Orfos\UserBundle\Form\Type;

///import form events namespace
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Event\DataEvent;

class RegistrationFormType extends BaseType
{

    private $request;

    public function __construct($class, $request, $doctrine)
    {
        parent::__construct($class);
        $this->request = $request;
        $this->doctrine = $doctrine;
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        parent::buildForm($builder, $options);
        //other fields

        $locale = $this->request->getLocale();

        $builder->add('country', 'entity', array(
            'class' => 'Orfos\CoreBundle\Entity\Country',
            'property' => $locale . 'name',
            'label' => 'register.country.label',
            'query_builder' => function(EntityRepository $er) {
                return $er->createQueryBuilder('c')
                                ->select('c', 't')
                                ->join('c.translations', 't');
            },
        ));

        $factory = $builder->getFormFactory();
        $refreshRegion = function ($form, $country) use ($factory, $locale) {
                    $form->add($factory->createNamed('entity', 'region', null, array(
                                'class' => 'Orfos\CoreBundle\Entity\Region',
                                'property' => $locale . 'name',
                                'label' => 'register.region.label',
                                'query_builder' => function (EntityRepository $repository) use ($country) {
                                    $qb = $repository->createQueryBuilder('region')
                                            ->select('region', 'translation')
                                            ->innerJoin('region.country', 'country')
                                            ->join('region.translations', 'translation');

                                    if ($country instanceof Country) {
                                        $qb = $qb->where('region.country = :country')
                                                ->setParameter('country', $country);
                                    } elseif (is_numeric($country)) {
                                        $qb = $qb->where('country.id = :country_id')
                                                ->setParameter('country_id', $country);
                                    } else {
                                        $qb = $qb->where('country.id = 1');
                                    }

                                    return $qb;
                                }
                            )));
                };
        $factory = $builder->getFormFactory();
        $refreshCity = function($form, $region) use ($factory, $locale) {
                    $form->add($factory->createNamed('entity', 'city', null, array(
                                'class' => 'Orfos\CoreBundle\Entity\City',
                                'property' => $locale . 'name',
                                'label' => 'register.city.label',
                                'query_builder' => function (EntityRepository $repository) use ($region) {
                                    $qb = $repository->createQueryBuilder('city')
                                            ->select('city', 'translation')
                                            ->innerJoin('city.region', 'region')
                                            ->innerJoin('city.translations', 'translation');

                                    if ($region instanceof Region) {
                                        $qb = $qb->where('city.region = :region')
                                                ->setParameter('region', $region);
                                    } elseif (is_numeric($region)) {
                                        $qb = $qb->where('region.id = :region_id')
                                                ->setParameter('region_id', $region);
                                    } else {
                                        $qb = $qb->where('region.id = 1');
                                    }

                                    return $qb;
                                }
                            )));
                };

        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (DataEvent $event) use ($refreshRegion, $refreshCity) {
                    $form = $event->getForm();
                    $data = $event->getData();

                    if ($data == null){
                        $refreshRegion($form, null);
                        $refreshCity($form, null);
                    }

                    if ($data instanceof Country) {
                        $refreshRegion($form, $data->getCountry()->getRegions());
                        $refreshCity($form, $data->getRegion()->getCities());
                    }
                });

        $builder->addEventListener(FormEvents::PRE_BIND, function (DataEvent $event) use ($refreshRegion, $refreshCity) {
                    $form = $event->getForm();
                    $data = $event->getData();

                    if (array_key_exists('country', $data)) {
                        $refreshRegion($form, $data['country']);
                    }
                    if (array_key_exists('region', $data)) {
                        $refreshCity($form, $data['region']);
                    }                    
                });
    }

}

Ответ 3

Вы можете создать действие, которое будет возвращать массив json с сотрудниками компании. Когда список компаний изменился, вы должны запросить это действие с помощью ajax и создать список сотрудников.

Действие контроллера формы:

/**
 * @Route("/job", name="_demo_job")
 * @Template()
 */
public function jobAction()
{
    $form = $this->createForm(new JobType());

    $request = $this->getRequest();
    if ($request->getMethod() == 'POST') {
        $form->bindRequest($request);
        $data = $form->getData();
        // some operations with form data
    }

    return array(
        'form' => $form->createView(),
    );
}

Conroller, который возвращает сотрудников компании в json:

/**
 * Finds all employees by company
 *
 * @Route("/{id}/show", name="employees_by_category")
 */
public function listByCompanyAction($id)
{
    $request = $this->getRequest();

    if ($request->isXmlHttpRequest() && $request->getMethod() == 'POST') {
        $em = $this->getDoctrine()->getEntityManager();

        $company = $em->getRepository('AcmeDemoBundle:Company')->find($id);

        // create array for json response
        $empoloyees = array();
        foreach ($company->getEmployees() as $employee) {
            $empoloyees[] = array($employee->getId(), $employee->getName());
        }

        $response = new Response(json_encode($empoloyees));
        $response->headers->set('Content-Type', 'application/json');

        return $response;
    }
    return new Response();
}

Шаблон формы:

<script type="text/javascript">
    $(document).ready(function() {
        $('#form_company').change(function() {
            var companyId = $(this).val();
            $.post('{{ route }}/' + companyId + '/show', function(data) {
                // last selected employee
                var selectedVal = $('option:selected', '#form_employee').attr('value');

                $('#form_employee option').remove();
                for (i in data) {
                    // create option with employee
                    var option = $('<option></option>').
                        attr('value', data[i][0]).
                        text(data[i][1]);
                    // set selected employee
                    if (data[i][0] == selectedVal) {
                        option.attr('selected', 'selected');
                    }
                    // append to employee to employees select
                    $('#form_employee').append(option);
                }
            }, 'json');
        })

        // request employees by company
        $('#form_company').change();
    })

</script>
<form action="{{ path('_demo_job') }}" method="post" {{ form_enctype(form) }}>
    {{ form_widget(form) }}

    <input type="submit" />
</form>

Для более подробного примера вы должны более подробно описать свою проблему.