Skip to content

[Validator] Let option values reference values in the object graph #7726

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
webmozart opened this issue Apr 19, 2013 · 10 comments
Closed

[Validator] Let option values reference values in the object graph #7726

webmozart opened this issue Apr 19, 2013 · 10 comments

Comments

@webmozart
Copy link
Contributor

In #790 and #7444 the need to reference dynamic values in constraint options was discovered. A simple example:

use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Constraints\Reference;

/**
 * @Range(min = @Reference("min"), max = @Reference("max"))
 */
private $value;

private $min;

private $max

Here, the values of the "min" and "max" option are determined at runtime. References can contain any valid property path.

XML example:

<property name="value">
    <constraint name="Range">
        <option name="min" reference="min" />
        <option name="max" reference="max" />
    </constraint>
</property>

YAML example:

properties:
    value:
        - Range:
            min: @min

Attention: This example would be consistent with the DIC YAML syntax for service references, but it would be incompatible for options where values starting with "@" are valid expected values. Is this a problem?

PHP example:

$metadata->addPropertyConstraint('value', new Range(array(
    'min' => new Reference('min'),
    'max' => new Reference('max'),
)));

Some implementation hints:

Class Reference should be an annotation but not inherit from Constraint (it is no constraint). It probably needs only a constructor. Additionally, we need a ReferenceResolver (and ReferenceResolverInterface, of course) that receives a PropertyAccessorInterface in its constructor. It needs only a method resolveReference(Reference $reference, ExecutionContextInterface $context) that returns the value of a reference based on the current state of the execution context.

All validators that support references then need the ReferenceResolver to resolve any Reference instances when they find them.

@stof
Copy link
Member

stof commented Apr 19, 2013

How would you inject the ReferenceResolver ? Would the ConstraintValdiatorFactory know it and inject it by doing an instanceof check ? Or would you require defining all these valdiators as service ?
The first option seems better for the standalone usage of the component

@webmozart
Copy link
Contributor Author

That's a possibility. Alternatively, we could add resolveReference to ExecutionContextInterface. What do you think?

@stof
Copy link
Member

stof commented Apr 19, 2013

yeah, it may be easier (no need to inject the resolver in constraint validators)

@marcospassos
Copy link

@danielholmes what is not clear for you? Can we discuss about that here? Do you already read the issue #7444? For me, it's clear, but I can try to answer your questions.

@danielholmes
Copy link
Contributor

@marcospassos I hadn't seen #7444 before, yea that's all clear. It's more work than I thought it might be. It's getting late where I am and my work day is full tomorrow so I probably couldn't do it before feature freeze. If you or someone else completed this generic Reference PR then it won't take long to put it in to the comparison validators

@webmozart
Copy link
Contributor Author

This will be postponed to 2.4. There are too many open questions for finishing this by tomorrow.

@marcospassos
Copy link

@bschussek what are the open questions (except about the YML syntax)? I would like to work on that to keep live. Adding the resolveReference to ExecutionContextInterface it seems become easy.

@stof
Copy link
Member

stof commented Oct 28, 2013

@bschussek can it be closed now that we have expressions ?

@webmozart
Copy link
Contributor Author

@stof Not unless we make it possible to execute other constraints from within the Expression constraint.

@webmozart
Copy link
Contributor Author

In fact, this can easily be done using callbacks:

/**
 * @Assert\Callback
 */
public function validate(ExecutionContextInterface $context)
{
    $validator = $context->getValidator()->inContext($context);

    $validator->atPath('value')->validate($this->value, new Range(array(
        'min' => $this->min,
        'max' => $this->max,
    )));
}

I think this is simpler and superior to some magic new syntax.

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

4 participants