PHPackages                             jeckel-lab/contract - 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. jeckel-lab/contract

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

jeckel-lab/contract
===================

Contract / Interfaces used by other packages and DDD projects

v2.5.1(2y ago)37.3k7MITPHPPHP ^8.0CI failing

Since Jun 15Pushed 2y ago1 watchersCompare

[ Source](https://github.com/Jeckel-Lab/contract)[ Packagist](https://packagist.org/packages/jeckel-lab/contract)[ RSS](/packages/jeckel-lab-contract/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (10)Versions (18)Used By (7)

[![Latest Stable Version](https://camo.githubusercontent.com/0f80348f2794d42a7d0dd795e91b0b388491712400fe8f9f897bb61d3a46cdbc/68747470733a2f2f706f7365722e707567782e6f72672f6a65636b656c2d6c61622f636f6e74726163742f762f737461626c65)](https://packagist.org/packages/jeckel-lab/contract)[![Total Downloads](https://camo.githubusercontent.com/2090bd533ed3bab89f780fab57af4c12570eb5da2d0af0d0712041c88c179f35/68747470733a2f2f706f7365722e707567782e6f72672f6a65636b656c2d6c61622f636f6e74726163742f646f776e6c6f616473)](https://packagist.org/packages/jeckel-lab/contract)[![Build Status](https://camo.githubusercontent.com/b11cded934b401b4dcb0c68dceafb013f120214df6e3f84ad64ee628454e4c83/68747470733a2f2f7472617669732d63692e6f72672f4a65636b656c2d4c61622f636f6e74726163742e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/Jeckel-Lab/contract)[![codecov](https://camo.githubusercontent.com/d7fc0ecc5df0ed318267e6bca27e02b07c1bb6ea7644e7d193f25dd5149de50d/68747470733a2f2f636f6465636f762e696f2f67682f4a65636b656c2d4c61622f636f6e74726163742f6272616e63682f6d61696e2f67726170682f62616467652e7376673f746f6b656e3d38385844547171646172)](https://codecov.io/gh/Jeckel-Lab/contract)[![Mutation testing badge](https://camo.githubusercontent.com/bc747dbea8c20948af897747c116fe0cc4fe396151f22f1a17c0693491c77d98/68747470733a2f2f696d672e736869656c64732e696f2f656e64706f696e743f7374796c653d666c61742675726c3d687474707325334125324625324662616467652d6170692e737472796b65722d6d757461746f722e696f2532466769746875622e636f6d2532464a65636b656c2d4c6162253246636f6e74726163742532466d61696e)](https://dashboard.stryker-mutator.io/reports/github.com/Jeckel-Lab/contract/main)

Jeckel-Lab Contract
===================

[](#jeckel-lab-contract)

List of interfaces use as contract in other packages or DD projects

This contract includes some strong typings, object relation and psalm validation.

Require **`php >= 7.2.*`** and **`php >= 8.0`**

Release nameBranch namePhp Version1.xrelease/1.Xphp &gt;= 7.2 &amp; php &lt;= 8.02.xmasterphp &gt;= 8.0Documentation for version 2.x (php &gt;= 8.0)
=============================================

[](#documentation-for-version-2x-php--80)

Domain
------

[](#domain)

Domain contract are part of DDD implementation suggestion, it's not required and is not linked to any frameworks.

### Identity

[](#identity)

[Identity](src/Domain/Identity/Identity.php) are used to define a unique identifier for an Entity or a RootAggregate.

Identity must be:

- immutable
- final
- constructor should be private, use a factory method:
    - `new` ==&gt; Generate (if possible) a new Identity object with a random value (like UUIDs)
    - `from` ==&gt; Instantiate Identity from an existing value

> See detailed implementation proposal: [jeckel-lab/identity-contract](https://github.com/Jeckel-Lab/identity-contract)

### Entity

[](#entity)

**[Entity](src/Domain/Entity/Entity.php)**: main **Entity** contract

Entity **must** have an Id implementing the `Identity` interface.

Don't forget to use `@psalm templates`

```
/**
 * DiverId is using an `int` as unique identifier
 * @implements Identity
 */
final class DriverId implements Identity
{
}

/**
 * Now Driver can use a DriverId as an identifier
 * @implements Entity
 */
class Driver implements Entity
{
    public function __construct(private DriverId $id)
    {
    }

    /**
     * @return DriverId
     */
    public function getId(): Identity
    {
        return $id;
    }
}
```

### Event

[](#event)

[Event](src/Domain/Event/Event.php) are notification about what happened during a use case.

Event **must** be:

- immutable

### DomainEventAware

[](#domaineventaware)

**Entities** and **root aggregates** handle domain events. To facilitate this behaviour, you can use this **interface** and **trait**:

- **[DomainEventAwareInterface](src/Domain/Entity/DomainEventAwareInterface.php)**
- **[DomainEventAwareTrait](src/Domain/Entity/DomainEventAwareTrait.php)**

This interface defines two methods:

```
    /**
     * @param Event ...$events
     * @return static
     */
    public function addDomainEvent(Event ...$events): static;

    /**
     * @return list
     */
    public function popEvents(): array;
```

- `addDomainEvent` allow you to register new event occurred during a Use Case.
- `popEvent` will empty the entity's event list at the end of a use case to dispatch them into an Event Dispatcher.

Just use the interface and trait into your entity:

```
class MyEntity implement DomainEventAwareInterface
{
    use DomainEventAwareTrait;

    /**
     * Example of a use case that add an event to the queue
     * @return self
     */
    public function activateEntity(): self
    {
        $this->activated = true;
        $this->addDomainEvent(new EntityActivated($this->id));
        return $this;
    }

    //...
}
```

And if you use the CommandBus pattern, then you can add events to the response easily:

```
new CommandResponse(events: $entity->popEvents());
```

### ValueObject

[](#valueobject)

Using `ValueObject` to embed a value (or group of value for complex types) as an object allow you:

- to use strong typing in the application (a `Speed` can not be mixed with any random float)
- to embed data validation (be sure that the `Speed` is always a positive value, is lower than a reasonable value, etc.)

Value object must be defined as:

- immutable (one's instantiated, they should not be modified unless a new instance is created).
- final
- constructor should be private, use the static `from` method as a factory
- when requesting to ValueObject with same value, `from` should return the same instance

Think about implementing it like this:

```
final class Speed implements ValueObject, ValueObjectFactory
{
    private static $instances = [];

    private function __constructor(private float $speed)
    {
    }

    /**
     * @param mixed $value
     * @return static
     * @throws InvalidArgumentException
     */
    public static function from(mixed $speedValue): static
    {
        if (! self::$instances[$speedValue]) {
            if ($speedValue < 0) {
                throw new InvalidArgumentException('Speed needs to be positive');
            }
            self::$instances[$speedValue] = new self($speedValue);
        }
        self::$instances[$speedValue]
    }

    // implements other methods
}

// And now
$speed1 = Speed::from(85.2);
$speed2 = Speed::from(85.2);
$speed1 === $speed2; // is true
```

Core
----

[](#core)

> To be completed

### Command Dispatcher

[](#command-dispatcher)

> To be completed

> See detailed implementation proposal: [jeckel-lab/command-dispatcher](https://github.com/Jeckel-Lab/command-dispatcher)

### Query Dispatcher

[](#query-dispatcher)

> To be completed

> See detailed implementation proposal: [jeckel-lab/query-dispatcher](https://github.com/Jeckel-Lab/query-dispatcher)

Exceptions
----------

[](#exceptions)

Each layer has it's own Exception interface that extends `Throwable`:

- Core: [CoreException](src/Core/Exception/CoreException.php)
- Domain: [DomainException](src/Domain/Exception/DomainException.php)
- Infrastructure: [InfrastructureException](src/Infrastructure/Exception/InfrastructureException.php)
- Presentation: [PresentationException](src/Presentation/Exception/PresentationException.php)

In each layer, when we need to throw an Exception, we create a new class corresponding to the type of Exception. This class must:

- extends one of the [SPL exception](https://www.php.net/manual/en/spl.exceptions.php) or another (more generic) exception from the same namespace.
- implements the exception interface of the current layer.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity24

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity69

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

Recently: every ~217 days

Total

16

Last Release

783d ago

Major Versions

0.1.4 → v1.0.02020-12-10

v1.2.0 → v2.0.02021-07-06

PHP version history (4 changes)0.1.0PHP ^7.2

v1.0.0PHP ^7.3 || ^8.0

v1.1.1PHP ^7.2 || ^8.0

v2.0.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/57215536?v=4)[Jeckel-Lab](/maintainers/jeckel-lab)[@Jeckel-Lab](https://github.com/Jeckel-Lab)

---

Top Contributors

[![jeckel](https://avatars.githubusercontent.com/u/2981531?v=4)](https://github.com/jeckel "jeckel (110 commits)")

---

Tags

command-patterncontractsdddddd-patternsdtoentityeventsforce-immutabilityidentityphp8psalm-templatingvalueobject

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/jeckel-lab-contract/health.svg)

```
[![Health](https://phpackages.com/badges/jeckel-lab-contract/health.svg)](https://phpackages.com/packages/jeckel-lab-contract)
```

###  Alternatives

[google/cloud-core

Google Cloud PHP shared dependency, providing functionality useful to all components.

343121.4M79](/packages/google-cloud-core)[aimeos/aimeos-base

Aimeos base layer for abstracting from host environments

2.1k134.0k1](/packages/aimeos-aimeos-base)[phpgt/dom

Modern DOM API.

12412.2M18](/packages/phpgt-dom)[anthropic-ai/sdk

Anthropic PHP SDK

129134.7k5](/packages/anthropic-ai-sdk)[jaxon-php/jaxon-core

Jaxon is an open source PHP library for easily creating Ajax web applications

73142.3k25](/packages/jaxon-php-jaxon-core)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)

PHPackages © 2026

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