<p dir="auto">Originally I wanted to display radio buttons without the possibility of changing them.<br>
I tried using the <code class="notranslate">read_only</code> attribute on my field type first:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$builder-&gt;add('onCall', 'choice', array(
    'choices' =&gt; array(0 =&gt; 'no', 1 =&gt; 'yes'),
    'expanded' =&gt; true,
    'read_only' =&gt; true
));"><pre class="notranslate"><span class="pl-s1"><span class="pl-c1">$</span>builder</span>-&gt;<span class="pl-en">add</span>(<span class="pl-s">'onCall'</span>, <span class="pl-s">'choice'</span>, <span class="pl-en">array</span>(
    <span class="pl-s">'choices'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-c1">0</span> =&gt; <span class="pl-s">'no'</span>, <span class="pl-c1">1</span> =&gt; <span class="pl-s">'yes'</span>),
    <span class="pl-s">'expanded'</span> =&gt; <span class="pl-c1">true</span>,
    <span class="pl-s">'read_only'</span> =&gt; <span class="pl-c1">true</span>
));</pre></div>
<p dir="auto">As expected the <code class="notranslate">readonly</code> attribute gets added to the <code class="notranslate">input</code>:</p>
<div class="highlight highlight-text-html-twig notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;input id=&quot;timekeeping_entry_day_onCall_0&quot; type=&quot;radio&quot; value=&quot;0&quot; required=&quot;required&quot; readonly=&quot;readonly&quot; name=&quot;timekeeping_entry_day[onCall]&quot;&gt;"><pre class="notranslate">&lt;<span class="pl-ent">input</span> <span class="pl-e">id</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall_0<span class="pl-pds">"</span></span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>radio<span class="pl-pds">"</span></span> <span class="pl-e">value</span>=<span class="pl-s"><span class="pl-pds">"</span>0<span class="pl-pds">"</span></span> <span class="pl-e">required</span>=<span class="pl-s"><span class="pl-pds">"</span>required<span class="pl-pds">"</span></span> <span class="pl-e">readonly</span>=<span class="pl-s"><span class="pl-pds">"</span>readonly<span class="pl-pds">"</span></span> <span class="pl-e">name</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day[onCall]<span class="pl-pds">"</span></span>&gt;</pre></div>
<p dir="auto">But in the end this does not have any effect since - as we all know by now - <code class="notranslate">readonly</code> is not supported for radio buttons:<br>
<a href="http://www.w3.org/TR/WD-forms-970402#readonly" rel="nofollow">http://www.w3.org/TR/WD-forms-970402#readonly</a><br>
<code class="notranslate">READONLY applies to INPUT elements of type TEXT or PASSWORD and to the TEXTAREA element.</code></p>
<p dir="auto">So allowing the <code class="notranslate">read_only</code> option on an <code class="notranslate">expanded</code> <code class="notranslate">choice</code> does not seem to make sense anyway, correct?</p>
<p dir="auto">The desired effect on the element should be to disable it. But setting <code class="notranslate">disabled</code> on the field type will ignore validation after form submit if the radio buttons have been enabled again by a javascript on client side.</p>
<p dir="auto">So it looks like the only way to do it is to set the HTML attribute <code class="notranslate">disabled</code> on the field type.<br>
This way it can be enabled again by the client and the submitted value would not be ignored.</p>
<p dir="auto">My attempt for this:</p>
<div class="highlight highlight-text-html-php notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="$builder-&gt;add('onCall', 'choice', array(
    'choices' =&gt; array(0 =&gt; 'no', 1 =&gt; 'yes'),
    'expanded' =&gt; true,
    'attr' =&gt; array('disabled' =&gt; 'disabled')
));"><pre class="notranslate"><span class="pl-s1"><span class="pl-c1">$</span>builder</span>-&gt;<span class="pl-en">add</span>(<span class="pl-s">'onCall'</span>, <span class="pl-s">'choice'</span>, <span class="pl-en">array</span>(
    <span class="pl-s">'choices'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-c1">0</span> =&gt; <span class="pl-s">'no'</span>, <span class="pl-c1">1</span> =&gt; <span class="pl-s">'yes'</span>),
    <span class="pl-s">'expanded'</span> =&gt; <span class="pl-c1">true</span>,
    <span class="pl-s">'attr'</span> =&gt; <span class="pl-en">array</span>(<span class="pl-s">'disabled'</span> =&gt; <span class="pl-s">'disabled'</span>)
));</pre></div>
<p dir="auto">Unfortunately the HTML result does not apply the <code class="notranslate">disabled</code> attribute to the <code class="notranslate">input</code> but to the <code class="notranslate">div</code> around it:</p>
<div class="highlight highlight-text-html-twig notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&lt;div id=&quot;timekeeping_entry_day_onCall&quot; disabled=&quot;disabled&quot;&gt;
&lt;input id=&quot;timekeeping_entry_day_onCall_0&quot; type=&quot;radio&quot; value=&quot;0&quot; required=&quot;required&quot; name=&quot;timekeeping_entry_day[onCall]&quot;&gt;
&lt;label class=&quot;required&quot; for=&quot;timekeeping_entry_day_onCall_0&quot;&gt;no&lt;/label&gt;
&lt;input id=&quot;timekeeping_entry_day_onCall_1&quot; type=&quot;radio&quot; value=&quot;1&quot; required=&quot;required&quot; name=&quot;timekeeping_entry_day[onCall]&quot;&gt;
&lt;label class=&quot;required&quot; for=&quot;timekeeping_entry_day_onCall_1&quot;&gt;yes&lt;/label&gt;
&lt;/div&gt;"><pre class="notranslate">&lt;<span class="pl-ent">div</span> <span class="pl-e">id</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall<span class="pl-pds">"</span></span> <span class="pl-e">disabled</span>=<span class="pl-s"><span class="pl-pds">"</span>disabled<span class="pl-pds">"</span></span>&gt;
&lt;<span class="pl-ent">input</span> <span class="pl-e">id</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall_0<span class="pl-pds">"</span></span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>radio<span class="pl-pds">"</span></span> <span class="pl-e">value</span>=<span class="pl-s"><span class="pl-pds">"</span>0<span class="pl-pds">"</span></span> <span class="pl-e">required</span>=<span class="pl-s"><span class="pl-pds">"</span>required<span class="pl-pds">"</span></span> <span class="pl-e">name</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day[onCall]<span class="pl-pds">"</span></span>&gt;
&lt;<span class="pl-ent">label</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>required<span class="pl-pds">"</span></span> <span class="pl-e">for</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall_0<span class="pl-pds">"</span></span>&gt;no&lt;/<span class="pl-ent">label</span>&gt;
&lt;<span class="pl-ent">input</span> <span class="pl-e">id</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall_1<span class="pl-pds">"</span></span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>radio<span class="pl-pds">"</span></span> <span class="pl-e">value</span>=<span class="pl-s"><span class="pl-pds">"</span>1<span class="pl-pds">"</span></span> <span class="pl-e">required</span>=<span class="pl-s"><span class="pl-pds">"</span>required<span class="pl-pds">"</span></span> <span class="pl-e">name</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day[onCall]<span class="pl-pds">"</span></span>&gt;
&lt;<span class="pl-ent">label</span> <span class="pl-e">class</span>=<span class="pl-s"><span class="pl-pds">"</span>required<span class="pl-pds">"</span></span> <span class="pl-e">for</span>=<span class="pl-s"><span class="pl-pds">"</span>timekeeping_entry_day_onCall_1<span class="pl-pds">"</span></span>&gt;yes&lt;/<span class="pl-ent">label</span>&gt;
&lt;/<span class="pl-ent">div</span>&gt;</pre></div>
<p dir="auto">I'm not using the Bootstrap theme.</p>
<p dir="auto">Setting the <code class="notranslate">attr</code> seems to be the issue:</p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="15498045" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/8269" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/8269/hovercard" href="https://github.com/symfony/symfony/issues/8269">#8269</a> by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sargath/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sargath">@sargath</a></li>
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="14369423" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/8051" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/8051/hovercard" href="https://github.com/symfony/symfony/issues/8051">#8051</a> by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/AdamQuadmon/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/AdamQuadmon">@AdamQuadmon</a></li>
</ul>
<p dir="auto">The <code class="notranslate">div</code> uses the <code class="notranslate">widget_container_attributes</code> block:<br>
<a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig#L46">https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig#L46</a></p>
<p dir="auto">While the <code class="notranslate">input</code> uses a <code class="notranslate">widget_attributes</code> block:<br>
<a href="https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig#L93">https://github.com/symfony/symfony/blob/2.7/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig#L93</a></p>
<p dir="auto">Are the <code class="notranslate">attr</code> passed to the wrong block?</p>
<p dir="auto">Original issue I started:</p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="63732817" data-permission-text="Title is private" data-url="https://github.com/sonata-project/SonataAdminBundle/issues/2842" data-hovercard-type="issue" data-hovercard-url="/sonata-project/SonataAdminBundle/issues/2842/hovercard" href="https://github.com/sonata-project/SonataAdminBundle/issues/2842">sonata-project/SonataAdminBundle#2842</a></li>
</ul>
<p dir="auto">Possibly related:</p>
<ul dir="auto">
<li><a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="51684910" data-permission-text="Title is private" data-url="https://github.com/symfony/symfony/issues/12946" data-hovercard-type="issue" data-hovercard-url="/symfony/symfony/issues/12946/hovercard" href="https://github.com/symfony/symfony/issues/12946">#12946</a></li>
</ul>
<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>no</td>
</tr>
<tr>
<td>BC Break report?</td>
<td>no</td>
</tr>
<tr>
<td>RFC?</td>
<td>yes</td>
</tr>
<tr>
<td>Symfony version</td>
<td>2.8.0 - 3.2.2</td>
</tr>
</tbody>
</table>
<p dir="auto">In my application, I have several authentication mechanisms and each one has it's own UserProvider. The security.yml looks like this:</p>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="security:
    providers:
        chain_provider:
            chain:
                providers: [provider1, provider2]
        provider1: ...
        provider2: ...

    firewalls:
        main:
            guard:
                authenticators:
                    - authenticator1
                    - authenticator2
                entry_point: authenticator1"><pre class="notranslate"><span class="pl-ent">security</span>:
    <span class="pl-ent">providers</span>:
        <span class="pl-ent">chain_provider</span>:
            <span class="pl-ent">chain</span>:
                <span class="pl-ent">providers</span>: <span class="pl-s">[provider1, provider2]</span>
        <span class="pl-ent">provider1</span>: <span class="pl-s">...</span>
        <span class="pl-ent">provider2</span>: <span class="pl-s">...</span>

    <span class="pl-ent">firewalls</span>:
        <span class="pl-ent">main</span>:
            <span class="pl-ent">guard</span>:
                <span class="pl-ent">authenticators</span>:
                    - <span class="pl-s">authenticator1</span>
                    - <span class="pl-s">authenticator2</span>
                <span class="pl-ent">entry_point</span>: <span class="pl-s">authenticator1</span></pre></div>
<p dir="auto">Now, as far as I understand, <a href="https://github.com/symfony/symfony/blob/v3.2.2/src/Symfony/Component/Security/Core/User/ChainUserProvider.php#L45-L58">ChainUserProvider::loadUserByUsername</a> lets each chained provider try to load a user with the provided credentials until one user is found or all providers have tried unsuccessfully. I.e. provider1 will eventually try to load a user with the credentials provided by authenticator2. If user1's credentials for authenticator1 are the same as user2's credentials for authenticator2, user2 would be logged in as user1 due to the order of the chained user providers. I think this should be prevented.</p>
<p dir="auto">My idea to work around that problem was to tie providers to authenticators, so that a provider would only accept credentials from it's corresponding authenticator(s). If loadUserByUsername would not only have one parameter for the username, but a second one for the calling authenticator, I could've implemented that check in this method.</p>
<p dir="auto">Makes sense? Is there a already a better way to tie the both of them? Or am I missing another concept here?</p>