PHPackages                             stratadox/hydration-mapping - 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. [Database &amp; ORM](/categories/database)
4. /
5. stratadox/hydration-mapping

ActiveLibrary[Database &amp; ORM](/categories/database)

stratadox/hydration-mapping
===========================

v4.3(5y ago)1481[1 PRs](https://github.com/Stratadox/HydrationMapping/pulls)2MITPHPPHP &gt;=7.2CI failing

Since Nov 19Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/Stratadox/HydrationMapping)[ Packagist](https://packagist.org/packages/stratadox/hydration-mapping)[ RSS](/packages/stratadox-hydration-mapping/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependencies (10)Versions (20)Used By (2)

Hydration Mapping
=================

[](#hydration-mapping)

[![Build Status](https://camo.githubusercontent.com/1150edc79120b53c7cbf5ddd0e4a4935997519b89bdc205877b26a8aa820ff04/68747470733a2f2f636972636c6563692e636f6d2f67682f537472617461646f782f487964726174696f6e4d617070696e672e7376673f7374796c653d736869656c64)](https://app.circleci.com/pipelines/github/Stratadox/HydrationMapping)[![codecov](https://camo.githubusercontent.com/794ecddbb2e4f95b1770899562a2ee9ad198e01ba1f0351548c33e02a014527d/68747470733a2f2f636f6465636f762e696f2f67682f537472617461646f782f487964726174696f6e4d617070696e672f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/Stratadox/HydrationMapping)[![Infection Minimum](https://camo.githubusercontent.com/9869b35ce43d688258560e4884ced2122032ce9596e904aaf1d70390581b36b6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6d696e5f6d73692d37302d677265656e2e737667)](https://app.circleci.com/pipelines/github/Stratadox/Hydrator)[![PhpStan Level](https://camo.githubusercontent.com/fea51e527bede503df965094b675f2d69410677df2767431d51dd33dd584c556/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068707374616e2d382d627269676874677265656e2e737667)](https://travis-ci.org/Stratadox/HydrationMapping)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/6ed0118ad41bb0c110b7c1a9b98dc70c6e1c092704d89dd762977d0d55696b62/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f537472617461646f782f487964726174696f6e4d617070696e672f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/Stratadox/HydrationMapping/?branch=master)[![Maintainability](https://camo.githubusercontent.com/63f107b7022c7199c46ca97c3773f3206c0e8589c638cb4cbb284639bddb26a6/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f63633235383563653330333936376464346337642f6d61696e7461696e6162696c697479)](https://codeclimate.com/github/Stratadox/HydrationMapping/maintainability)[![Latest Stable Version](https://camo.githubusercontent.com/af961420186d2a3ca16bd34cb5f15340dee0237ee9bf2d4f112516e4af7723d3/68747470733a2f2f706f7365722e707567782e6f72672f737472617461646f782f687964726174696f6e2d6d617070696e672f762f737461626c65)](https://packagist.org/packages/stratadox/hydration-mapping)[![License](https://camo.githubusercontent.com/72c1beb71a730780c108a82b588f76a32d382a371e74381627564dadb59f1cd1/68747470733a2f2f706f7365722e707567782e6f72672f737472617461646f782f687964726174696f6e2d6d617070696e672f6c6963656e7365)](https://packagist.org/packages/stratadox/hydration-mapping)

[![Implements](https://camo.githubusercontent.com/22310323fd7a1ed5523bcaf5b168314c35a6ce539c298534ea228e4a5f723489/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f696e66657266616365732d6769746875622d626c75652e737667)](https://github.com/Stratadox/HydrationMappingContracts)[![Latest Stable Version](https://camo.githubusercontent.com/e98ab84e54f78f93bc8baca9b32ab5fd56bccc24f815b6eacb6a725efec5e5c1/68747470733a2f2f706f7365722e707567782e6f72672f737472617461646f782f687964726174696f6e2d6d617070696e672d636f6e7472616374732f762f737461626c65)](https://packagist.org/packages/stratadox/hydration-mapping-contracts)[![License](https://camo.githubusercontent.com/c98a3005452e206125b39d0f57191e58a1de6246890190cbfbbfc5918c7351ad/68747470733a2f2f706f7365722e707567782e6f72672f737472617461646f782f687964726174696f6e2d6d617070696e672d636f6e7472616374732f6c6963656e7365)](https://packagist.org/packages/stratadox/hydration-mapping-contracts)

Mappings for hydration purposes.

Maps array or array-like data structures to object properties, in order to assemble the objects that model a business domain.

Installation
------------

[](#installation)

Install using composer:

`composer require stratadox/hydration-mapping`

Purpose
-------

[](#purpose)

These mapping objects define the relationship between an object property and the source of the data.

Typical Usage
-------------

[](#typical-usage)

Typically, hydration mappings are given to [`Mapped`](https://github.com/Stratadox/Hydrator/blob/master/src/Mapping.php)[`Hydrator`](https://github.com/Stratadox/Hydrator) instances. Together they form a strong team that solves a single purpose: mapping data to an object graph.

For example:

```
use Stratadox\Hydration\Mapping\Simple\Type\IntegerValue;
use Stratadox\Hydration\Mapping\Simple\Type\StringValue;
use Stratadox\Hydrator\MappedHydrator;
use Stratadox\Hydrator\ObjectHydrator;

$hydrator = MappedHydrator::using(
    ObjectHydrator::default(),
    StringValue::inProperty('title'),
    IntegerValue::inProperty('rating'),
    StringValue::inPropertyWithDifferentKey('isbn', 'id')
);

$book = new Book;
$hydrator->writeTo($book, [
    'title'  => 'This is a book.',
    'rating' => 3,
    'isbn'   => '0000000001'
]);
```

More often, the mapped hydrator is given to a [`deserializer`](https://github.com/Stratadox/Deserializer):

```
use Stratadox\Deserializer\ObjectDeserializer;
use Stratadox\Hydration\Mapping\Simple\Type\IntegerValue;
use Stratadox\Hydration\Mapping\Simple\Type\StringValue;
use Stratadox\Hydrator\MappedHydrator;
use Stratadox\Hydrator\ObjectHydrator;
use Stratadox\Instantiator\ObjectInstantiator;

$deserialize = ObjectDeserializer::using(
    ObjectInstantiator::forThe(Book::class),
    MappedHydrator::using(
        ObjectHydrator::default(),
        StringValue::inProperty('title'),
        IntegerValue::inProperty('rating'),
        StringValue::inPropertyWithDifferentKey('isbn', 'id')
    )
);

$book = $deserialize->from([
   'title'  => 'This is a book.',
   'rating' => 3,
   'isbn'   => '0000000001'
]);
```

Mapping
-------

[](#mapping)

Three types of property mappings are available:

- Scalar mappings
- Relationship mappings
- Extension points

### Scalar Mapping

[](#scalar-mapping)

Scalar typed properties can be mapped using the `*Value` classes. The following scalar mappings are available:

- `BooleanValue`
- `FloatValue`
- `IntegerValue`
- `StringValue`
- `NullValue`

Scalar mappings are created through the named constructors:

- `inProperty`
    - Usage: `IntegerValue::inProperty('amount')`
    - Use when the property name and data key are the same.
- `inPropertyWithDifferentKey`
    - Usage: `BooleanValue::inPropertyWithDifferentKey('isBlocked', 'is_blocked')`
    - Use when the data key differs from the property name.

#### Basic Validation

[](#basic-validation)

When appropriate, these mappings validate the input before producing a value. For instance, the `IntegerValue` mapping checks that:

- The input value is formatted as an integer number
- The value does not exceed the integer boundaries

This process can be skipped by using the `Casted*` mappings instead. They provide a minor speed bonus at the cost of decreased integrity. `Casted*` mappings are available as:

- `CastedFloat`
- `CastedInteger`

To skip the entire typecasting process, the `OriginalValue` mapping can be used.

Input to a `BooleanValue` must either be 0, 1 or already boolean typed. Custom true/false values can be provided as optional parameters:

```
use Stratadox\Hydration\Mapping\Simple\Type\BooleanValue;

$myProperty = BooleanValue::withCustomTruths('foo', ['yes', 'y'], ['no', 'n']);
```

#### Nullable- and Mixed values

[](#nullable--and-mixed-values)

Each of the above mappings can be made *nullable* by wrapping the mapping with `CanBeNull`.

For example, instead of `IntegerValue::inProperty('foo')`, the `foo` property can be made *nullable* with: `CanBeNull::or(IntegerValue::inProperty('foo'))`.

In the same style, mixed value types can be configured. To map a value that could be either an int or a float, as numeric PHP values are often found, `CanBeInteger` can be used: `CanBeInteger::or(FloatValue::inProperty('foo')))`. This mapping will first check if the value can safely be transformed into an integer, and fall back to a floating point value. Non-numeric values will result in an exception, denoting where and why the input data could not be mapped.

These mixed mapping can be combined (as is customary for [decorators](https://sourcemaking.com/design_patterns/decorator)) to produce, for instance, mapping configurations that first attempt to map the value to a boolean, otherwise as an integer, if that cannot be done to cast it to a floating point, and if all else fails, make it a string:

```
use Stratadox\Hydration\Mapping\Simple\Type\CanBeBoolean;
use Stratadox\Hydration\Mapping\Simple\Type\CanBeInteger;
use Stratadox\Hydration\Mapping\Simple\Type\CanBeFloat;
use Stratadox\Hydration\Mapping\Simple\Type\StringValue;

$theProperty = CanBeBoolean::orCustom(
    CanBeInteger::or(
        CanBeFloat::or(
            StringValue::inProperty('bar')
        )
    ), ['TRUE'], ['FALSE']
);
```

### Relationship Mapping

[](#relationship-mapping)

Relationships can be mapped with a monogamous `HasOne*` or polygamist `HasMany*`mapping.

Each of these are connected to the input data in one of three ways:

- As `*Embedded` values (for loading from tabular data)
- As `*Nested` data structures (for loading from a json structure)
- As `*Proxies` (for loading lazily)

This boils down to the following possibilities:

- `HasManyNested`
- `HasManyProxies`
- `HasOneEmbedded`
- `HasOneNested`
- `HasOneProxy`

Relationship mappings are created through the named constructors:

- `inProperty`
    - Usage: `HasOneNested::inProperty('name', $deserializer)`
    - Use when the property name and data key are the same.
- `inPropertyWithDifferentKey`
    - Usage: `HasOneNested::inPropertyWithDifferentKey('friends', 'contacts', $deserializer)`
    - Use when the data key differs from the property name.

In this context, the term `key` refers to the key of the associative array from which the object data is mapped, also known as `offset`, `index` or `position`.

#### Nested vs Embedded

[](#nested-vs-embedded)

For `*Embedded` classes, there is no `inPropertyWithDifferentKey`. Instead of relying on an embedded array in the key, they are given the original input array and compose their attributes from one or more of its values.

##### Has One

[](#has-one)

`HasOne*`-type relationships are each given an object that [`Deserializes`](https://github.com/Stratadox/DeserializerContracts/blob/master/src/Deserializes.php)the related instance.

A `HasOneNested` receives the value that was found in the original input for the given `key`. This value must be an array, presumably associative.

`HasOneEmbedded` mappings take a different approach: they produce a new object from the data in the original input array. This approach is useful when mapping, for example, [embedded values](https://martinfowler.com/eaaCatalog/embeddedValue.html).

##### Has Many

[](#has-many)

A `HasMany*` relation requires one object that `Deserializes` the collection, and one that `Deserializes` the items.

This approach allows for a lot of freedom in the way collections are mapped. The available [deserializers](https://github.com/Stratadox/Deserializer) can map the collection either as plain array or to a custom collection object.

These deserializers may in turn use mapped hydrator instances. The combination
is able to map entire structures of objects in all kinds and shapes.

##### Proxies

[](#proxies)

[`Proxies`](https://github.com/Stratadox/Proxy) are used to allow for lazy loading. Rather than deserializers, they take a factory to create objects that, in turn, load the "real" object in place of the proxy whenever called upon.

Lazy has-one relations can be mapped with the `HasOneProxy` mapping. Lazy has-many relationships have the option to be normally lazy, or extra lazy. For extra lazy relations, the `HasManyProxies` mapping is used. When the relation is "regular" lazy, it is mapped as `HasOneProxy`, where "one" refers to one collection.

The latter only works when the collection is contained in a collection object. In cases where objects that are contained in an array should be lazy-loaded, a `HasManyProxies` mapping should be used, where each proxy is configured to load the entire array when called upon.

Using this mechanism, both lazy and extra-lazy loading is supported through any type of collection, whether it be an array or a collection object.

#### Bidirectional

[](#bidirectional)

Bidirectional `one-to-many` and `one-to-one` relationships can be mapped using the `HasBackReference` mapping.

This mapping acts as an observer to the hydrator for the owning side, assigning the reference of the "owner" object to the given property.

### Advanced validation

[](#advanced-validation)

Advanced input validation can be applied with a `ConstrainedMapping`. A `ConstrainedMapping` will produce the value of the mapping if the [specification](https://github.com/Stratadox/Specification) is satisfied with it, or throw an exception otherwise.

For example, a check on whether a rating is between 1 and 5 might look like this:

```
use Stratadox\Hydration\Mapping\Composite\ConstrainedMapping;
use Stratadox\Hydration\Mapping\Simple\Type\IntegerValue;
use Your\Constraint\IsNotLess;
use Your\Constraint\IsNotMore;

ConstrainedMapping::checkThatIt(
    IsNotLess::than(1)->and(IsNotMore::than(5)),
    IntegerValue::inProperty('rating')
);
```

The constraints themselves implement the (minimal) interface [`Satisfiable`](https://github.com/Stratadox/SpecificationInterfaces/blob/master/src/Satisfiable.php), which mandates only the method `isSatisfiedBy($input)`.

The recommended way to implement custom constraints is by extending the abstract [`Specification`](https://github.com/Stratadox/Specification/blob/master/src/Specification.php) class:

```
use Stratadox\Specification\Specification;

class IsNotLess extends Specification
{
    private $minimum;

    private function __construct(int $minimum)
    {
        $this->minimum = $minimum;
    }

    public static function than(int $minimum): self
    {
        return new self($minimum);
    }

    public function isSatisfiedBy($number): bool
    {
        return $number >= $this->minimum;
    }
}
```

Or by using the [`Specifying`](https://github.com/Stratadox/Specification/blob/master/src/Specifying.php)trait:

```
use Stratadox\Specification\Contract\Specifies;
use Stratadox\Specification\Specifying;

class IsNotMore implements Specifies
{
    use Specifying;

    private $maximum;

    private function __construct(int $maximum)
    {
        $this->maximum = $maximum;
    }

    public static function than(int $maximum): self
    {
        return new self($maximum);
    }

    public function isSatisfiedBy($number): bool
    {
        return $number maximum;
    }
}
```

### Default values

[](#default-values)

To honour the PHP spirit, a class is available that loads a default value rather than propagating the exception: `Defaults::to(-1, IntegerValue::inProperty('foo'))`

### Extension

[](#extension)

The `ClosureMapping` provides an easy extension point. It takes in an anonymous function as constructor parameter. This function is called with the input data to produce the mapped result.

For additional extension power, custom mapping can be produced by implementing the `Mapping` interface.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance54

Moderate activity, may be stable

Popularity14

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity67

Established project with proven stability

 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 ~64 days

Recently: every ~233 days

Total

18

Last Release

1999d ago

Major Versions

v1.4.2 → v2.02018-01-28

v2.2.0 → v3.02019-07-25

v3.0 → v4.22020-11-22

PHP version history (2 changes)v1PHP &gt;=7.1

v3.0PHP &gt;=7.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5333260?v=4)[Stratadox](/maintainers/Stratadox)[@Stratadox](https://github.com/Stratadox)

---

Top Contributors

[![Stratadox](https://avatars.githubusercontent.com/u/5333260?v=4)](https://github.com/Stratadox "Stratadox (274 commits)")

---

Tags

converterhydratehydrationhydratormappermappingmappingsormphp7

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/stratadox-hydration-mapping/health.svg)

```
[![Health](https://phpackages.com/badges/stratadox-hydration-mapping/health.svg)](https://phpackages.com/packages/stratadox-hydration-mapping)
```

###  Alternatives

[doctrine/orm

Object-Relational-Mapper for PHP

10.2k285.3M6.2k](/packages/doctrine-orm)[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k115.1M102](/packages/jdorn-sql-formatter)[illuminate/database

The Illuminate Database package.

2.8k52.4M9.4k](/packages/illuminate-database)[mongodb/mongodb

MongoDB driver library

1.6k64.0M546](/packages/mongodb-mongodb)[ramsey/uuid-doctrine

Use ramsey/uuid as a Doctrine field type.

90340.3M211](/packages/ramsey-uuid-doctrine)[reliese/laravel

Reliese Components for Laravel Framework code generation.

1.7k3.4M16](/packages/reliese-laravel)

PHPackages © 2026

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