8000 "cascade_validation" option not working at third level in beta4 · Issue #5204 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

"cascade_validation" option not working at third level in beta4 #5204

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

Closed
arnaugm opened this issue Aug 7, 2012 · 18 comments
Closed

"cascade_validation" option not working at third level in beta4 #5204

arnaugm opened this issue Aug 7, 2012 · 18 comments
Labels

Comments

@arnaugm
Copy link
arnaugm commented Aug 7, 2012

I have a form with three levels of nesting. Imagine a group, which has users, which have phone numbers.
The GroupType has the option cascade_validation => true, and a collection of UserType.
The UserType has the option cascade_validation => true, and a collection of PhoneType.

I have validations defined for the three entities in the file validation.yml, simple NotBlank validations.
The validations of Group and User work perfectly and I get the error when I try to submit the form with blank fields, but if I let the fields of the Phone empty, the form goes ahead and causes a db error because is receiving a null for a non null column.

The issue is in beta4, I haven't had time to test it in the RC1, even I haven't seen anything related in the change log.

@Tobion
Copy link
Contributor
Tobion commented Aug 10, 2012

I can confirm this issue.

You can work around that by setting the Valid constraint on your collection.

@arnaugm
Copy link
Author
arnaugm commented Aug 11, 2012

Problem only half solved.

Now my validation.yml file looks like this

Manager\UsersBundle\Entity\User:
    properties:
        name:
            - NotBlank:
                message: The name can not be blank
        phones:
            - Valid: ~

Manager\UsersBundle\Entity\Phone:
    properties:
        number:
            - NotBlank:
                message: The number can not be blank

The validation is now correctly executed because $form->isValid() returns false.
Debugging I can see the error in the field, but the error message is not printed anywhere. I've played with {{ form_errors(form) }}, {{ form_errors(form.phones) }} and all the possible options in the templates, and nothing. I also tried setting 'error_bubbling' => false / true, in the PhoneType and no result.

@arnaugm
Copy link
Author
arnaugm commented Aug 13, 2012

Related to that but not sure if the issue is exactly the same.
Also in a third level of nesting. Websites and Emails are both one to many relations with the same configuration. The first validation is executed, but not the second one.

Manager\UsersBundle\Entity\User:
    properties:
        websites:
            - Count:
                min: 1
                minMessage: You must add at least one website
        emails:
            - Count:
                min: 1
                minMessage: You must add at least one email

This is the doctrine configuration in User.orm.yml

Manager\UsersBundle\Entity\User:
  type: entity
  repositoryClass: Manager\UsersBundle\Repository\UserRepository
  table: users
  fields:
    id:
      id: true
      type: integer
      unsigned: false
      nullable: false
      generator:
        strategy: AUTO
    username:
      type: string
      length: 255
      fixed: false
      nullable: false
      unique: true
    password:
      type: string
      length: 255
      fixed: false
      nullable: false
    salt:
      type: string
      length: 255
      fixed: false
      nullable: false
    created:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: create
    updated:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: update
  manyToOne:
    group:
      targetEntity: Group
      inversedBy: users
      joinColumns:
        group_id:
          referencedColumnName: id
          nullable: false
  oneToMany:
    phones:
      targetEntity: Phone
      mappedBy: user
      cascade: ["persist", "remove"]
      orphanRemoval: true
    websites:
      targetEntity: Website
      mappedBy: user
      nullable: true
      cascade: ["persist", "remove"]
      orphanRemoval: true
    emails:
      targetEntity: Email
      mappedBy: user
      nullable: true
      cascade: ["persist", "remove"]
      orphanRemoval: true
  lifecycleCallbacks: {  }

and the related entities

Manager\UsersBundle\Entity\Website:
  type: entity
  repositoryClass: Manager\UsersBundle\Repository\WebsiteRepository
  table: websites
  fields:
    id:
      id: true
      type: integer
      unsigned: false
      nullable: false
      generator:
        strategy: AUTO
    url:
      type: string
      length: null
      fixed: false
      nullable: false
    isMain:
      type: boolean
      length: null
      fixed: false
      nullable: true
      column: is_main
    created:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: create
    updated:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: update
  manyToOne:
    user:
      targetEntity: User
      inversedBy: websites
      joinColumns:
        user_id:
          referencedColumnName: id
          nullable: false
  lifecycleCallbacks: {  }
Manager\UsersBundle\Entity\Email:
  type: entity
  table: emails
  fields:
    id:
      id: true
      type: integer
      unsigned: false
      nullable: false
      generator:
        strategy: AUTO
    email:
      type: string
      length: null
      fixed: false
      nullable: false
    isMain:
      type: boolean
      length: null
      fixed: false
      nullable: true
      column: is_main
    created:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: create
    updated:
      type: datetime
      nullable: false
      gedmo:
        timestampable:
          on: update
  manyToOne:
    user:
      targetEntity: User
      inversedBy: emails
      joinColumns:
        user_id:
          referencedColumnName: id
          nullable: false
  lifecycleCallbacks: {  }

@arnaugm
Copy link
Author
arnaugm commented Aug 21, 2012

Confirmed that in RC1 the problem is not solved.

@arnaugm
Copy link
Author
arnaugm commented Aug 29, 2012

Would you consider this issue as a 2.1 blocker? @fabpot @bschussek

@arnaugm
Copy link
Author
arnaugm 8000 commented Sep 18, 2012

The problem is still there in 2.1.1, any clue about where is the issue?

@arnaugm
Copy link
Author
arnaugm commented Sep 26, 2012

I've discovered that the second problem in fact has nothing to do with the first, I moved to a new issue #5609.

@arnaugm
Copy link
Author
arnaugm commented Oct 5, 2012

Hi @Tobion, you confirmed the issue right? As @bschussek didn't make any comment on that I'm starting to think that's a problem on my side.

I really need to solve that, I have a complex form and if I have to implement myself the validation it becomes a nightmare. By now I have js validations, but I don't feel comfortable only with them.

Your workaround worked but the errors don't appear, which is not much better, because the form is not saved and the user doesn't know why.

Any idea?

Thank you.

@Tobion
Copy link
Contributor
Tobion commented Oct 5, 2012

A form of mine with 3 levels of nesting works fine with the Valid constraint on each sub-collection. So errors do appear. To test this isssue I simply changed this form to use cascade_validation instead and then the validation didn't happen anymore at third level. But using the Valid constraint is the better way anyway. So try to use it.

@arnaugm
Copy link
Author
arnaugm commented Oct 5, 2012

Yes, I was already following your advice.
I noticed a new detail in the behavior. If an element of the collection was already saved and I modify it removing the mandatory fields, now I do see the error. But I still don't see the error for the elements generated with the add button.
The same piece of twig is used in both cases.
Can be that the prototype doesn't contain the error span because at the generation time it doesn't detect errors?

@vazgen
Copy link
vazgen commented Mar 11, 2013

the same problem, 2 levels work fine, 3 does not work. I have tests also by using Valid but it was not help too
(Symfony 2.2.0)
maybe I do something wrong.

I have removed 'cascade_validation' => true, and put @Assert\Valid but it does not help too

/**
 * @ORM\OneToMany(targetEntity="Yit\MainBundle\Entity\Voice", mappedBy="precinct", cascade={"persist", "remove"})
 * @Assert\Valid
 * 
*/
protected $voices;

Form class

class PrecinctVoiceType extends AbstractType
{
  /**
  * 
  * @param \Symfony\Component\Form\FormBuilderInterface $builder
  * @param array $options
  */
 public function buildForm(FormBuilderInterface $builder, array $options)
 {
   $builder->add('voices', 'collection', array('type' => new VoiceType()));
 }

 public function setDefaultOptions(OptionsResolverInterface $resolver)
 {
  $resolver->setDefaults(array(
    'data_class' => 'Yit\MainBundle\Entity\Precinct',
    //'cascade_validation' => true,
   ));
 }
}

@stollr
Copy link
stollr commented Jul 11, 2013

I had the same issue and I found out that the cascade_validation option has not only be set to true on the form types itself but also on the collection.

My case: I have a Project form type, which has a collection of Article form types, which has a collection of ProductionQuantity form types. And one field of the ProductionQuantity form type should be validated.

Here my form classes in short:

class ProjectType extends \Symfony\Component\Form\AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('articles', 'collection', array(
            'type' => new ArticleType(),
            'cascade_validation' => true,  // <- this is needed to get the grandchild validated!!
        ));
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Project',
            'cascade_validation' => true,
        ));
    }
}
class ArticleType extends \Symfony\Component\Form\AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('productionQuantities', 'collection', array(
            'type' => new ProductionQuantityType(),
        ));
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Article',
            'cascade_validation' => true,
        ));
    }
}
class ProductionQuantityType extends \Symfony\Component\Form\AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('year', 'integer'); // this should be validated !!
    }
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'ProductionQuantity'
        ));
    }
}

It was hard to figure out that the cascade_validation option has to be true for the collection of ArticleTypes, too. Otherwise only the class validators of the Article entity are executed but not the property validators. It would be nice if this could be changed anyhow.

If not, this behaviour should be documented. I tried already to find the right place in the documentation, to add this hint. But I do not know where. Maybe someone could give me a suggestion ;)

I am using version 2.3.*

@albertboada
Copy link

Wow! Setting the cascade_validation option on both the collection field definition and the setDefaults worked like a charm. Thanks for the insight!!
(Anyways, the whole thing is either nonsense or so poorly documented).


On the other hand, trying to perform the same cascading validation with @Assert\Valid on the Entity's field (instead of with the method above) will result in weird validation behaviours. If the submitted collection array has non-correlative indexes (i.e. we have dinamically removed some elements in the collection), some won't be validated, while if they are correlative, they all will. Example with the same exact data set:

Correlative indexes with the @Assert\Valid method:

events:
0:
        description:
            ERROR: This value should not be blank.
1:
        description:
            ERROR: This value should not be blank.
2:
        description:
            ERROR: This value should not be blank.

Non-correlative indexes with the @Assert\Valid method:

events:
0:
        description:
            ERROR: This value should not be blank.
3:
        description:
            No errors
4:
        description:
            No errors

With the cascade_validation method, everything is correctly validated, no matter the indexes.

Symfony 2.3.2

@maks-rafalko
Copy link
Contributor

Some related issue:

3rd level validation doesn't work when there is a Form Listener with preSubmitData callback where validated field is changed.

Without listener the field is validated correctly.

@fabpot
Copy link
Member
fabpot commented Apr 28, 2014

@ping webmozart

@jakzal
Copy link
Contributor
jakzal commented Apr 28, 2014

ping @webmozart :)

@webmozart webmozart added Form and removed Validator labels Aug 19, 2014
@peterrehm
Copy link
Contributor

Should we document the need for the duplicate cascade_validation setting?

@webmozart
Copy link
Contributor

The "cascade_validation" constraint is now deprecated. See #12237

fabpot added a commit that referenced this issue Jun 17, 2015
This PR was merged into the 2.8 branch.

Discussion
----------

[Form] Deprecated "cascade_validation"

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #11268 (requires explicit work though)
| License       | MIT
| Doc PR        | TODO

This is #12237 rebased on 2.8.

The "cascade_validation" option was designed for a 1% use case and comparatively used way too often when the `Valid` constraint should have been used instead. Also, there seem to be bugs with that option (#5204).

The option is now deprecated. When using the 2.5 Validator API, you can set the "constraints" option of the respective child to a `Valid` constraint instead. Alternatively, set the constraint in the model (as most people hopefully do).

Commits
-------

6c554c6 [Form] Deprecated "cascade_validation"
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

10 participants
0