Skip to content

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: Kit becomes the base of FormFactoryKit (or merges into it), and FormFactoryService becomes a core service. Their known problems (shared state in FormFactoryService, side effects in Kit::getChildrenArray(), KitsService reading \Drupal::getContainer() instead of using injection) should be fixed in the move, not carried over.
  • query is only needed for one method. Dropping setCondition() (keeping setFilter(), 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:

  1. A core Drupal\Core\Form\Kit namespace (name to be decided) with:
    • one base class combining Drupal\kits\Kit and FormFactoryKit (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.
  2. A handful of kits that exercise nesting and AJAX: text field, select, checkboxes, details, container, vertical tabs, submit.
  3. 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).
  4. 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