I have three entities: Country, State and City with the following relationships:
When creating a City, I want two selectors, one for the Country and one for the State where the city belongs. These two selectors need to be chained so changing the Country will "filter" the States shown in the other selector.
I found a tutorial showing how to do this using Form Events but their example it's not quite my case. My entity City it's not directly related to the Country entity (they are indirectly related through State) so, when setting the country field in the City form (inside the class CityType), I'm forced to declare that field as 'property_path'=>false
as you can see in the code below:
class CityType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('country', 'entity', array(
'class'=>'TestBundle:Country',
'property'=>'name',
'property_path'=>false //Country is not directly related to City
));
$builder->add('name');
$factory = $builder->getFormFactory();
$refreshStates = function ($form, $country) use ($factory)
{
$form->add($factory->createNamed('entity', 'state', null, array(
'class' => 'TestTestBundleEntityState',
'property' => 'name',
'query_builder' => function (EntityRepository $repository) use ($country)
{
$qb = $repository->createQueryBuilder('state')
->innerJoin('state.country', 'country');
if($country instanceof Country) {
$qb->where('state.country = :country')
->setParameter('country', $country);
} elseif(is_numeric($country)) {
$qb->where('country.id = :country')
->setParameter('country', $country);
} else {
$qb->where('country.name = :country')
->setParameter('country', "Venezuela");;
}
return $qb;
}
)));
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (DataEvent $event) use ($refreshStates)
{
$form = $event->getForm();
$data = $event->getData();
if($data == null)
return;
if($data instanceof City){
if($data->getId()) { //An existing City
$refreshStates($form, $data->getState()->getCountry());
}else{ //A new City
$refreshStates($form, null);
}
}
});
$builder->addEventListener(FormEvents::PRE_BIND, function (DataEvent $event) use ($refreshStates)
{
$form = $event->getForm();
$data = $event->getData();
if(array_key_exists('country', $data)) {
$refreshStates($form, $data['country']);
}
});
}
public function getName()
{
return 'city';
}
public function getDefaultOptions(array $options)
{
return array('data_class' => 'TestTestBundleEntityCity');
}
}
The problem is that when I try to edit an existing City, the related Country is not selected by default in the form. If I remove the line 'property_path'=>false
I get (not surprisingly) the error message:
Neither property "country" nor method "getCountry()" nor method "isCountry()" exists in class "TestTestBundleEntityCity"
Any ideas?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…