Skip to content

Form validator guesser problem #11871

@rhorv

Description

@rhorv

Hi,

I think I may have found a bug in ValidatorTypeGuesser , either that or this is quite an unexpected behavior.

Validator guesser for required (guessRequired) does not seem to work properly when there is no constraint defined for a given property at all.
The documentation says: "The required option can be guessed based on the validation rules (i.e. is the field NotBlank or NotNull)"
Which seems to be confirmed by the source code comments in ValidatorTypeGuesser.php:

// If we don't find any constraint telling otherwise, we can assume
// that a field is not required (with LOW_CONFIDENCE)

however this is not happening if no constraints are defined at all, it does work properly when a non-related constraint is defined (any constraint)

to reproduce:

The form:

class TestFormType extends AbstractType 
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add("name")
            ->add("comments");
    }
    public function getName()
    {
        return "test_form";
    }
}

The entity:

class TestEntity
{
    private $name;
    private $comments;

// ... getters and setters ...
}

The validator:

<class name="FormExperiment\TestBundle\Entity\TestEntity">
        <property name="name">
            <constraint name="NotBlank" />
        </property>
    </class>

and in the controller simply:

$form = $this->createForm(new TestFormType(), new TestEntity());

and then just pass $form->createView() to the template

Expected behavior:
name has required="required", and comments doesn't have it.

What actually happens:
Both name and comments have required="required"

If you add any constraint to 'comments', like:

        <property name="comments">
            <constraint name="Length">
                <option name="max">5</option>
            </constraint>
        </property>

then it will guess the required option properly (in this case required is false since the constraint is not NotNull or NotBlank)

even more bizarre that if I override the default in the form type with:

public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'required' => false
            ));
    }

then both will miss required="required" regardless of the guessing altogether, seems like the default option is stronger than anything else.

I managed to trace the problem and make the guesser work though:
The main problem is that since constraints are not present for comments at all the whole guessing is skipped here (ValidatorTypeGuesser.php):

    protected function guess($class, $property, \Closure $closure, $defaultValue = null)
    {
        $guesses = array();
        $classMetadata = $this->metadataFactory->getMetadataFor($class);

       if ($classMetadata->hasMemberMetadatas($property)) {
            $memberMetadatas = $classMetadata->getMemberMetadatas($property);

            foreach ($memberMetadatas as $memberMetadata) {
                $constraints = $memberMetadata->getConstraints();

                foreach ($constraints as $constraint) {
                    if ($guess = $closure($constraint)) {
                        $guesses[] = $guess;
                    }
                }
            }

            if (null !== $defaultValue) {
                $guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE);
            }
        }

        return Guess::getBestGuess($guesses);
    }

the condition if ($classMetadata->hasMemberMetadatas($property)) skips the entire guess because of this. this condition does not seem to be neccessary since in the next line:
$memberMetadatas = $classMetadata->getMemberMetadatas($property);

getMemberMetadatas has a guard for missing metadata anyway and returns an empty array in that case which then skips through the foreach and does a false valueguess for required as it should.
If I remove this condition everything works fine. the guess actually makes it through and works properly. I could not find a good reason why this condition is here but someone more familiar with the code might know better.

Regards

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy