<table role="table">
<thead>
<tr>
<th>Q</th>
<th>A</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bug report?</td>
<td>no</td>
</tr>
<tr>
<td>Feature request?</td>
<td>yes</td>
</tr>
<tr>
<td>BC Break report?</td>
<td>no</td>
</tr>
<tr>
<td>RFC?</td>
<td>no</td>
</tr>
<tr>
<td>Symfony version</td>
<td>4.1</td>
</tr>
</tbody>
</table>
<p dir="auto">What about add constraint on unique elements collection?<br>
I think it will be named as Assert\UniqueCollection.<br>
It is partly linked with <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="24860629" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/9888" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/9888/hovercard" href="https://github.com/symfony/symfony/issues/9888">#9888</a><br>
What do you think? I'd be happy to send a PR after it's discussed.</p>
<p dir="auto">I propose to add the following constraints for validating <code class="notranslate">Traversable</code> instances and arrays:</p>
<ul dir="auto">
<li><code class="notranslate">Each</code>: Validates that each entry satisfies some constraint (replaces <code class="notranslate">All</code>, which should be deprecated).</li>
<li><code class="notranslate">Some</code>: Validates that at least one entry satisfies some constraint. The lower limit (default 1) and upper limit (default <code class="notranslate">null</code>, i.e. unbounded) can be configured. Alternatively, a precise number of matches can be given.</li>
<li><code class="notranslate">None</code>: Validates that 0 entries satisfy some constraint (alias for <code class="notranslate">Some(exactly = 0, ...)</code>)</li>
<li><code class="notranslate">Unique</code>: Validates that the collection does not contain duplicates.</li>
</ul>
<p dir="auto">Example:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/**
 * @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."><pre class="notranslate"><span class="pl-c">/**</span>
<span class="pl-c"> * @Each(@GreaterThan(6))</span>
<span class="pl-c"> */</span>
<span class="pl-k">private</span> <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.

<span class="pl-c">/**</span>
<span class="pl-c"> * @Some(@GreaterThan(6))</span>
<span class="pl-c"> */</span>
private <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.

<span class="pl-c">/**</span>
<span class="pl-c"> * @Some(@GreaterThan(6), min = 2, max = 5)</span>
<span class="pl-c"> */</span>
private <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.

<span class="pl-c">/**</span>
<span class="pl-c"> * @Some(@GreaterThan(6), exactly = 3)</span>
<span class="pl-c"> */</span>
private <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.

<span class="pl-c">/**</span>
<span class="pl-c"> * @None(@GreaterThan(6))</span>
<span class="pl-c"> */</span>
private <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.

<span class="pl-c">/**</span>
<span class="pl-c"> * @Unique</span>
<span class="pl-c"> */</span>
private <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.</pre></div>
<p dir="auto">Each constraint should expect either a single constraint or an array of constraints to be given. That means you can also do:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/**
 * @Each({
 *     @NotNull,
 *     @GreaterThan(6)
 * })
 */
private $numbers."><pre class="notranslate"><span class="pl-c">/**</span>
<span class="pl-c"> * @Each({</span>
<span class="pl-c"> *     @NotNull,</span>
<span class="pl-c"> *     @GreaterThan(6)</span>
<span class="pl-c"> * })</span>
<span class="pl-c"> */</span>
<span class="pl-k">private</span> <span class="pl-s1"><span class="pl-c1">$</span>numbers</span>.</pre></div>
<p dir="auto">"min" or "max" and "exactly" must not be given at the same time:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// ConstraintDefinitionException
new Some(array(
    'constraints' =&gt; array(...),
    'min' =&gt; 2,
    'exactly' =&gt; 2,
));"><pre class="notranslate"><span class="pl-c">// ConstraintDefinitionException</span>
<span class="pl-k">new</span> <span class="pl-v">Some</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-en">array</span>(...),
    <span class="pl-s">'min'</span> =&gt; <span class="pl-c1">2</span>,
    <span class="pl-s">'exactly'</span> =&gt; <span class="pl-c1">2</span>,
));</pre></div>
<p dir="auto">Groups on inner constraints should be supported (ref <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="4807960" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/4453" data-hovercard-type="pull_request" data-hovercard-url="/symfony/symfony/pull/4453/hovercard" href="https://github.com/symfony/symfony/pull/4453">#4453</a>).</p>
<ul dir="auto">
<li>
<p dir="auto">If a collection constraint has explicit groups given, it should call <code class="notranslate">addImplicitGroupName()</code> on the nested constraints with each of these groups (except "Default").</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="new Each(array(
    'groups' =&gt; array('Default', 'Strict'),
    'constraints' =&gt; new GreaterThan(6), // implicitly group &quot;Default&quot; and &quot;Strict&quot;
));"><pre class="notranslate"><span class="pl-k">new</span> <span class="pl-v">Each</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-k">new</span> <span class="pl-v">GreaterThan</span>(<span class="pl-c1">6</span>), <span class="pl-c">// implicitly group "Default" and "Strict"</span>
));</pre></div>
</li>
<li>
<p dir="auto">If a collection constraint has no explicit group given, its groups should be the merged result of all nested groups.</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="new Each(array(
    'constraints' =&gt; array(
        new GreaterThan(array(
            'value' =&gt; 6,
            'groups' =&gt; array('Default', 'Strict'),
        )),
        new NotNull(array('groups' =&gt; 'Filled')),
    ),
    // implicitly group &quot;Default&quot;, &quot;Strict&quot; and &quot;Filled&quot;
));"><pre class="notranslate"><span class="pl-k">new</span> <span class="pl-v">Each</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-en">array</span>(
        <span class="pl-k">new</span> <span class="pl-v">GreaterThan</span>(<span class="pl-en">array</span>(
            <span class="pl-s">'value'</span> =&gt; <span class="pl-c1">6</span>,
            <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
        )),
        <span class="pl-k">new</span> <span class="pl-v">NotNull</span>(<span class="pl-en">array</span>(<span class="pl-s">'groups'</span> =&gt; <span class="pl-s">'Filled'</span>)),
    ),
    <span class="pl-c">// implicitly group "Default", "Strict" and "Filled"</span>
));</pre></div>
</li>
<li>
<p dir="auto">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.</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// ok
new Each(array(
    'groups' =&gt; array('Default', 'Strict'),
    'constraints' =&gt; new GreaterThan(array(
        'value' =&gt; 6,
        'groups' =&gt; array('Default', 'Strict'),
    )),
));

// ok
new Each(array(
    'groups' =&gt; array('Default', 'Strict'),
    'constraints' =&gt; new GreaterThan(array(
        'value' =&gt; 6,
        'groups' =&gt; 'Strict',
    )),
));

// ConstraintDefinitionException
new Each(array(
    'groups' =&gt; array('Default', 'Strict'),
    'constraints' =&gt; new GreaterThan(array(
        'value' =&gt; 6,
        'groups' =&gt; array('Strict', 'Sales'),
    )),
));"><pre class="notranslate"><span class="pl-c">// ok</span>
<span class="pl-k">new</span> <span class="pl-v">Each</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-k">new</span> <span class="pl-v">GreaterThan</span>(<span class="pl-en">array</span>(
        <span class="pl-s">'value'</span> =&gt; <span class="pl-c1">6</span>,
        <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
    )),
));

<span class="pl-c">// ok</span>
<span class="pl-k">new</span> <span class="pl-v">Each</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-k">new</span> <span class="pl-v">GreaterThan</span>(<span class="pl-en">array</span>(
        <span class="pl-s">'value'</span> =&gt; <span class="pl-c1">6</span>,
        <span class="pl-s">'groups'</span> =&gt; <span class="pl-s">'Strict'</span>,
    )),
));

<span class="pl-c">// ConstraintDefinitionException</span>
<span class="pl-k">new</span> <span class="pl-v">Each</span>(<span class="pl-en">array</span>(
    <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Default'</span>, <span class="pl-s">'Strict'</span>),
    <span class="pl-s">'constraints'</span> =&gt; <span class="pl-k">new</span> <span class="pl-v">GreaterThan</span>(<span class="pl-en">array</span>(
        <span class="pl-s">'value'</span> =&gt; <span class="pl-c1">6</span>,
        <span class="pl-s">'groups'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'Strict'</span>, <span class="pl-s">'Sales'</span>),
    )),
));</pre></div>
</li>
<li>
<p dir="auto">Calls to <code class="notranslate">addImplicitGroupName()</code> on the collection constraint should be propagated to nested constraints.</p>
</li>
</ul>