Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The choice "464" does not exist or is not unique #8

Open
artscorestudio opened this issue Mar 29, 2017 · 18 comments
Open

The choice "464" does not exist or is not unique #8

artscorestudio opened this issue Mar 29, 2017 · 18 comments
Labels

Comments

@artscorestudio
Copy link

Hi,
I do not understand why but I still have the following error: "The choice "464" does not exist or is not unique". By doing tests, I get into the "subscriber", the "choices" array is populated but the error is still there.

In the profiler, I have the following information after submission :

Default Data :
    Model Format : same as normalized format
    Normalized format : null
    View format : 464

Submitted Data :
    View format : 464
    Normalized format : null
    Model Format : same as normalized format

Passed options :
    choices : [0 => Object(Proxies\......MyEntity)]

Can you help me ?

@Alsatian67
Copy link
Owner

Which Type (Choice/Entity/Document) are you using ?
How do you use it ?

@artscorestudio
Copy link
Author

Hi,

I use an Entity.

In my form :

$builder->add('arriveIn', ExtensibleEntityType::class, array(
            'choices' => array(), // Prevent default EntityType behavior (load all entities)
            'label' => 'Service',
            'route' => 'ref_service_search_all',
            'class' => 'AppBundle:Service',
            'choice_label' => 'name',
        ));

The subscriber (Alsatian\FormBundle\Form\Extensions\ExtensibleSubscriber) do his job on PRE_SET_DATA and PRE_SUBMIT :

// [...]
$form->add($childName, $type['originalType'], $options);
if ( $childName == 'arriveIn' ) { // For testing choices are populated - it's OK.
    dump($form->get($childName)->getConfig()->getOptions()['choices']);
}

Note : I have 5 fields in the form with the ExtensibleEntityType. But I don't think it's the problem.

@artscorestudio
Copy link
Author

When I dig in Form mechanism, I found this :

  1. EntityType use \Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer on this types of fields.
  2. ChoiceToValueTransformer use \Symfony\Component\Form\ChoiceList\ArrayChoiceList::getChoicesForValues for load choice list
  3. getChoicesForValues() use $this->choices who is generated with the parameter in form type options.
  4. form type options is empty array() but your subscriber fill it normaly... no ?

@Alsatian67
Copy link
Owner

Alsatian67 commented Mar 29, 2017

First of all, try to remove choices' => array() by your form definition.

It is already set here

Where is your exception thrown ?
From the subscriber ?

if yes :
on pre_set_data, or on pre_submit ?

Is 674 the id of a submitted AppBundle:Service entity ?

@artscorestudio
Copy link
Author

Both of them. I tested to inject a Service entity mapped in arriveIn field. I pass through the subscriber, it does its job but nothing... no option tag... it's like the $form in subscriber it's ont the same as the $form create in controller.

Otherwhise, the exception is thrown in transformer on PRESUBMIT. Logic, because the list is empty.

@Alsatian67
Copy link
Owner

Did you try to remove your choices => array() ?

@artscorestudio
Copy link
Author

Yes

@artscorestudio
Copy link
Author

I will try to do the same thing again in a clean symfony version. For information I am under symfony 2.8.*. I will make you a return.

@Alsatian67
Copy link
Owner

I wrote this bundle using the 2.8 version ...

My subscriber works with a priority of -50 :
https://github.com/Alsatian67/FormBundle/blob/master/Form/Extensions/ExtensibleSubscriber.php#L29

May be you have some other listener acting after my PRE_SUBMIT event ?
I can't find the official doc about built in listeners priority anymore :(

@Alsatian67 Alsatian67 added the bug label Mar 29, 2017
@artscorestudio
Copy link
Author

Hi,

I tested your bundle on a fresh Symfony 2.8.18... and I have the same behavior. Maybe I missed something...

I started by the view :

{% extends 'base.html.twig' %}
{% block body %}
    {{ form_start(form) }}
    {{ form_row(form) }}
    <input type="submit" value="Ajouter" />
    {{ form_end(form) }}
{% endblock %}

The Form :

class MyFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('service', ExtensibleEntityType::class, array(
            'choice_label'=>'name',
            'class' => 'AppBundle\Entity\Service',
            'placeholder' => 'Veuillez sélectionner un service'
        ));
    }
    
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\MyEntity'
        ));
    }
    
    public function getBlockPrefix()
    {
        return 'my_form';
    }
    
    public function getName()
    {
        return $this->getBlockPrefix();
    }
}

The controller :

public function indexAction(Request $request)
{
        $myEntity = new MyEntity();
        $form = $this->createForm(MyFormType::class, $myEntity);
        $form->handleRequest($request);
        
        if ( $form->isSubmitted() && $form->isValid() ) {
            $myEntity = $form->getData();
        }
        
        return $this->render('AppBundle:default:index.html.twig', array(
            'form' => $form->createView()
        ));
}

MyEntity entity :

class MyEntity
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     * 
     * @var integer
     */
    private $id;
    
    /**
     * @ORM\ManyToOne(targetEntity="Service")
     * @ORM\JoinColumn(nullable=false)
     * @Assert\NotNull()
     * 
     * @var \AppBUndle\Entity\Service
     */
    private $service;
}

Service entity :

class Service
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     *
     * @var integer
     */
    private $id;
    
    /**
     * @ORM\Column(type="string", nullable=false)
     * @Assert\NotNull()
     * 
     * @var string
     */
    private $name;
}

@Alsatian67
Copy link
Owner

Et si on parlait français, ce serait peut-être plus simple ?

En fait je sais pas trop d'où vient ton problème.
Il faut que je teste deux trois trucs pour voir ce que ça peut être. C'est aussi possible que Symfony a changé quelque chose depuis aout 2016 (y compris sur Symfony 2.8) en corrigeant un bug ...

J'ai vu que plusieurs commits ont changé ce qui touche à l'EntityType que je surcharge ...

Je n'utilise plus du tout symfony depuis plusieurs mois et je ne pas si mon bundle marche encore sur mon application, je vais m'y replonger pour y répondre, mais j'ai pas trop le temps avant plusieurs jours.

Ce que tu peux faire pour débuguer :

  • Quand tu fais un dump() dans le listener, vérifie bien que tu ne le fais que dans PRE_SUBMIT, car même quand tu soumets un formulaire, symfony va d'abord appeler le listener en PRE_SET_DATA et ensuitement seulement en PRE_SUBMIT, du coup tu as peut etre dumpé le résultat de PRE_SET_DATA

  • Après faudrait lire la configuration du form et regarder quels sont les autres listeners qui y sont attachés (y compris les "built in")

  • Rajouter un evenement SUBMIT et un POST_SUBMIT, pour voir si les choix définis dans PRE_SUBMIT sont encore là

Voilà ce que tu peux faire en attendant ...

Je teste dès que j'ai le temps

@artscorestudio
Copy link
Author

J'ai fais les tests sur tous les événements, et la modification est bien prise en compte pratout.
Lorsque je reviens sur mon formulaire après soumission, mon option injecté pendant le PRE_SUBMIT est bien présente dans la rubrique "passed options".

Je crois que j'ai levé un loup, le noeud du problème est que le transformer dans son reverse_transform fait appel au loader ArrayChocieList qui pour contrôler les options fait :

foreach ($values as $i => $givenValue) {
            if (array_key_exists($givenValue, $this->choices)) {
                $choices[$i] = $this->choices[$givenValue];
            }
        }

Le $this->choices fait référence à la liste des choix que l'on donne dans configureOptions() du FormType. Sauf qu'à l'initialisation, il n'y en a pas... d'où l'erreur.

Ce qui n'est pas normal, c'est qu'on la modifie cette liste via PRE_SUBMIT et PRE_SET_DATA mais la modification n'est pas prise en compte à ce niveau là.

@artscorestudio
Copy link
Author

J'ai avancé,

Lorsque j'édite une entité qui a un service de renseigné (entité Service mappé sur le champ service), le PRE_SET_DATA fonctionne si et seulement si je définie un buildView() de mon formulaire MyFormType.

Par contre, lorsque je soumet le formulaire, toujours rien.

@Alsatian67
Copy link
Owner

Alsatian67 commented Apr 3, 2017

Bizarre,

chez moi j'ai tout mis à jour, (sur symfony 3.2), j'ai tout re-testé et tout fonctionne toujours très bien.
Dans mon app, mes formtypes n'ont pas de configuration particulière, juste le minimum requis.

Peut-tu me faire un genre de fork minimal qui reproduit le bug ?

@artscorestudio
Copy link
Author

Je vais te mettre dans un dépôt le symfony 2.8 et ton bundle.

@artscorestudio
Copy link
Author

capture

Je sais si cela va te parler mais voilà ce que me ressort la debug toolbar après soumission du formulaire.

@Pasuvan
Copy link

Pasuvan commented Oct 23, 2019

I have the same issue did you resolved above issue, if yes then can you explain?

@Alsatian67
Copy link
Owner

Alsatian67 commented Nov 12, 2019

I could not reproduce the same issue. It is till open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants