如何在Symfony中使用相关的选择框?
让我们说,我有一个包含公司的选择列表,另一个包含所选公司的员工。我如何在Symfony中定义它们? 我已经创建了所有与Javascript相关的代码,但在提交表单并在某些字段上出错时,所有" sub"选择字段重置为null。
任何想法?
谢谢,
编辑:由于这个问题似乎被误解了,我会增加一些准确性:
不工作,没有办法开箱即用。即使是没有开箱即用的解决方案......
但是在创建表单时,值为空。这些值仅在 bindRequest 。
上设置这实际上有效,但我认为除了真正难看的编程之外别无他法。
此处已在Symfony2邮件列表,Twitter和官方Symfony 2论坛上提出问题。在发布我的问题之前,我当然已经多次搜索过这些内容。
答案 0 :(得分: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);
}
}
然后我考虑手动将所选公司作为 第二个下拉列表的查询构建器的参数。
此处的示例根据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。
没有。使用表单工厂(第三个参数)创建表单时设置值,
或者当你致电$form->setData($foo);
时。当您bind
表单的新输入时,数据会被修改。
这种方法可能存在问题:绑定到表单的员工ID可能在表单选项列表中不可用,因为您更改了公司(以及员工)。
答案 1 :(得分: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']);
}
});
}
}
答案 2 :(得分:1)
您可以创建操作,即与公司员工一起返回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>
有关详细示例,请更详细地描述您的问题。