<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.8.18</td>
</tr>
</tbody>
</table>
<p dir="auto">I've tripped on an edge case where although <code class="notranslate">@UniqueEntity</code> fails the form is declared valid.</p>
<p dir="auto">I have an entity with a unique constraint on two fields. I build a form that has one of those fields pre-selected and disabled. The user is supposed to see the value of the field, but not change it. The user is supposed to fill in the second field.</p>
<p dir="auto">When this form is submitted the disabled field gets an 'error' message, but Form::getErrors skips the first field and declares it valid only because it's disabled. Source: <a href="https://github.com/symfony/symfony/blob/v2.8.18/src/Symfony/Component/Form/Form.php#L765">Symfony/Component/Form/Form.php v2.8.18 line 765</a></p>
<p dir="auto">This code says the form is valid, which results in a SQL constraint validation when attempting to save the entity.</p>
<p dir="auto">Is there anything that I can do to get over this?</p>
<p dir="auto">Why I'm doing this: I'm using EasyAdminBundle. It uses select2 for dropdowns. select2 won't implement 'read_only' in the latest version. I'm working on changing this to a hidden field plus a plain text row, but meanwhile I have this issue.</p>
<p dir="auto">Here are some snippers of code that should help with replication:</p>
<h4 dir="auto">The entity</h4>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="/**
 * MyEntity
 *
 * @ORM\Table(name=&quot;my_entity&quot;, uniqueConstraints={
 *     @ORM\UniqueConstraint(name=&quot;two_field_constraint&quot;, columns={&quot;field1&quot;, &quot;field2&quot;})
 * })
 * @ORM\Entity()
 * @UniqueEntity(fields={&quot;field1&quot;, &quot;field2&quot;})
 */
class MyEntity
// ..."><pre class="notranslate"><span class="pl-c">/**</span>
<span class="pl-c"> * MyEntity</span>
<span class="pl-c"> *</span>
<span class="pl-c"> * @ORM\Table(name="my_entity", uniqueConstraints={</span>
<span class="pl-c"> *     @ORM\UniqueConstraint(name="two_field_constraint", columns={"field1", "field2"})</span>
<span class="pl-c"> * })</span>
<span class="pl-c"> * @ORM\Entity()</span>
<span class="pl-c"> * @UniqueEntity(fields={"field1", "field2"})</span>
<span class="pl-c"> */</span>
<span class="pl-k">class</span> <span class="pl-v">MyEntity</span>
<span class="pl-c">// ...</span></pre></div>
<h4 dir="auto">The form type</h4>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class MyEntityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            -&gt;add('field1', TextType::class, ['disabled' =&gt; true])
            -&gt;add('field2', TextType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver-&gt;setDefaults(array(
            'data_class' =&gt; 'AppBundle\Entity\MyEntity'
        ));
    }
//...
}"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-v">MyEntityType</span> <span class="pl-k">extends</span> <span class="pl-v">AbstractType</span>
{
    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">buildForm</span>(<span class="pl-smi"><span class="pl-smi">FormBuilderInterface</span></span> <span class="pl-s1"><span class="pl-c1">$</span>builder</span>, <span class="pl-smi">array</span> <span class="pl-s1"><span class="pl-c1">$</span>options</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span>builder</span>
            -&gt;<span class="pl-en">add</span>(<span class="pl-s">'field1'</span>, <span class="pl-v">TextType</span>::class, [<span class="pl-s">'disabled'</span> =&gt; <span class="pl-c1">true</span>])
            -&gt;<span class="pl-en">add</span>(<span class="pl-s">'field2'</span>, <span class="pl-v">TextType</span>::class)
        ;
    }

    <span class="pl-k">public</span> <span class="pl-k">function</span> <span class="pl-en">configureOptions</span>(<span class="pl-smi"><span class="pl-smi">OptionsResolver</span></span> <span class="pl-s1"><span class="pl-c1">$</span>resolver</span>)
    {
        <span class="pl-s1"><span class="pl-c1">$</span>resolver</span>-&gt;<span class="pl-en">setDefaults</span>(<span class="pl-en">array</span>(
            <span class="pl-s">'data_class'</span> =&gt; <span class="pl-s">'AppBundle\Entity\MyEntity'</span>
        ));
    }
<span class="pl-c">//...</span>
}</pre></div>
<h4 dir="auto">the initial data</h4>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="INSERT INTO my_table ('value1', 'value2');"><pre class="notranslate"><span class="pl-k">INSERT INTO</span> my_table (<span class="pl-s"><span class="pl-pds">'</span>value1<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>value2<span class="pl-pds">'</span></span>);</pre></div>
<h4 dir="auto">the test code trying to insert duplicate data</h4>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="        $builder = $this-&gt;container-&gt;get('form.factory')-&gt;createBuilder(MyEntityType::class, null, ['csrf_protection' =&gt; false]);

        $form = $builder-&gt;getForm();

        $data = [
            'field1' =&gt; 'value1',
            'field2' =&gt; 'value2',
        ];

        $form-&gt;submit($data);
        dump($form-&gt;isSubmitted(), $form-&gt;isValid());"><pre class="notranslate">        <span class="pl-s1"><span class="pl-c1">$</span>builder</span> = <span class="pl-s1"><span class="pl-c1">$</span><span class="pl-smi">this</span></span>-&gt;<span class="pl-c1">container</span>-&gt;<span class="pl-en">get</span>(<span class="pl-s">'form.factory'</span>)-&gt;<span class="pl-en">createBuilder</span>(<span class="pl-v">MyEntityType</span>::class, <span class="pl-c1">null</span>, [<span class="pl-s">'csrf_protection'</span> =&gt; <span class="pl-c1">false</span>]);

        <span class="pl-s1"><span class="pl-c1">$</span>form</span> = <span class="pl-s1"><span class="pl-c1">$</span>builder</span>-&gt;<span class="pl-en">getForm</span>();

        <span class="pl-s1"><span class="pl-c1">$</span>data</span> = [
            <span class="pl-s">'field1'</span> =&gt; <span class="pl-s">'value1'</span>,
            <span class="pl-s">'field2'</span> =&gt; <span class="pl-s">'value2'</span>,
        ];

        <span class="pl-s1"><span class="pl-c1">$</span>form</span>-&gt;<span class="pl-en">submit</span>(<span class="pl-s1"><span class="pl-c1">$</span>data</span>);
        dump(<span class="pl-s1"><span class="pl-c1">$</span>form</span>-&gt;<span class="pl-en">isSubmitted</span>(), <span class="pl-s1"><span class="pl-c1">$</span>form</span>-&gt;<span class="pl-en">isValid</span>());</pre></div>
<p dir="auto"><a href="https://github.com/symfony/form/blob/master/Form.php#L724">Submitted and disabled form is always valid.</a> So in the situation:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {
        $data = $from-&gt;getData();
        // handle data ...
    }"><pre class="notranslate"><code class="notranslate">    if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {
        $data = $from-&gt;getData();
        // handle data ...
    }
</code></pre></div>
<p dir="auto">Is it expected that code depending on <code class="notranslate">$form-&gt;getData()</code> is able to handle <a href="https://github.com/symfony/form/blob/master/Form.php#L506">complete lack of data</a> even if the from is valid? Or should I always check that form is not disabled? So instead recommended <code class="notranslate">if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid()) {</code> default to <code class="notranslate">if ($form-&gt;isSubmitted() &amp;&amp; $form-&gt;isValid() &amp;&amp; !$from-&gt;isDisabled()) {</code>?</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/edit/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/edit">@edit</a> I'm asking the question because I saw deprecation of calling <code class="notranslate">$form-&gt;isValid()</code> when the form is not submitted, but the issue mentioned above bothers me much more. I'm curious if I'm missing something or the part  <code class="notranslate">if ($this-&gt;isDisabled()) { return true; }</code> should be removed from there (or at least better documented).</p>