Backend DCA Building
List drivers and filter elements assemble their backend palettes and field tweaks at runtime by implementing
Contract\DcaContract:
use HeimrichHannot\FlareBundle\DataContainer\Builder\DcaBuilder;
use HeimrichHannot\FlareBundle\DataContainer\Builder\DcaContext;
public function buildDca(DcaBuilder $dca, DcaContext $context): void;
FLARE's loadDataContainer listener collects the configuration declared here (plus any changes made by
ElementDcaEvent listeners) and materializes it into the live
$GLOBALS['TL_DCA'] array for tl_flare_filter and tl_flare_list.
This replaces the removed palette: parameter of #[AsFilterElement] / #[AsListType] (now
#[AsListDriver]) and the removed
#[AsFilterCallback] / #[AsListCallback] DCA callback attributes. See
Migrating from v0.1 for the full mapping.
1. The DcaBuilder
palette(?string $palette): Sets the element's own palette part — a string of DCA legends and field names, e.g.'{filter_legend},fieldGeneric,preselect'. It is merged between the table's__prefix__and__suffix__palettes. Passnullif the type contributes no own fields.prefix(string|callable|null $prefix)/suffix(string|callable|null $suffix): Override the palette prefix/suffix for this type. A string replaces the table's__prefix__/__suffix__, a callablefn (string $current): stringtransforms it,nullkeeps it as is.field(string $name): DcaFieldBuilder: Returns a builder for per-type tweaks of a DCA field definition.
The referenced fields must exist in the table's DCA (tl_flare_filter / tl_flare_list) — field() tweaks
definitions, it does not create columns.
2. The DcaFieldBuilder
Fluent, all methods return the builder:
inputType(string $inputType): Sets the field'sinputType.eval(array $eval): Merges into the field'sevalarray.merge(array $definition): Merges an arbitrary partial field definition.options(callable|array $options): Sets the field's options — an array, or a lazyfn (): arraycallable evaluated when the DCA is built.load(callable $fn)/save(callable $fn): Registersload_callback/save_callbackhandlers.
3. The DcaContext
Read-only information about the record being edited:
| Member | Description |
|---|---|
$context->table | The DCA table being built (tl_flare_filter or tl_flare_list) |
$context->type | The element / list type alias |
$context->listModel | The ListModel of the (parent) list |
$context->filterModel | The FilterModel being edited, or null on tl_flare_list |
$context->getExecutionContext() | Lazy ?ListExecutionContext (query base, table aliases) |
$context->getTables() | array<string, string> of table names by alias |
$context->getTargetTable() | The table the filter's conditions target (configured target alias' table, falling back to the list's data container) |
4. Worked Example
Condensed from the built-in BooleanFilterElement:
use HeimrichHannot\FlareBundle\DataContainer\Builder\DcaBuilder;
use HeimrichHannot\FlareBundle\DataContainer\Builder\DcaContext;
public function buildDca(DcaBuilder $dca, DcaContext $context): void
{
$intrinsic = (bool) $context->filterModel?->intrinsic;
$dca->palette($intrinsic
? '{filter_legend},fieldGeneric,preselect'
: '{filter_legend},fieldGeneric,label,boolMode,preselect');
$dca->field('preselect')
->inputType('select')
->eval(['includeBlankOption' => false, 'chosen' => false])
->options([
'true' => 'flare.bool_preselect.true',
'false' => 'flare.bool_preselect.false',
]);
// Lazy options against the filter's target table
$dca->field('fieldGeneric')
->options(fn (): array => $this->getFieldOptions($context->getTargetTable()));
}
Note how the palette can react to the record's current state ($context->filterModel), and how expensive
option lookups stay lazy.
5. Modifying Another Type's DCA
To adjust the backend configuration of an element or list driver you don't own, listen to ElementDcaEvent
(HeimrichHannot\FlareBundle\Event\ElementDcaEvent, readonly properties $dca and $context). It is
dispatched after the element's own buildDca() ran, under a name specific to the type:
flare.filter_element.{type}.dcafor filter elements (ontl_flare_filter)flare.list.{type}.dcafor list drivers (ontl_flare_list)
use HeimrichHannot\FlareBundle\Event\ElementDcaEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener('flare.filter_element.flare_bool.dca')]
public function __invoke(ElementDcaEvent $event): void
{
$event->dca->field('preselect')->eval(['tl_class' => 'w50']);
}
6. Migrating from v0.1 Callbacks
| v0.1 | v0.2 |
|---|---|
#[AsFilterElement(palette: '...')] / #[AsListType(palette: '...')] | $dca->palette('...') in buildDca() |
#[AsFilterCallback(TYPE, 'fields.myField.options')] | $dca->field('myField')->options(...) — or ElementDcaEvent on flare.filter_element.{type}.dca for foreign types |
#[AsFilterCallback(TYPE, 'fields.myField.load')] / 'fields.myField.save' | $dca->field('myField')->load(...) / ->save(...) |
#[AsFilterCallback(TYPE, 'config.onload')] / list config.onload | buildDca() (own type) / ElementDcaEvent listener (foreign type) |
PaletteContract::getPalette() / PaletteEvent (flare.*.palette) | buildDca() with palette()/prefix()/suffix() / ElementDcaEvent (flare.*.dca) |