Skip to content

[Form] Form validates although invalid choice is given with expanded=true  #5113

Closed
@frastel

Description

@frastel

In Symfony 2.0 a form is not valid when an unknown/invalid choice value is bound to a form. It does not matter if the type option expanded is set to true or false.
However with the latest changes in the Symfony master the form is now valid with this invalid choice. The invalid choice "is lost" somewhere in the form workflow and so the field is validated successfully because its value is empty and not required.
When the expanded=true option is set in the type everything is working as expected.
Besides one can pass anything as invalid choice, a string, an array the result is always the same: the form validates and the resulting field value is null. It also does not matter if the choice type gets the optional Choice constraint assigned.

Here two example test cases (without namespaces) for Symfony 2.0 and 2.1

Test case for Symfony 2.0 (form is not valid: OK):

require_once dirname(__DIR__).'/../../../app/AppKernel.php';

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Validator\Constraints\Choice;

/**
 * Test case
 */
class InvalidChoiceType20Test extends \PHPUnit_Framework_TestCase
{
    private $container;

    protected function setUp()
    {
        $this->kernel = new \AppKernel('test', true);
        $this->kernel->boot();

        $this->container = $this->kernel->getContainer();
    }

    /**
     * @group invalidchoice
     */
    public function testInvalidChoice()
    {
        $type = new WhatChoiceType();

        $form = $this->container->get('form.factory')->createBuilder($type)->getForm();
        $form->bind(array(
            'what' => 'baz' //invalid choice should fail
        ));

        print_r($form->getErrors());
        //print_r($form->get('something')->getErrors());
        $this->assertFalse($form->isValid());
    }
}

class WhatChoiceType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $choices = array('foo' => 'FOO!', 'bar' => 'BAR?');

        $options = array(
            'label' => 'Your choice',
            'choices' => $choices,
            'multiple' => false,
            'expanded' => true,
        );
        $builder->add('what', 'choice', $options);
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'csrf_protection' => false
        );
    }

    public function getName()
    {
        return 'what';
    }
}

Test case for Symfony 2 master (form is valid: FAIL!):

require_once dirname(__DIR__).'/../../../../../app/AppKernel.php';

use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Choice;

/**
 * Test case
 */
class InvalidChoiceType21Test extends \PHPUnit_Framework_TestCase
{
    private $container;

    protected function setUp()
    {
        $this->kernel = new \AppKernel('test', true);
        $this->kernel->boot();

        $this->container = $this->kernel->getContainer();
    }

    /**
     * @group invalidchoice
     */
    public function testInvalidChoice()
    {
        $whatType = new WhatChoiceType();

        $form = $this->container->get('form.factory')->createBuilder($whatType, null, array('csrf_protection' => false))->getForm();
        $form->bind(array(
            'what' => 'baz' //invalid choice should fail
        ));

        print_r($form->getErrors());
        //print_r($form->get('framework')->getErrors());
        $this->assertFalse($form->isValid());
    }

}

class WhatChoiceType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $choices = array('foo' => 'FOO!', 'bar' => 'BAR?');

        $options = array(
            'label' => 'Your choice',
            'choices' => $choices,
            'multiple' => false,
            'expanded' => true,
            'constraints' => new Choice(array(
                'multiple' => false,
                'choices' => array_keys($choices),
                'message' => 'Plz choose sth'
            ))
        );
        $builder->add('what', 'choice', $options);
    }

    public function getName()
    {
        return 'what';
    }
}

Maybe we are missing something, but we could not get it running.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions