Skip to content

[Validator] Improve support for collection validation #9888

Closed
@webmozart

Description

@webmozart

I propose to add the following constraints for validating Traversable instances and arrays:

  • Each: Validates that each entry satisfies some constraint (replaces All, which should be deprecated).
  • Some: Validates that at least one entry satisfies some constraint. The lower limit (default 1) and upper limit (default null, i.e. unbounded) can be configured. Alternatively, a precise number of matches can be given.
  • None: Validates that 0 entries satisfy some constraint (alias for Some(exactly = 0, ...))
  • Unique: Validates that the collection does not contain duplicates.

Example:

/**
 * @Each(@GreaterThan(6))
 */
private $numbers.

/**
 * @Some(@GreaterThan(6))
 */
private $numbers.

/**
 * @Some(@GreaterThan(6), min = 2, max = 5)
 */
private $numbers.

/**
 * @Some(@GreaterThan(6), exactly = 3)
 */
private $numbers.

/**
 * @None(@GreaterThan(6))
 */
private $numbers.

/**
 * @Unique
 */
private $numbers.

Each constraint should expect either a single constraint or an array of constraints to be given. That means you can also do:

/**
 * @Each({
 *     @NotNull,
 *     @GreaterThan(6)
 * })
 */
private $numbers.

"min" or "max" and "exactly" must not be given at the same time:

// ConstraintDefinitionException
new Some(array(
    'constraints' => array(...),
    'min' => 2,
    'exactly' => 2,
));

Groups on inner constraints should be supported (ref #4453).

  • If a collection constraint has explicit groups given, it should call addImplicitGroupName() on the nested constraints with each of these groups (except "Default").

    new Each(array(
        'groups' => array('Default', 'Strict'),
        'constraints' => new GreaterThan(6), // implicitly group "Default" and "Strict"
    ));
  • If a collection constraint has no explicit group given, its groups should be the merged result of all nested groups.

    new Each(array(
        'constraints' => array(
            new GreaterThan(array(
                'value' => 6,
                'groups' => array('Default', 'Strict'),
            )),
            new NotNull(array('groups' => 'Filled')),
        ),
        // implicitly group "Default", "Strict" and "Filled"
    ));
  • If both the collection constraint and a nested constraint have explicit groups given, the groups of the nested constraint need to be a subset of the groups of the outer constraint.

    // ok
    new Each(array(
        'groups' => array('Default', 'Strict'),
        'constraints' => new GreaterThan(array(
            'value' => 6,
            'groups' => array('Default', 'Strict'),
        )),
    ));
    
    // ok
    new Each(array(
        'groups' => array('Default', 'Strict'),
        'constraints' => new GreaterThan(array(
            'value' => 6,
            'groups' => 'Strict',
        )),
    ));
    
    // ConstraintDefinitionException
    new Each(array(
        'groups' => array('Default', 'Strict'),
        'constraints' => new GreaterThan(array(
            'value' => 6,
            'groups' => array('Strict', 'Sales'),
        )),
    ));
  • Calls to addImplicitGroupName() on the collection constraint should be propagated to nested constraints.

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