PHPackages                             somnambulist/domain-input - 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. somnambulist/domain-input

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

somnambulist/domain-input
=========================

A collection of Domain Input/Response classes to act as a bridge between domain and environment.

4.1.0(4y ago)01.5kMITPHPPHP &gt;=8.0CI failing

Since Aug 7Pushed 3y ago3 watchersCompare

[ Source](https://github.com/somnambulist-tech/domain-input)[ Packagist](https://packagist.org/packages/somnambulist/domain-input)[ RSS](/packages/somnambulist-domain-input/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (3)Versions (10)Used By (0)

Domain Input Mapper Library
---------------------------

[](#domain-input-mapper-library)

[![GitHub Actions Build Status](https://camo.githubusercontent.com/f7d46450c0414cd079c700564fc89903c4d941a6af5a9eab74b51d0c7b271ba9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f736f6d6e616d62756c6973742d746563682f646f6d61696e2d696e7075742f74657374732e796d6c3f6c6f676f3d676974687562266272616e63683d6d6173746572)](https://github.com/somnambulist-tech/domain-input/actions?query=workflow%3Atests)[![Issues](https://camo.githubusercontent.com/5c962dd50203bdbd4a6cd68937bb4a92bba1dcc928ea06dfb44d766488e49773/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f736f6d6e616d62756c6973742d746563682f646f6d61696e2d696e7075743f6c6f676f3d676974687562)](https://github.com/somnambulist-tech/domain-input/issues)[![License](https://camo.githubusercontent.com/4ca3d088d1a15721a5612ea829e9fb1689f966002825f31db521db47a2708f75/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f736f6d6e616d62756c6973742d746563682f646f6d61696e2d696e7075743f6c6f676f3d676974687562)](https://github.com/somnambulist-tech/domain-input/blob/master/LICENSE)[![PHP Version](https://camo.githubusercontent.com/2ac61a7e39fb8aad0dacf399174b66c36d0da46eeb2d8b6472566ea46d584ae3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f736f6d6e616d62756c6973742f646f6d61696e2d696e7075743f6c6f676f3d706870266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/somnambulist/domain-input)[![Current Version](https://camo.githubusercontent.com/c0e88f5a0f25adf883534fbb5e94df1752fe554eb204caf44783f44b7049b08a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736f6d6e616d62756c6973742f646f6d61696e2d696e7075743f6c6f676f3d7061636b6167697374266c6f676f436f6c6f723d7768697465)](https://packagist.org/packages/somnambulist/domain-input)

This library provides an abstraction between a request object e.g. Http\\Request and your domain entities. Instead of passing the request directly, it is converted to a DomainInput object that contains the information to be mapped to the domain objects. The domain input contains read-only collections of the request data and files.

For Http, the Symfony UploadedFile and Request are used, however any request could be used.

### Requirements

[](#requirements)

- PHP 8.0+
- somnambulist/collection 5.0+

### Installation

[](#installation)

Install using composer, or checkout / pull the files from github.com.

- composer require somnambulist/domain-input

### Domain Input

[](#domain-input)

The first component is DomainInput and the associated factory class: DomainInputFactory. The factory contains methods to create from a HttpRequest or directly from passed collections.

The DomainInput object contains all input and file data that is to be mapped into an entity or aggregate route in the domain. By abstracting away the request type, the domain mapping / processing can be kept clean of implementation and more easily used in other contexts.

The DomainInput is composed of:

- inputs
- files

Both are converted from standard collections to Immutable collections. These should not be modified once created as they now represent the request into the domain.

DomainInput has accessors for input (aliased to get()) and to file(). Both support dot notation to access nested arrays of data e.g.: object.type.file.

### Domain Response

[](#domain-response)

When returning data back from the domain, it can be preferable to represent the results as a single unit that includes:

- transformed domain data
- the transaction / domain status
- any messages (e.g. errors / warnings)

A basic interface and implementation are provided that implement a Domain Response.

This response is read-only and utilises the Immutable collection for storing the domain data and any messages. In addition, the original Domain Input is associated with the response. This ensures that the originating input is available when further processing the domain data.

An important feature is that domain processing result is provided in this response. It does not need to be "discovered" again by a view / responder layer. The status can be any data type that your application requires, though either a string or integer are suggested.

As the response is read-only and built via the constructor, any domain data should be collected in a Collection and this passed into the constructor.

### Domain Mapper

[](#domain-mapper)

The last component is an interface and basic aggregate implementation for mapping the DomainInput to your entity / aggregates. This is a very simple interface containing two methods:

- `map`
- `supports`

`map` performs the work and accepts the DomainInput and a pre-created entity. It is important to note that the mapper is not intended to create the main root entity / aggregate. This should be provided to it via a separate factory step before the data is mapped to it. With that said, mappers can create the needed sub-entities that will be attached to the root.

`supports` is a simple check to see if the mapper supports the passed entity. This will usually be an instanceof type check against the entity. This is used in an aggregate mapper to prevent unsupported mappers from being called with the entity.

The mapper itself can be as complex or as simple as needed; the one thing to keep in mind is that it should only perform mapping for a single entity or sub-set of the aggregate. For example: you have an aggregate composed of an order with sub-entities of line-items, the customer, an address. Each of these may require separate repositories or additional support logic. This can be encapsulated within individual mappers and an OrderMapper aggregate used to map the whole input at one time.

### Example

[](#example)

#### The main order mapper

[](#the-main-order-mapper)

```
use Somnambulist\Components\Domain\Contracts\DataInputMapper as DataInputMapperContract;
class OrderMapper implements DataInputMapperContract
{

    /**
     * @param Input $input
     * @param Order $entity
     */
    public function map(Input $input, $entity)
    {
        $entity
            ->setProperty($input->get('order.property'))
            // ... do other mapping
        ;
    }

    /**
     * @return boolean
     */
    public function supports($entity)
    {
        return ($entity instanceof Order);
    }
}
```

#### Order item mapper

[](#order-item-mapper)

```
use Somnambulist\Components\Domain\Contracts\DataInputMapper as DataInputMapperContract;
class OrderItemMapper implements DataInputMapperContract
{

    protected $factory;

    public function __construct(OrderFactory $factory)
    {
        $this->factory = $factory;
    }

    /**
     * @param Input $input
     * @param Order $entity
     */
    public function map(Input $input, $entity)
    {
        // look up existing items, or make new ones
        foreach ($input->get('order.item') as $item) {
            $orderItem = $this->factory->createOrderItem($entity);

            // item will be an array, convert to collection
            $item = new Immutable($item);
            $orderItem
                ->setSomeProperty($item->get('some_property'))
                // ... do other mapping
            ;
        }
    }

    /**
     * @return boolean
     */
    public function supports($entity)
    {
        return ($entity instanceof Order);
    }
}
```

#### Address mapper

[](#address-mapper)

```
use Contracts\AddressableEntity;
use Somnambulist\Components\Domain\Contracts\DataInputMapper as DataInputMapperContract;
class AddressMapper implements DataInputMapperContract
{

    /**
     * @param Input $input
     * @param Order $entity
     */
    public function map(Input $input, $entity)
    {
        $address = new Address();
        $address
            ->setAddressLine1($input->get('address.address_line_1')
            //... assign the rest
        ;

        // addresses should be value objects so we'll check if it is the same
        // these methods will all be defined in the AddressableEntity interface.
        // The address being a value object will have an isSameAs method.
        if (!$entity->hasAddress() || !$entity->getAddress()->isSameAs($address)) {
            $entity->setAddress($address);
        }
    }

    /**
     * @return boolean
     */
    public function supports($entity)
    {
        return ($entity instanceof AddressableEntity);
    }
}
```

#### Putting them all together

[](#putting-them-all-together)

```
class OrderAggregateMapper extends AggregateMapper
{

}

// in an input handler / command (better defined in the DI container)
$mapper = new OrderAggregateMapper([
    new OrderMapper(),
    new OrderItemMapper(new OrderFactory()),
    new AddressMapper(),
]);

$input  = $inputFactory->createFromHttpRequest($request);
$entity = new Order();

$mapper->map($input, $entity);
```

The benefit of this approach is segregation and isolation of each piece. This makes each part easier to test, easier to manage and in some instances, the mapper can be re-used (e.g. address). The alternative to this would be a single handler that either has to receive an entity manager instance or many repositories to do the same job and what if you don't want to map all the data or you want to partially map the aggregate root in multiple steps? Each would have to be handled where as through this approach, simply add the mappers you need at the various stages.

Finally: it is important to remember that the data input mapper is a part of your domain and not part of the controller or context types. It should not be aware of HTTP or CLI specifics.

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity74

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

Recently: every ~222 days

Total

9

Last Release

1658d ago

Major Versions

1.0.3 → 2.0.02019-07-11

2.1.0 → 3.0.02020-08-26

3.0.0 → 4.0.02021-01-21

PHP version history (4 changes)1.0.0PHP &gt;=7

2.0.0PHP &gt;=7.2

3.0.0PHP &gt;=7.4

4.0.0PHP &gt;=8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/c0e439bf91b68c2e81e0250c752d3a552e78752c91acdf00c72a1f93aeb1ceca?d=identicon)[dredfern](/maintainers/dredfern)

---

Top Contributors

[![dave-redfern](https://avatars.githubusercontent.com/u/1477147?v=4)](https://github.com/dave-redfern "dave-redfern (13 commits)")

---

Tags

dddmappersphprequest-responseddddomaininput mapping

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/somnambulist-domain-input/health.svg)

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

###  Alternatives

[aura/payload

A Domain Payload implementation.

55377.9k9](/packages/aura-payload)[thejano/laravel-domain-driven-design

Helps to use domain driven design within laravel

15424.8k](/packages/thejano-laravel-domain-driven-design)[aura/payload-interface

An interface package for Domain Payload implementations.

12400.2k4](/packages/aura-payload-interface)

PHPackages © 2026

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