Estendendo o EntityType para permitir opções extras definidas com chamadas AJAX
Eu tento criar um tipo personalizado do Symfonyestendendo o nucleo "entidade" tipo.
Mas eu quero usá-lo comSelect2 versão 4.0.0 (o ajax agora funciona com o elemento html "select" e não com a "entrada" oculta como antes).
Esse tipo deve criar uma seleção vazia em vez da lista completa de entidades pelo tipo "entidade" estendido.Isso funciona configurando a opção (consulte configureOption):
'choices'=>array()
Ao editar o objeto anexado ao formulário, ele deve preencher a seleção com os dados atuais do objeto. Resolvi esse problema, mas apenas para a visualização com o seguinte método buildView ...Select2 reconhece o conteúdo do html "select" e faz seu trabalho com ajax. Mas quando o formulário é enviado de volta, o Symfony não reconhece as opções selecionadas (porque não eram permitidas?)
Symfony\Component\Form\Exception\TransformationFailedException
Unable to reverse value for property path "user": The choice "28" does not exist or is not unique
Tentei vários métodos usando EventListeners ou Subscribers, mas não consigo encontrar uma configuração funcional.
Com o Select2 3.5. * Resolvi o problema com eventos de formulário e substituindo o tipo de formulário oculto, mas aqui a extensão do tipo de entidade é muito mais difícil.
Como posso criar meu tipo para permitir que ele gerencie a transformação reversa dos meus direitos?
Tipo personalizado:
<?php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
class AjaxEntityType extends AbstractType
{
protected $router;
public function __construct($router)
{
$this->router = $router;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->setAttribute('attr',array_merge($options['attr'],array('class'=>'select2','data-ajax--url'=>$this->router->generate($options['route']))));
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['attr'] = $form->getConfig()->getAttribute('attr');
$choices = array();
$data=$form->getData();
if($data instanceOf \Doctrine\ORM\PersistentCollection){$data = $data->toArray();}
$values='';
if($data != null){
if(is_array($data)){
foreach($data as $entity){
$choices[] = new ChoiceView($entity->getAjaxName(),$entity->getId(),$entity,array('selected'=>true));
}
}
else{
$choices[] = new ChoiceView($data->getAjaxName(),$data->getId(),$data,array('selected'=>true));
}
}
$view->vars['choices']=$choices;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array('route'));
$resolver->setDefaults(array('choices'=>array(),'choices_as_value'=>true));
}
public function getParent() {
return 'entity';
}
public function getName() {
return 'ajax_entity';
}
}
Formulário pai
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AlarmsType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name','text',array('required'=>false))
->add('user','ajax_entity',array("class"=>"AppBundle:Users","route"=>"ajax_users"))
->add('submit','submit');
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('data_class' => 'AppBundle\Entity\Alarms','validation_groups'=>array('Default','form_user')));
}
/**
* @return string
*/
public function getName()
{
return 'alarms';
}
}