PHPackages                             morebec/domain-normalizer - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. morebec/domain-normalizer

AbandonedArchivedLibrary[Utility &amp; Helpers](/categories/utility)

morebec/domain-normalizer
=========================

Domain Object Normalizer

0.4.0(5y ago)0222MITPHP

Since Feb 28Pushed 5y ago1 watchersCompare

[ Source](https://github.com/Morebec/DomainNormalizer)[ Packagist](https://packagist.org/packages/morebec/domain-normalizer)[ RSS](/packages/morebec-domain-normalizer/feed)WikiDiscussions master Synced 6d ago

READMEChangelogDependencies (6)Versions (7)Used By (0)

DomainNormalizer
================

[](#domainnormalizer)

DomainNormalizer is an Orkestra Component used to easily normalize domain objects, through a fluent interface. It has the benefit of moving serialization/persistence concerns out of the domain classes, while providing a quick and easy way of defining primitive mapping information for domain classes.

It contains features for both serialization and deserialization (through normalization).

Normalization
-------------

[](#normalization)

Normalization is the process of transforming a Domain Object instance to an array representation of primitive (int,string,float.bool, array) values. This array representation is called a normalized form.

Given a class structure like:

```
class Order
{
    /** @var string */
    private $id;

    /** @var int */
    private $createdAt;

    /** @var array */
    private $lineItems;
}

class OrderLineItem
{
    /**
     * @var string
     */
    private $productId;
    /**
     * @var int
     */
    private $quantity;

    public function __construct(ProductId $productId, int $quantity)
    {
        $this->productId = $productId;
        $this->quantity = $quantity;
    }
}

class ProductId
{
    /**
     * @var string
     */
    private $id;

    public function __construct(string $id)
    {
        $this->id = $id;
    }

    public function __toString()
    {
        return $this->id;
    }
}
```

Using the following definition:

```
use DateTime;
use Morebec\DomainNormalizer\Normalization\Configuration\NormalizerConfiguration;
use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinitionFactory as DefinitionFactory;
use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinition as Definition;
use Morebec\DomainNormalizer\Normalization\Normalizer;
use Morebec\DomainNormalizer\Normalization\NormalizationContext;

$config = new NormalizerConfiguration();

$config->registerDefinition(DefinitionFactory::forClass(
    Order::class,
    static function (Definition $d) {
        $d->property('id')
            ->renamedTo('ID')
            ->asString();

        $d->property('createdAt')->as(static function (NormalizationContext $context) {
            $value = $context->getValue();
            return (new DateTime("@$value"))->format('Y-m-d');
        });

        $d->property('lineItems')
            ->asArrayOfTransformed(OrderLineItem::class);

        $d->createProperty('nbLineItems')
            ->as(static function(NormalizationContext $context) {
                return count($context->getObject()->getLineItems());
            }
        );
    })
);

$config->registerDefinition(DefinitionFactory::forClass(
    OrderLineItem::class,
    static function (Definition $d) {
        $d->property('quantity');
        $d->property('productId')->asString();
    })
);

$normalizer = new Normalizer($config);
$obj = new Order();
$data = $normalizer->normalize($obj);
```

Would return the following normalized form:

```
[
  "id" => "id5e5716cf048284.16614551",
  "createdAt" => "2020-02-27",
  "lineItems" => [
    0 => [
      "quantity" => 5,
      "productId" => "5e5716cf0485b7.29093456",
    ],
    1 => [
      "quantity" => 5,
      "productId" => "5e5716cf048606.07838602"
    ]
  ]
];
```

It is also possible to contain your definitions inside classes:

```
use Morebec\DomainNormalizer\Normalization\Configuration\ObjectNormalizationDefinition;

class OrderDefinition extends ObjectNormalizationDefinition
{
    public function __construct()
    {
        parent::__construct(Order::class);

        $this->property('id')
            ->renamedTo('ID')
            ->asString();

        $this->property('createdAt')->as(static function (TransformationContext $context) {
            $value = $context->getValue();
            return (new DateTime("@$value"))->format('Y-m-d');
        });

        $this->property('lineItems')
            ->asArrayOfTransformed(OrderLineItem::class);

        $this->createProperty('nbLineItems')
            ->as(static function(TransformationContext $context) {
                return count($context->getObject()->getLineItems());
            }
        );
    }
}
```

The rules are simple:

- If the normalizer cannot find a definition for a given object:
    - It will look in its registry to find out if there is a definition for one of the object's parent class that it can use.
    - Otherwise: It will throw an exception
- Definitions follow an explicit declaration approach:
    - If a property exists on the instance but is not part the definition, it will not be normalized. It will be ignored.
    - If a property exists does not exists on the instance but is part of the definition:
        - Unless it is a "bound" property, the normalizer will throw an exception.
        - In the case of Bound properties, they will be added to the resulting normalized form. (This can be defined either though the `bound` definition when using definition factory or through the `createProperty`)

### Denormalization

[](#denormalization)

The process of denormalization is the opposite of normalization: Transforming a normalized form to a Domain Object Instance.

In denormalization definitions, instead of defining properties, we define keys.

The rules are similar to normalization but presets some subtle differences:

- Definitions also follow an explicit declaration approach:
    - If key exists on the normalized form but it not part of the definition, it will not be denormalized.
    - Every nested normalized forms must have an associated definition.
        - If none is found, the denormalizer will throw an exception.
    - If a key definition exists but the associated data does not:
        - It will apply the configured missing transformer which is usually to either throw an error, or provide a default value.
            - By default it is to throw an error
    - If a key definition exists, but no corresponding property exists on the class:
        - Throw an exception.

```
class OrderDenormalizationDefinition extends ObjectDenormalizationDefinition
{
    public function __construct()
    {
        parent::_construct(Order::class);
        $this->key('ID')
             ->renamedTo('id')
             ->as(static function (TransformationContext $context) {
                return new ProductId($context->getValue());
            }
        );

        $this->key('createdAt')->as(static function (TransformationContext $context) {
            return strtotime($context->getValue());
        });
        $this->key('newKey')->defaultsTo('test');

        $this->key('lineItems')
            ->asArrayOfTransformed(OrderLineItem::class);

    }
}
```

Automatic De/Normalization
--------------------------

[](#automatic-denormalization)

Although we recommend using explicit definitions, it is also possible to use automatic normalization and denormalization.
This can be useful when dealing with simple DTOs to normalize/denormalize:

```
new AutomaticNormalizationDefinition(Order::class);

new AutomaticDenormalizationDefinition(Order::class);
```

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity11

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~24 days

Total

5

Last Release

2173d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/10d7f5561446f2d4df4413803946e9f77175155d241f78bd65c0dd94e6caffc5?d=identicon)[jwillp](/maintainers/jwillp)

---

Top Contributors

[![jwillp](https://avatars.githubusercontent.com/u/5913483?v=4)](https://github.com/jwillp "jwillp (25 commits)")

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/morebec-domain-normalizer/health.svg)

```
[![Health](https://phpackages.com/badges/morebec-domain-normalizer/health.svg)](https://phpackages.com/packages/morebec-domain-normalizer)
```

###  Alternatives

[spatie/laravel-event-sourcing

The easiest way to get started with event sourcing in Laravel

9003.7M26](/packages/spatie-laravel-event-sourcing)[voku/arrayy

Array manipulation library for PHP, called Arrayy!

4875.5M16](/packages/voku-arrayy)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.4k423.9k30](/packages/mcp-sdk)[phpdocumentor/reflection

Reflection library to do Static Analysis for PHP Projects

12521.4M109](/packages/phpdocumentor-reflection)[cognesy/instructor-php

The complete AI toolkit for PHP: unified LLM API, structured outputs, agents, and coding agent control

310107.9k1](/packages/cognesy-instructor-php)[symfony/ai-platform

PHP library for interacting with AI platform provider.

51927.7k136](/packages/symfony-ai-platform)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
