PHPackages                             php-architecture-kit/domain-core - 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. php-architecture-kit/domain-core

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

php-architecture-kit/domain-core
================================

Domain Core abstract classes, interfaces and categorized exceptions.

1.0.0(1mo ago)171MITPHPPHP ^7.4 || ^8.0

Since May 6Pushed 3w agoCompare

[ Source](https://github.com/php-architecture-kit/domain-core)[ Packagist](https://packagist.org/packages/php-architecture-kit/domain-core)[ Docs](https://github.com/php-architecture-kit/domain-core)[ RSS](/packages/php-architecture-kit-domain-core/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (2)Used By (1)

php-architecture-kit/domain-core
================================

[](#php-architecture-kitdomain-core)

Domain-Driven Design building blocks for PHP applications. Provides abstract classes, interfaces, and categorized domain exceptions mappable to HTTP status codes.

Features
--------

[](#features)

- **AggregateRoot** - Base class with domain event recording
- **DomainEvent** - Marker interface for domain events
- **Categorized Exceptions** - 7 domain exceptions mapped to HTTP codes (400, 402, 403, 409, 422, 424, 451)
- **Zero dependencies** - Pure PHP, no external packages
- **PHP 7.4+** - Compatible with legacy and modern PHP

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

[](#installation)

```
composer require php-architecture-kit/domain-core
```

Quick Start
-----------

[](#quick-start)

### Aggregate Root

[](#aggregate-root)

```
use PhpArchitecture\DomainCore\AggregateRoot;
use PhpArchitecture\DomainCore\DomainEvent;

class OrderCreated implements DomainEvent
{
    public function __construct(
        public readonly string $orderId,
        public readonly array $items,
    ) {}
}

class Order extends AggregateRoot
{
    private string $id;
    private array $items;
    private string $status = 'draft';

    public static function create(string $id, array $items): self
    {
        $order = new self();
        $order->id = $id;
        $order->items = $items;
        $order->recordEvent(new OrderCreated($id, $items));

        return $order;
    }

    public function confirm(): void
    {
        if ($this->status !== 'draft') {
            throw new InvalidStateToPerformActionException('Order already confirmed');
        }

        $this->status = 'confirmed';
        $this->recordEvent(new OrderConfirmed($this->id));
    }
}
```

### Using Domain Events

[](#using-domain-events)

```
// Create aggregate and perform actions
$order = Order::create('order-123', ['item1', 'item2']);
$order->confirm();

// Get recorded events (without clearing)
$events = $order->getEvents(); // [OrderCreated, OrderConfirmed]

// Release events (get and clear)
$events = $order->releaseEvents(); // [OrderCreated, OrderConfirmed]
$events = $order->getEvents();     // []
```

Domain Exceptions
-----------------

[](#domain-exceptions)

All exceptions extend `\DomainException` and can be mapped to HTTP status codes in your infrastructure layer.

ExceptionHTTP CodeWhen to Use`InvalidInputException`400 Bad RequestInput data violates business rules`PaymentStatusException`402 Payment RequiredAction requires specific payment status`InsufficientPrivilegeException`403 ForbiddenUser lacks required role/relationship`InvalidStateToPerformActionException`409 ConflictAggregate state doesn't allow action`InvalidStateCausedException`422 Unprocessable EntityData would cause invalid state`DependencyStateException`424 Failed DependencyDependent aggregate unavailable/wrong state`LegalRestrictionException`451 Unavailable For Legal ReasonsLegal restrictions prevent action### Exception Usage Examples

[](#exception-usage-examples)

```
use PhpArchitecture\DomainCore\Exception\InvalidInputException;
use PhpArchitecture\DomainCore\Exception\InsufficientPrivilegeException;
use PhpArchitecture\DomainCore\Exception\InvalidStateToPerformActionException;

class Order extends AggregateRoot
{
    public function addItem(string $sku, int $quantity, string $actorId): void
    {
        // 400 - Invalid input
        if ($quantity ownerId !== $actorId) {
            throw new InsufficientPrivilegeException('Only owner can modify order');
        }

        // 409 - Invalid state to perform action
        if ($this->status === 'shipped') {
            throw new InvalidStateToPerformActionException('Cannot modify shipped order');
        }

        $this->items[] = new OrderItem($sku, $quantity);
    }
}
```

### HTTP Mapping (Infrastructure Layer)

[](#http-mapping-infrastructure-layer)

```
// Symfony Exception Listener
use PhpArchitecture\DomainCore\Exception\InvalidInputException;
use PhpArchitecture\DomainCore\Exception\PaymentStatusException;
use PhpArchitecture\DomainCore\Exception\InsufficientPrivilegeException;
use PhpArchitecture\DomainCore\Exception\InvalidStateToPerformActionException;
use PhpArchitecture\DomainCore\Exception\InvalidStateCausedException;
use PhpArchitecture\DomainCore\Exception\DependencyStateException;
use PhpArchitecture\DomainCore\Exception\LegalRestrictionException;

class DomainExceptionListener
{
    private const HTTP_MAP = [
        InvalidInputException::class => 400,
        PaymentStatusException::class => 402,
        InsufficientPrivilegeException::class => 403,
        InvalidStateToPerformActionException::class => 409,
        InvalidStateCausedException::class => 422,
        DependencyStateException::class => 424,
        LegalRestrictionException::class => 451,
    ];

    public function onKernelException(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();

        foreach (self::HTTP_MAP as $class => $code) {
            if ($exception instanceof $class) {
                $event->setResponse(new JsonResponse(
                    ['error' => $exception->getMessage()],
                    $code
                ));
                return;
            }
        }
    }
}
```

API Reference
-------------

[](#api-reference)

### AggregateRoot

[](#aggregateroot)

MethodVisibilityDescription`getEvents(): DomainEvent[]`publicReturns recorded events without clearing`releaseEvents(): DomainEvent[]`publicReturns and clears recorded events`recordEvent(DomainEvent $event): void`protectedRecords a domain event### DomainEvent

[](#domainevent)

Marker interface - implement in your domain event classes:

```
interface DomainEvent {}
```

### Exceptions

[](#exceptions)

All exceptions extend `\DomainException` and accept standard parameters:

```
__construct(string $message = '', int $code = 0, ?Throwable $previous = null)
```

Testing
-------

[](#testing)

Package is tested with PHPUnit in the [php-architecture-kit/workspace](https://github.com/php-architecture-kit/workspace) project.

License
-------

[](#license)

MIT

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance94

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 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

Unknown

Total

1

Last Release

34d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/145db325ca53baabce2d955faebe43d56bc4f3122b9ae463d41ee0e5da487cea?d=identicon)[patrykbaszak](/maintainers/patrykbaszak)

---

Top Contributors

[![patrykbaszak](https://avatars.githubusercontent.com/u/66377724?v=4)](https://github.com/patrykbaszak "patrykbaszak (8 commits)")

---

Tags

dddframework agnosticaggregatedomain-core

### Embed Badge

![Health badge](/badges/php-architecture-kit-domain-core/health.svg)

```
[![Health](https://phpackages.com/badges/php-architecture-kit-domain-core/health.svg)](https://phpackages.com/packages/php-architecture-kit-domain-core)
```

###  Alternatives

[prooph/service-bus

PHP Enterprise Service Bus Implementation supporting CQRS and DDD

4421.4M32](/packages/prooph-service-bus)[ecotone/ecotone

Enterprise architecture layer for Laravel and Symfony — CQRS, Event Sourcing, Durable Workflows (Sagas, Orchestrators), Projections, and Outbox messaging via PHP attributes.

562565.8k41](/packages/ecotone-ecotone)[prooph/event-sourcing

PHP EventSourcing library

266818.8k18](/packages/prooph-event-sourcing)[predaddy/predaddy

Common DDD classes and utilities

16826.5k1](/packages/predaddy-predaddy)[php-flasher/flasher

The foundational PHP library for PHPFlasher, enabling the creation of framework-agnostic flash notifications. Ideal for building custom integrations or for use in PHP projects.

634.7M41](/packages/php-flasher-flasher)[phpmentors/domain-kata

Kata for domain models

73441.4k9](/packages/phpmentors-domain-kata)

PHPackages © 2026

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