Problem/Motivation
DataDefinitionInterface can describe a value's type, label, description, settings, constraints and whether it is required — but not what value it starts from. Because the typed data layer can't express a default, every layer built on top of it has grown its own way of saying the same thing:
- Field API:
FieldDefinitionInterface::getDefaultValue(),getDefaultValueLiteral()andgetDefaultValueCallback(). - Plugin contexts:
ContextDefinition::getDefaultValue()/setDefaultValue(), bolted onto a class that is otherwise aDataDefinitionwrapper. - Config: defaults live outside the schema entirely, in each module's
config/installYAML. - Contrib APIs that describe inputs with data definitions (ECA, Typed Data API enhancements, tool-style input definitions) each re-add a default value property to their own wrapper.
Each of these is a parallel spelling of one concept the base definition can't carry. That has practical costs beyond duplication:
- Core can now emit JSON Schema from normalizers (the
json_schemaserialization format,\Drupal\Core\Serialization\Attribute\JsonSchema). JSON Schema has a standarddefaultkeyword, but a schema derived from typed data can never populate it — the source metadata has nowhere to hold one. The same gap applies to anything producing OpenAPI output from typed data. - Code that generates UI or documentation from a data definition (form builders, schema browsers, API docs) has to special-case every wrapper that happens to have its own default API, and gets nothing for plain definitions.
DataDefinition::createFromDataType('email')and friends give you a fully described value space with no way to suggest a starting point, even when the defining code knows one.
This was almost in core once: #2204509 originally proposed defaults for typed data definitions and context definitions together, and was deliberately narrowed to context definitions only — the typed data half was considered a nice addition that wasn't needed for the driving use case at the time (comment #12). The landscape has changed since: core now derives JSON Schema from typed data, which gives the deferred half a concrete consumer.
Steps to reproduce
Not applicable (feature request). For a quick illustration of the gap: build any DataDefinition and look for a way to declare what value it should start from — there isn't one, which is why ContextDefinition and FieldDefinitionInterface both carry their own.
Proposed resolution
Add default value support to DataDefinition as plain metadata, stored under a default value key in the definition array like the existing properties:
setDefault($value): staticgetDefault(): mixed
No behavior changes anywhere: TypedDataManager::create() keeps instantiating with whatever value it is given, and validation is untouched. The default is descriptive metadata that consumers opt into — schema emitters map it to the JSON Schema default keyword, form generators use it to prepopulate, and the layered APIs above could (in follow-ups, if desired) delegate to it instead of maintaining their own copies.
Naming needs care, per the discussion in #2204509: BaseFieldDefinition extends DataDefinition and implements FieldDefinitionInterface, whose getDefaultValue(FieldableEntityInterface $entity) takes a required argument — a no-arg getDefaultValue() on the base class would collide. Options include a distinct name for the definition-level accessor, or aligning with the no-arg getDefaultValueLiteral() shape the field layer already has. Whether the methods land on DataDefinitionInterface itself or only on the DataDefinition base class first is a second BC question for this issue to settle.
Remaining tasks
Agree on the definition array key and whether. RemovedhasDefault()is wanted.hasDefault().- Patch + tests.
- Follow-up issues: emit
defaultfrom the JSON Schema normalizers (See #3623431: Emit data definition default values as the JSON Schema "default" keyword); evaluate delegatingContextDefinition::getDefaultValue()to the underlying definition.
User interface changes
None.
Introduced terminology
None.
API changes
Three new methods on DataDefinition (and potentially DataDefinitionInterface, subject to the BC discussion above). Purely additive; no existing method changes signature or behavior.
Data model changes
None. The definition array gains an optional key.
Release notes snippet
Data definitions can now declare a default value via DataDefinition::setDefault(). The default is descriptive metadata available to consumers such as JSON Schema emitters and form generators; it does not change how typed data is instantiated or validated.
AI usage (if applicable)
- [x] AI Assisted Issue: This issue was generated with AI assistance, but was reviewed and refined by the creator.
- [ x] AI Assisted Code: This code was mainly generated by a human, with AI autocompleting or parts AI generated, but under full human supervision.
Issue fork drupal-3620920
Show commands
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
michaellander commentedComment #4
michaellander commentedComment #5
michaellander commentedComment #6
michaellander commentedI called out the emitting of default values to json schema as a separate issue, but would it be more appropriate to include as part of this? Setting back to needs work to remove the `hasDefault()` method, as it's inconsistent with the rest of the class.
Comment #7
michaellander commentedI created a separate issue for emitting to json schema #3623431: Emit data definition default values as the JSON Schema "default" keyword. Please let me know if the preference is to combine them.
Comment #8
michaellander commented