<table role="table">
<thead>
<tr>
<th>Q</th>
<th>A</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bug report?</td>
<td>yes</td>
</tr>
<tr>
<td>Feature request?</td>
<td>no</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>2.7.*</td>
</tr>
</tbody>
</table>
<p dir="auto">Hello everyone. I have the problem with yaml validation of collection with fields of different groups. I debugged a lot, and I came to the conclusion that there is a bug in validation of <code class="notranslate">\Symfony\Component\Validator\Constraints\Collection</code> with different groups.</p>
<hr>
<h3 dir="auto">Example description</h3>
<p dir="auto">For example, we had two equal entities: <code class="notranslate">User</code> and <code class="notranslate">Category</code>. Both have <code class="notranslate">id</code>, <code class="notranslate">modifier</code> and <code class="notranslate">info</code> (the array of some additional information with keys <code class="notranslate">id</code>, <code class="notranslate">title</code> and <code class="notranslate">text</code>).</p>
<p dir="auto">– Root field <code class="notranslate">id</code> is required (I mean it should have the <code class="notranslate">NotBlank</code> constraint).<br>
– Second field <code class="notranslate">modifier</code> is required only on update, so we add custom validation group called <code class="notranslate">modify</code>. We assume, on create we won't pass this group, but we will pass it on update.<br>
– Third field <code class="notranslate">info</code> it is a large collection of different <em>non-required</em> parameters: in our case they are <code class="notranslate">id</code> (some other identification), <code class="notranslate">title</code> (length should be between 3 and 25 chars, only with group <code class="notranslate">info</code>) and <code class="notranslate">text</code> (length should be between 3 and 25 chars). I added additional validation group <code class="notranslate">info</code> for <code class="notranslate">title</code> because I wanted to check it not always, only when group is passed.</p>
<hr>
<h3 dir="auto">Problem reproduce</h3>
<p dir="auto">I prepared a little repository for tests to figure out the problem. The original successful code is located in <code class="notranslate">validation</code> branch of <code class="notranslate">Aliance/SymfonyTest</code> repository: <a href="https://github.com/Aliance/SymfonyTest/tree/validation">https://github.com/Aliance/SymfonyTest/tree/validation</a><br>
The failed code is located into <code class="notranslate">validation-collection-with-different-groups</code> branch, see pr: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="242087725" data-permission-text="Title is private" data-url="https://github.com/Aliance/SymfonyTest/issues/1" data-hovercard-type="pull_request" data-hovercard-url="/Aliance/SymfonyTest/pull/1/hovercard" href="https://github.com/Aliance/SymfonyTest/pull/1">Aliance/SymfonyTest#1</a><br>
If you execute phpunit tests you will find out that they fails after adding second group in other field on collection.</p>
<p dir="auto"><em>Note that tests fails only with yaml validation!</em></p>
<hr>
<h3 dir="auto">What I have already debugged</h3>
<p dir="auto">– First of all, code execution runs to <code class="notranslate">\Symfony\Component\Validator\Validator\RecursiveContextualValidator::validate</code> with my object as a <code class="notranslate">$value</code> and all three passed groups <code class="notranslate">['Default','modify','info']</code> as a <code class="notranslate">$groups</code><br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/7838144/28077936-d87a7ca2-666b-11e7-92f2-59c78297f460.png"><img width="587" alt="2017-07-11 19 04 42" src="https://user-images.githubusercontent.com/7838144/28077936-d87a7ca2-666b-11e7-92f2-59c78297f460.png" style="max-width: 100%;"></a><br>
– Later it iterates on each groups on every field. Reaching the <code class="notranslate">info</code> type it will raise <code class="notranslate">\Symfony\Component\Validator\Constraints\CollectionValidator::validate</code>. It will repeat validation on every field without any groups passed:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/7838144/28078873-eaa2cc10-666e-11e7-9e4f-305b82686047.png"><img width="789" alt="2017-07-11 19 26 39" src="https://user-images.githubusercontent.com/7838144/28078873-eaa2cc10-666e-11e7-9e4f-305b82686047.png" style="max-width: 100%;"></a><br>
Looks strange, seems to me that <code class="notranslate">CollectionValidator</code> should pass <code class="notranslate">$fieldConstraint-&gt;groups</code> to <code class="notranslate">validate</code> method...<br>
– But later somehow valid groups are came to validator: <code class="notranslate">\Symfony\Component\Validator\Validator\RecursiveContextualValidator::validateEachObjectIn</code>:<br>
<a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/7838144/28078406-6b2afcba-666d-11e7-8efa-37f83c63628b.png"><img width="559" alt="2017-07-11 19 16 03" src="https://user-images.githubusercontent.com/7838144/28078406-6b2afcba-666d-11e7-8efa-37f83c63628b.png" style="max-width: 100%;"></a><br>
– But in deeps of this method, checked constraint-group has already cached as validated, because cache key only consist of <code class="notranslate">spl_object_hash($constraint)</code>, without validation group handling: see <a href="https://github.com/symfony/symfony/blob/v2.8.22/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php#L866-L872">https://github.com/symfony/symfony/blob/v2.8.22/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php#L866-L872</a></p>
<hr>
<p dir="auto">Can anyone approve this bug or tell me what I am doing wrong?</p>
<p dir="auto">Hi,</p>
<p dir="auto">I don't know if it's a bug but it seem that all embedded constraints of a collection constraint are not applied when using validation groups.</p>
<p dir="auto">I think that <strong>only the first validation group</strong> passed to the validator is used and the other are omitted.</p>
<p dir="auto">With the following example if <code class="notranslate">$config</code> is equal to <code class="notranslate">['foo' =&gt; 'a']</code> then with validation groups:</p>
<ul dir="auto">
<li><code class="notranslate">['foo', 'bar', 'baz']</code> we have <strong>0</strong> violation (<code class="notranslate">NotBlank</code>)</li>
<li><code class="notranslate">['baz', 'bar', 'foo']</code> we have <strong>1</strong> violation (<code class="notranslate">Lenght(min="4")</code>)</li>
<li><code class="notranslate">['bar', 'baz', 'foo']</code> we have <strong>1</strong> violation (<code class="notranslate">Lenght(min="2")</code>)</li>
</ul>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    /**
     * @Collection(
     *     fields={
     *          &quot;foo&quot; = {
     *              @NotBlank(groups={&quot;foo&quot;}),
     *              @Length(min=&quot;2&quot;, groups={&quot;bar&quot;}),
     *              @Length(min=&quot;4&quot;, groups={&quot;baz&quot;})
     *          }
     *     }
     * )
     */
    public $config;"><pre class="notranslate">    <span class="pl-c">/**</span>
<span class="pl-c">     * @Collection(</span>
<span class="pl-c">     *     fields={</span>
<span class="pl-c">     *          "foo" = {</span>
<span class="pl-c">     *              @NotBlank(groups={"foo"}),</span>
<span class="pl-c">     *              @Length(min="2", groups={"bar"}),</span>
<span class="pl-c">     *              @Length(min="4", groups={"baz"})</span>
<span class="pl-c">     *          }</span>
<span class="pl-c">     *     }</span>
<span class="pl-c">     * )</span>
<span class="pl-c">     */</span>
    <span class="pl-k">public</span> <span class="pl-s1"><span class="pl-c1">$</span>config</span>;</pre></div>
<p dir="auto">Here the complete gist with the tests : <a href="https://gist.github.com/blazarecki/5dcb754be22dae4f0e53">https://gist.github.com/blazarecki/5dcb754be22dae4f0e53</a></p>
<p dir="auto">Any idea ?<br>
Thanks.</p>