Skip to main content

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 NormalizerOverridden byAssigned to Editable by Default
OpenDxp\Bundle\ToolboxBundle\Normalizer\LinkNormalizerOpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessLinkNormalizerlink
OpenDxp\Bundle\ToolboxBundle\Normalizer\ImageEditableNormalizerOpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessImageEditableNormalizerNone (used in Toolbox for certain image elements)

Additional Headless Toolbox Normalizers

These normalizers are assigned by default to specific editable elements:

NormalizerAssigned to Editable by Default
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessInputNormalizerinput
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessTextareaNormalizertextarea
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessWysiwygNormalizerwysiwyg
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessThumbnailNormalizerimage
OpenDxp\Bundle\HeadlessToolboxBundle\Normalizer\HeadlessVideoNormalizervhs

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.