Fix #config_target support for the ai_provider_configuration element
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3580935. --> Reported by: [svendecabooter](https://www.drupal.org/user/35369) Related to !1342 >>> <p>[Tracker]<br> <strong>Update Summary: </strong>[One-line status update for stakeholders]<br> <strong>Short Description: </strong>[One-line issue summary for stakeholders]<br> <strong>Check-in Date: </strong>MM/DD/YYYY<br> <em>Metadata is used by the <a href="https://www.drupalstarforge.ai/" title="AI Tracker">AI Tracker.</a> Docs and additional fields <a href="https://www.drupalstarforge.ai/ai-dashboard/docs" title="AI Issue Tracker Documentation">here</a>.</em><br> [/Tracker]</p> <h3 id="summary-problem-motivation">Problem/Motivation</h3> <p>The <code>ai_provider_configuration</code> form element <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/ai/issues/3556181" title="Status: Closed (fixed)">#3556181: Create a form element for selecting providers</a></span> and the <code>ai.provider_config</code> schema type <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/ai/issues/3552774" title="Status: Closed (fixed)">#3552774: Create linkable schema for providers</a></span> were designed to work together. In <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/ai/issues/3552774" title="Status: Closed (fixed)">#3552774: Create linkable schema for providers</a></span> <a href="https://www.drupal.org/project/ai/issues/3552774#comment-16391026">comment #15</a>, @marcus_johansson described the intended workflow:</p> <ol> <li>Set up the `ai_provider_configuration` form element in your form.</li> <li>Store the value using the `ai.provider_config` config schema.</li> <li>Load the configured provider using a helper method from the plugin manager.</li> </ol> <p>However, step 2 doesn't work seamlessly because the form element and the schema use different value formats:</p> <p>Form element returns:</p> <div class="codeblock"> <pre><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br></span><span style="color: #007700">[<br>&nbsp; </span><span style="color: #DD0000">'provider' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'openai'</span><span style="color: #007700">,<br>&nbsp; </span><span style="color: #DD0000">'model' </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">'gpt-4.1'</span><span style="color: #007700">,<br>&nbsp; </span><span style="color: #DD0000">'config' </span><span style="color: #007700">=&gt; [</span><span style="color: #DD0000">'temperature' </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">0.7</span><span style="color: #007700">],<br>]<br></span><span style="color: #0000BB">?&gt;</span></span></pre></div> <p>Schema expects:</p> <pre>use_default: false<br>provider_id: openai<br>model_id: gpt-4.1<br>configuration:<br>&nbsp; temperature: 0.7</pre><p>This means:</p> <ul> <li>#config_target cannot be used with the ai_provider_configuration element, because ConfigFormBase::storeConfigKeyValueMap() would write the element's value (with provider/model/config keys) directly to config, which doesn't match the ai.provider_config schema (which expects use_default/provider_id/model_id/configuration keys). The element also sets '#default_value' =&gt; NULL in its getInfo(), which prevents ConfigFormBase::loadDefaultValuesFromConfig() from auto-populating the value.</li> <li>Every consumer module must manually translate between the two formats in submitForm() and when setting #default_value, adding error-prone boilerplate.</li> </ul> <p>The documentation added in <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/ai/issues/3556181" title="Status: Closed (fixed)">#3556181: Create a form element for selecting providers</a></span> (in ai_provider_configuration_element.md) even shows this manual translation in its "Saving to Configuration" example, confirming the gap.</p> <h4 id="summary-steps-reproduce">Steps to reproduce (required for bugs, but not feature requests)</h4> <ol> <li>Create a ConfigFormBase with an ai_provider_configuration element.</li> <li>Try to use #config_target pointing at a config key with type: ai.provider_config.</li> <li>Observe that: <ul> <li>The default value is not auto-populated from config (because getInfo() sets #default_value =&gt; NULL).</li> <li>On submit, the wrong key names are written to config (provider instead of provider_id, etc.).</li> <li>The use_default boolean is never set.</li> </ul> </li> </ol> <h3 id="summary-proposed-resolution">Proposed resolution</h3> <p>Add #config_target support to the ai_provider_configuration element by:</p> <ol> <li>Adding a toConfig() static method that translates the element's provider/model/config value to the schema's use_default/provider_id/model_id/configuration format.</li> <li>Adding a fromConfig() static method that does the reverse (for populating #default_value from config).</li> <li>These can be used as the ConfigTarget callable pair, enabling:</li> </ol> <pre>'#config_target' =&gt; new ConfigTarget(<br>&nbsp; 'my_module.settings',<br>&nbsp; 'provider_config',<br>&nbsp; toConfig: [AiProviderConfiguration::class, 'toConfig'],<br>&nbsp; fromConfig: [AiProviderConfiguration::class, 'fromConfig'],<br>),</pre><p>Or another method to achieve the same mapping logic automatically.</p> <h3 id="summary-remaining-tasks">Remaining tasks</h3> <ul> <li>Implement the translation layer or value format change</li> <li>Update the element's getInfo() so #default_value doesn't unconditionally block ConfigFormBase auto-population when #config_target is used</li> <li>Update documentation examples</li> <li>Add test coverage for #config_target usage with the element</li> </ul> <h3 id="summary-ai-usage">AI usage (if applicable)</h3> <p>[ x ] AI Assisted Issue<br> This issue was generated with AI assistance, but was reviewed and refined by the creator.</p> <p>[ x ] AI Generated Code<br> This code was mainly generated by an AI with human guidance, and reviewed, tested, and refined by a human.</p> > Related issue: [Issue #3552774](https://www.drupal.org/node/3552774) > Related issue: [Issue #3580948](https://www.drupal.org/node/3580948) > Related issue: [Issue #3580910](https://www.drupal.org/node/3580910)
issue