8000 Variable "this" has value of null in an "Expression" validation constraint inside an "All" validation constraint · Issue #20477 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Variable "this" has value of null in an "Expression" validation constraint inside an "All" validation constraint #20477

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
zsolt-racz opened this issue Nov 10, 2016 · 3 comments

Comments

@zsolt-racz
Copy link
zsolt-racz commented Nov 10, 2016

I have possibly found a bug in the Validator component when combining these two constraints: Expression and All. I'm going to show it on an example:

Considering these two classes:

namespace AppBundle;
class ParentClass {

	private $name;
	private $children;

	public function __construct(){
		$this->children = new ArrayCollection();
	}

	public function getName() {
		return $this->name;
	}

	public function setName( $name ) {
		$this->name = $name;
	}

	public function getChildren() {
		return $this->children;
	}

	public function addChild( $child ) {
		$this->children->add($child);
	}
}

and

namespace AppBundle;
class ChildClass {

	private $name;

	public function getName() {
		return $this->name;
	}

	public function setName( $name ) {
		$this->name = $name;
	}

}

With the following validation rules stored in validation.yml:

AppBundle\ParentClass:
    properties:
        children:
            - NotBlank: ~
            - Valid: ~
            - All:
                - Expression:
                    expression: "this.getName() != value.getName()"

AppBundle\ChildClass:
    properties:
        name:
            - NotBlank: ~

I would like to achieve to forbid assigning the parent's name to children. So the getName() method of the parent should return a distinct value from getName() methods of all children.

However after trying to validate an instance of ParentClass constructed like this:

    $validator = $this->get('validator');

    $parent = new ParentClass();
    $parent->setName("foo");

    $child = new ChildClass();
    $child->setName("bar");

    $parent->addChild($child);
    $validator->validate($parent);

A RuntimeException is thrown with the following message:

Unable to get a property on a non-object. 

As I figured out, the variable value is correctly assigned to child objects, however the variable this in the expression has a value of null. I would expect a reference to the parent object in this variable, regarding to the documentation:

this: The object being validated (e.g. an instance of BlogPost);


Symfony 3.1.6, PHP 7.0.8, Linux Mint 18

@stof
Copy link
Member
stof commented Nov 10, 2016

this is populated when you apply an Expression constraint on a property of an object, to be able to access the whole object (as value will be the property value).
For class-level constraint, there are only 2 possibilities: assign null, or assign the object, i.e. the same than value (which could be worse as it could hide things).

In your case, getting the ParentClass instance would be wrong. When the All constraint applies the constraints on all items of the array, we are not validating the ParentClass instance. We are validating the array item.

@zsolt-racz
Copy link
Author
zsolt-racz commented Nov 15, 2016

@stof Well, it makes sense and I agree with your reasoning. However I think the variable this should never be null - this is also what the documentation implicitly states.

Also I found out, that the expression variables in class-level constraints are assigned inconsistently depending if they are defined within the All constraint, or outside the All constraint. For example, if I define a class-level constraint like this:

AppBundle\ChildClass:
    constraints:
        - Expression:
            expression: "this == value"

The validation passes, since the expression is evaluated as true. In this case the value of this and the value of value is the same: the ChildClass object.

Then it would be expectable for the next constraint to pass too:

AppBundle\ParentClass:
    properties:
        children:
            - All:
                - Expression:
                    expression: "this == value"

However, it's definitely not, since in this case this gets assigned to null.

I think in both cases, this should hold the reference to the direct parent object, and value should have the same value or be assigned to null.

@maximecolin
Copy link
Contributor

I encountered the same bug expecting to access to the object being validated through this but got null.

I think the context should not be lost when All is used. The object being validated is still the parent object.

@xabbuh xabbuh removed the Unconfirmed label Mar 5, 2017
fabpot added a commit that referenced this issue Jan 3, 2018
… constraint (ostrolucky)

This PR was merged into the 2.7 branch.

Discussion
----------

[Validator] Fix access to root object when using composite constraint

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #12315, #20477, #21706
| License       | MIT
| Doc PR        |

Commits
-------

b18cdcf [Validator] Fix access to root object when using composite constraint
@fabpot fabpot closed this as completed Jan 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants
0