如何在另一个选择框中使用相关的选择框?

i.a*_*iel 23 forms validation symfony doctrine-orm

如何在Symfony中使用相关的选择框?

比方说,我有一个包含compagnies的选择列表,另一个包含所选公司的员工.我如何在Symfony中定义它们?我已经创建了所有与Javascript相关的代码,但在提交表单并在某些字段上出错时,所有"sub"选择字段都将重置为null.

有任何想法吗?
谢谢,

编辑:由于这个问题似乎被误解了,我将添加一些精确性:

说明:

  1. 我有一个实体公司,其中包含使用@OneToMany关系的员工列表.
  2. 当我在选择/下拉列表中选择公司时,包含员工的第二个下拉列表将通过jQuery更新.那部分完成,完美地运作
  3. 在提交表单时没有错误,实体表单解决方案工作正常.
  4. 提交包含错误的表单时,第二个下拉列表包含所有可能的值.它们不会在选定的公司上过滤.

尝试的解决方案:

  • 我的第一个想法是使用表单实体类型,认为组件可以以某种方式绑定在另一个字段上.即.根据所选公司的价值更新员工列表.

不工作,没有办法开箱即用.即使是非开箱即用的解决方案......

  • 然后我考虑手动将所选公司作为参数传递给第二个下拉列表的查询构建器.

但是在创建表单时,值为空.这些值仅在bindRequest上设置.

  • 考虑使用选择类型.通过Javascript将所有过滤器功能委托给UI.页面加载时的含义,将显示一个空列表,并由Javascript根据所选公司填充.

这实际上是有效的,但我认为除了真正难看的编程之外别无他法.

PS:

这里有一个问题,在Symfony2邮件列表,Twitter和官方Symfony 2论坛上.在发布我的问题之前,我当然已经多次搜索过这些.

Flo*_*ian 13

关于你已经尝试过的,我认为你应该重试你的第一个/第二个想法:

我的第一个想法是使用表单实体类型,认为组件可以以某种方式绑定在另一个字段上.即.根据所选公司的价值更新员工列表.

您可以使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我考虑手动将所选公司作为参数传递给第二个下拉列表的查询构建器.

此处的示例根据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)
                ;
            },
        ))
    ;
}
Run Code Online (Sandbox Code Playgroud)

您仍然需要在类中实现getEmployee()setEmployee()方法Entity\Foo.

但是在创建表单时,值为空.这些值仅在bindRequest上设置.

不可以.使用表单工厂(第三个参数)创建表单时,或者在调用时设置值$form->setData($foo);.当您bind对表单的新输入时,将修改数据.

这种方法可能存在问题:绑定到表单的员工ID可能在表单选项列表中不可用,因为您更改了公司(以及员工).


rty*_*hyk 5

我有同样的问题.您必须使用表单事件.我的代码示例包含国家,地区,城市关系.

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

}
Run Code Online (Sandbox Code Playgroud)