Merge path¶
This page sets out the realistic ways Form Factory Kits, or its approach, could reach Drupal core, and what each would cost. It is a proposal for discussion in #3562924 and #3525331, not a plan anyone has agreed to. Everything marked open on the readiness page applies to every option.
What would have to move¶
Form Factory Kits is the top of a stack of four contributed modules by the same maintainer:
| Module | What this module uses from it | Size |
|---|---|---|
drupal/kits 2.0.0-beta5 |
Kit (the base class of every kit: parameters, context, children, getChildrenArray()), KitInterface, KitsService (t() and getContainer()) |
4 PHP files, not re-counted on 25 October 2026 |
drupal/formfactory 2.1.0-beta3 |
FormFactoryService / FormFactoryInterface (load(), append(), getForm()) |
2 PHP files, not re-counted on 25 October 2026 |
drupal/query 2.0.0-beta7 |
Condition and Operator, used only by EntityAutoCompleteKit::setCondition() |
required by kits |
drupal/formfactorykits 2.1.0-beta2 |
the kits, traits, service and FormObjectBase |
76 PHP files under src/, not re-counted on 25 October 2026 |
Core cannot depend on contrib, so every option below has to deal with these three dependencies:
- kits and formfactory are small and could be folded into the core
code:
Kitbecomes the base ofFormFactoryKit(or merges into it), andFormFactoryServicebecomes a core service. Their known problems (shared state inFormFactoryService, side effects inKit::getChildrenArray(),KitsServicereading\Drupal::getContainer()instead of using injection) should be fixed in the move, not carried over. - query is only needed for one method. Dropping
setCondition()(keepingsetFilter(), which takes plain arrays) removes the dependency.
Options¶
(These options are numbered to keep them apart from A, B and C on the comparison page.)
For contrast, the wrapper approach (B) needs no new module and no contrib dependencies; its merge cost is a change to core's element base class and every element plugin (74 files in merge request !13985, tests included) plus the open AJAX coupling question from #3539320. Kits need no change to existing core code, but would bring a new module and have to absorb or replace three contributed modules first.
Option 1: core module (stable)¶
Add a new core module (name to be decided) containing the
kit classes, traits, the service and FormObjectBase, with kits and
formfactory absorbed.
- For: one supported API for everyone; nothing else in core has to change, because output is plain arrays.
- Against: the full API surface (44 factory methods, about 50 kit classes, 19 traits) becomes a BC promise at once, before anyone outside contrib has used it. Every new element type in core would need a kit to stay complete.
- Fit today: poor. Most readiness items are open.
Option 2: experimental core module¶
The same code as option 1, added under core's experimental module policy so the API can change between minor releases.
- For: gets real-world use and review from core contributors while the API can still change; core's process for experimental modules sets the quality bar and the path to stable (or removal).
- Against: experimental modules still need tests, coding standards and reviews to get in, so most readiness items have to be done first. It adds a second way to build forms, which documentation and support then have to explain.
- Fit today: possible after readiness items 1–6 and 9 are done.
Option 3: stay in contrib with a core-compatible interface¶
Keep Form Factory Kits in contrib. Bring kits and formfactory into this
project (or one project), fix the open items, and shape the public API so
that a later core version could be a drop-in replacement (same class names
under a different namespace, same method names).
- For: no core decision needed now; the API can be proven on real sites first; core reviewers can evaluate a stable contrib release instead of a plan. The approach does not need core changes to work, which is one of its main differences from wrappers.
- Against: does not by itself give core an object-oriented form API, which is what #3525331 is about; contrib adoption is uncertain.
- Fit today: the only option that does not depend on readiness work being done first.
Proposed first merge request¶
The smallest change that would let core reviewers evaluate the idea without committing to the whole kit catalogue:
- A core
Drupal\Core\Form\Kitnamespace (name to be decided) with:- one base class combining
Drupal\kits\KitandFormFactoryKit(parameters, context, children,getArray()returning a new array, no side effects on children); - one builder that does what
FormFactoryService::load()/append()/getForm()do, created per form rather than shared; - the traits that cover common properties:
TitleTrait,DescriptionTrait,RequiredTrait,DefaultValueTrait,ValueTrait,AttributesTrait,PrefixTrait,SuffixTrait,AjaxTrait.
- one base class combining
- A handful of kits that exercise nesting and AJAX: text field, select, checkboxes, details, container, vertical tabs, submit.
- Unit tests for every kit's output, and one functional test that builds a form with kits, submits it, and rebuilds it through AJAX from the form cache (the case that broke in #3539320).
- One core form converted as an example, as #3525331 did with
StringTextfieldWidget.
Explicitly out of the first MR: FormObjectBase, entity and file kits,
ExampleKit, TemplateKit, and the query integration.
Status of the work¶
| Step | Status | Evidence |
|---|---|---|
| Approach proposed in the core thread | done | #3525331 comment #84 |
| Separate evaluation issue | done | #3562924 |
| Documentation and evidence for reviewers | done | this section |
| Readiness items (tests, bugs, standards, releases) | open | Readiness |
kits and formfactory folded in or replaced |
open | formfactorykits.info.yml still lists both |
query dependency removed |
open | EntityAutoCompleteKit::setCondition() |
| Choice between options 1, 2 and 3 | open | needs core maintainers' input |
| First merge request | open | not started |