Fixed
Project:
Display Builder
Version:
1.0.x-dev
Component:
Code
Priority:
Major
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
1 Oct 2026 at 08:32 UTC
Updated:
3 Nov 2026 at 16:30 UTC
Jump to comment: Most recent
Child 6 of #3624396: Plan: Harden InstanceInterface, IslandInterface and DisplayBuildableInterface as public API before RC1. An island with a form, the four Contextual panels today, gets it through a pattern of its own:
IslandWithFormInterface declares static getFormClass() and hasFormClass(). Core's PluginWithFormsInterface has the same names as instance methods taking an operation, so an island cannot implement both, and the statics cannot be deprecated in place.ApiController calls getFormClass() on a class name, twice.builder_id holds the instance ID, instance_id the node ID, and instance the node data.setBuilderId() and setNodeId() pass state the build info already carries. setNodeId() has no caller.#[Island] gains forms. Islands implement PluginWithFormsInterface through PluginWithFormsTrait. configure stays the profile form. The in-builder form gets its own operation, contextual, named after where it shows, as core names the settings_tray form of blocks.IslandFormBase builds the plugin form through plugin_form.factory, with one build info shape on every path: island ID, instance ID, node ID, node data, contexts. Named as #3627256: IslandInterface: name the instance $instance, and settle the island API before RC1 names them.getFormClass() and hasFormClass() leave IslandWithFormInterface before RC1, with a change record. ApiController asks the island plugin instead of its class.setBuilderId() and setNodeId() removed: the build info carries what they set.display_builder_island_{island_id}: plugin_form.factory returns a subform, so IslandFormBase stays the wrapper that owns the ID.None.
IslandWithFormInterface::getFormClass() and hasFormClass() removed. Islands with a form implement PluginWithFormsInterface, and declare forms on #[Island].setBuilderId() and setNodeId() removed: the build info carries what they set.None.
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mogtofu33 commentedComment #3
mogtofu33 commentedComment #4
mogtofu33 commentedComment #5
mogtofu33 commentedComment #6
mogtofu33 commentedComment #7
pdureau commentedIt worth considering such change, especially if it moves methods from our interface to a Core one.
It will also be the opportunity of not suffixing by "Base" a final class:
I am not sure about this specific part though:
In #3621008: Move DisplayBuildable form logic to a dedicated class, we did this change without such attribute (and without its
PluginWithFormsTraitcompanion) which is not necessary when all plugins shared the same form by default.Also,
PluginWithFormsInterfacewould be better positioned as the parent ofIslandWithFormInterfaceto avoid the weight of such an interface on all island plugins.This was already done in #3623623: Contextual form loses clicks and invalid values silently as far as I know.
Comment #9
pdureau commentedI did a try.
What is good:
IslandWithFormInterface's::hasFormClass(), ::getFormClass(),::setBuilderId()and::setNodeId()has been removedApiControlleris updatedWhat is not great:
IslandFormBaseis the Drupal form.IslandContextualFormis the plugin form. It's the same split as core's block forms, withBlockFormas the Drupal form and the block plugin's configure form inside. They can't be merged.A second commit is renaming
IslandFormBasetoIslandForm.Comment #10
pdureau commentedComment #11
csakiistvanComment #12
csakiistvan✅ Tested and works — applied MR !518 on top of current 1.0.x, rebuilt caches, opened the builder of a new page layout: the Config and Visibility tabs of a selected component render, Config edits update the preview, a Request Path visibility value saves to History, and two components keep their own form values when switching between them. The tests the proposed resolution asked for were missing, so I pushed them to the MR; keeping it in Needs review.
Tests added
IslandFormTest::testSameBuildInfoOnRenderAndSave: a test island with a form gets the same build info when rendered and when saved throughApiController::thirdPartySettingsUpdate().IslandFormTest::testIslandFormsDoNotShareFormId: the Config form and a second island form render with their own form ID and form build ID (#3623715).Notes
submitForm(), so the test compares the two builds.contextsdiffer between the paths:thirdPartySettingsUpdate()passes[](existing @todo), so the test leaves them out.Comment #13
pdureau commentedComment #14
mogtofu33 commentedThanks for the work. Changelog tracked for next release.