Normalizer
Objective
The primary goal of normalizers is to standardize API output across different endpoints and data structures.
This ensures consistency whether data is returned within a brick (relation) or through a dedicated API endpoint (e.g., /api/products).
General Rules
- If a brick returns data that is also available in other API endpoints, you must create a normalizer that applies the appropriate headless transformers and denormalizers.
- If the data is unique to a specific context, you can define the response directly within the
headlessAction.
To facilitate this, the toolbox provides built-in normalizers that can be applied automatically to specified types.
Toolbox Normalizer Overrides
Some normalizers in the Toolbox bundle are overridden by their headless counterparts:
| Toolbox Normalizer | Overridden by | Assigned to Editable by Default |
|---|---|---|
OpenDxp\Bundle\ToolboxBundle\Normalizer\LinkNormalizer | OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessLinkNormalizer | link |
OpenDxp\Bundle\ToolboxBundle\Normalizer\ImageEditableNormalizer | OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessImageEditableNormalizer | None (used in Toolbox for certain image elements) |
Additional Headless Toolbox Normalizers
These normalizers are assigned by default to specific editable elements:
| Normalizer | Assigned to Editable by Default |
|---|---|
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessInputNormalizer | input |
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessTextareaNormalizer | textarea |
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessWysiwygNormalizer | wysiwyg |
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessThumbnailNormalizer | image |
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessVideoNormalizer | vhs |
Default Normalizers
These additional normalizers are automatically applied when the bundle is installed (see the config block below). To override them, simply define them within the same structure.
# toolbox-bundle-bundle/config/opendxp/config.yaml
# this config block is available, if the toolbox headless bundle is installed
# you don't have to redefine them again in your project as long you don't have to override something
opendxp_toolbox:
property_normalizer:
default_type_mapping:
image: OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessThumbnailNormalizer
vhs: OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessVideoNormalizer
link: OpenDxp\Bundle\ToolboxBundle\Normalizer\LinkNormalizer
wysiwyg: OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessWysiwygNormalizer
textarea: OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessTextareaNormalizer
input: OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessInputNormalizer
Custom Normalizers
You can define and apply your own normalizers to transform specific brick elements.
Transformer Normalizer
A transformer normalizer is useful when converting structured data within a brick.
Configuration
opendxp_toolbox:
areas:
foo_bar:
inline_config_elements:
relation:
type: table
title: 'Table'
property_normalizer: App\Toolbox\Normalizer\TableNormalizer
Implementation
<?php
namespace App\Toolbox\Normalizer;
use App\Headless\Transformer\MyTransformer;
use OpenDxp\Model\Document\Editable\Table;
use OpenDxp\Bundle\ToolboxBundle\Normalizer\PropertyNormalizerInterface;
class TableNormalizer extends AbstractHeadlessNormalizer implements PropertyNormalizerInterface
{
public function normalize(mixed $value, ?string $toolboxContextId = null): mixed
{
if (!$value instanceof Table) {
return $value;
}
return $this->applyHeadlessTransformer(
$value,
MyTransformer::class,
[]
);
}
}
Denormalizer
A denormalizer is useful when transforming related objects (e.g., data objects) into response entities.
Configuration
opendxp_toolbox:
areas:
foo_bar:
inline_config_elements:
relation:
type: relation
title: 'My Entity'
config:
types:
- object
subtypes:
object:
- object
classes:
- MyEntity
property_normalizer: App\Toolbox\Normalizer\MyEntityNormalizer
Implementation
<?php
namespace App\Toolbox\Normalizer;
use App\Domain\Common\ResponseEntity\MyEntityResponseEntity;
use OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\AbstractHeadlessNormalizer;
use OpenDxp\Model\DataObject;
use OpenDxp\Model\Document\Editable\Relation;
use OpenDxp\Bundle\ToolboxBundle\Normalizer\PropertyNormalizerInterface;
class MyEntityNormalizer extends AbstractHeadlessNormalizer implements PropertyNormalizerInterface
{
public function normalize(mixed $value, ?string $toolboxContextId = null): mixed
{
if (!$value instanceof Relation) {
return null;
}
$myEntity = $value->getElement();
if (!$myEntity instanceof DataObject\MyEntity) {
return null;
}
return $this->applyDenormalizer($myEntity, MyEntityResponseEntity::class);
}
}
Summary
- Use normalizers to unify API responses across bricks and endpoints.
- Default normalizers are available and can be applied automatically to common data types.
- Custom normalizers allow transformation and denormalization of specific data structures.
- Transformers modify brick-specific structured data.
- Denormalizers convert related objects into standardized response entities.
By following these guidelines, you ensure a consistent and maintainable API response structure across your project.