8000 Compose validation · Issue #35226 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Compose validation #35226

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
JumpIfBelow opened this issue Jan 6, 2020 · 9 comments
Closed

Compose validation #35226

JumpIfBelow opened this issue Jan 6, 2020 · 9 comments

Comments

@JumpIfBelow
Copy link
JumpIfBelow commented Jan 6, 2020

Description
Creates a new composite constraint to validate a composition of constraints. The minumum and maximum validated should be set optionnaly.

Example
For example, there are two use case that could be easily answered with such a composition.

  1. When properties are exclusive to each other
/**
 * @Assert\Compose(
 *   constraints={
 *     @Assert\Expression("value.bar !== null"),
 *     @Assert\Expression("value.baz !== null"),
 *   },
 *   min=1,
 *   max=1,
 *   minMessage="One of $bar or $baz should be set.",
 *   maxMessage="Only one of $bar or $baz should be set.",
 * )
 */
class Foo {
  public $bar;
  public $baz;
}
  1. Password security rules
    Often there are security rules to enforce for a new password. Those are limited set, and not all of the rules are mandatory for a valid password. For example, we could have the rules with the following statement:
  • at least 8 characters long
  • at least 3 of those:
    • contains 1 lower case character
    • contains 1 upper case character
    • contains 1 digit
    • contains 1 special character

It is an issue to enforce that a password is complex enough in the current state. Allowing to compose constraints enables simpler code:

class User {
  /**
   * @Assert\Length(min=8)
   * @Assert\Compose(
   *   constraints={
   *     @Assert\Regex("/[a-z]/"),
   *     @Assert\Regex("/[A-Z]/"),
   *     @Assert\Regex("/\d/"),
   *     @Assert\Regex("/[,;:.!?]/"),
   *   },
   *   min=3,
   *   minMessage="The password must contains at least one of those 3 character: ...",
   * )
   */
  public string $password;
}

Basic code
To me, a Compose annotation could look like this:

/**
 * @Annotation
 * @Target({"CLASS", "PROPERTY", "METHOD", "ANNOTATION"})
 */
class Compose extends Composite
{
    /**
     * @var string $minMessage
     */
    public string $minMessage = 'compose.min';

    /**
     * @var string $maxMessage
     */
    public string $maxMessage = 'compose.max';

    /**
     * @var Constraint[] $constraints
     */
    public array $constraints = [];

    /**
     * @var int $min
     */
    public int $min = 0;

    /**
     * @var int|null $max
     */
    public ?int $max = null;

    public function getDefaultOption()
    {
        return $this->getCompositeOption();
    }

    public function getTargets()
    {
        return [
            static::CLASS_CONSTRAINT,
            static::PROPERTY_CONSTRAINT,
        ];
    }

    protected function getCompositeOption()
    {
        return 'constraints';
    }
}
@xabbuh
Copy link
Member
xabbuh commented Jan 6, 2020

Would #31196 solve this (i.e. is this the same feature request as #9888)?

@JumpIfBelow
Copy link
Author

Would #31196 solve this (i.e. is this the same feature request as #9888)?

It looks a bit like the same, but the feature presented there is more generic and allows more customization. Not that I dislike the others which are clearer to use.

@stof
Copy link
Member
stof commented Jan 6, 2020

The case of a XOR can indeed be solved with this with meaningful error messages, thanks to having only 3 possible cases (below min, valid, above max), as this corresponds to min = max = 1.
but I'm not convinced that this proposal solves the second use case. You won't be able to provide a good error message, customized depending on the type of failure.

@JumpIfBelow
Copy link
Author

The case of a XOR can indeed be solved with this with meaningful error messages, thanks to having only 3 possible cases (below min, valid, above max), as this corresponds to min = max = 1.
but I'm not convinced that this proposal solves the second use case. You won't be able to provide a good error message, customized depending on the type of failure.

It actually do solve with the dedicated min/max messages. The type of failure will depend if there are less than min or more than max constraints validated. You can see the minMessage set for this purpose.

@stof
Copy link
Member
stof commented Jan 6, 2020

But if you have min=2, max=4 with a list of 6 constraints, you might need to provide different messages when the user is at 5 or 6 (telling them not to use something that they already don't use would be bad UX)

@JumpIfBelow
Copy link
Author

What would be the use case? The Some proposed in #9888 seems to have the same flaw, but it does not looks like an issue to me actually. The purpose is to validate the right constraints, not to decline depending on which have failed. The validator couldn't carry this information anyway.

@carsonbot
Copy link

Thank you for this suggestion.
There has not been a lot of activity here for a while. Would you still like to see this feature?

@carsonbot
Copy link

Hello? This issue is about to be closed if nobody replies.

@carsonbot
Copy link

Hey,

I didn't hear anything so I'm going to close it. Feel free to comment if this is still relevant, I can always reopen!

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
0