PHPackages                             somnambulist/aggregate-root - 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. somnambulist/aggregate-root

Abandoned → [somnambulist/domain](/?search=somnambulist%2Fdomain)ArchivedLibrary[Database &amp; ORM](/categories/database)

somnambulist/aggregate-root
===========================

An aggregate root implementation that raises domain events

1.0.0(7y ago)02MITPHPPHP &gt;=7

Since Jun 6Pushed 6y agoCompare

[ Source](https://github.com/dave-redfern/somnambulist-aggregate-root)[ Packagist](https://packagist.org/packages/somnambulist/aggregate-root)[ RSS](/packages/somnambulist-aggregate-root/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (4)Versions (2)Used By (0)

Moved to
==============================================================

[](#moved-to-httpsgithubcomdave-redfernsomnambulist-domain)

This repository has been archived. Please update to the combined package.s

Aggregate Root
--------------

[](#aggregate-root)

Implements a generalised Aggregate Root for raising domain events in an entity.

- [Doctrine and Domain Events](https://github.com/beberlei/whitewashing.de/blob/master/2013/07/24/doctrine_and_domainevents.rst)
- [Decoupling applications with Domain Events](http://www.whitewashing.de/2012/08/25/decoupling_applications_with_domain_events.html)
- [Gist for Doctrine Implementation](https://gist.github.com/beberlei/53cd6580d87b1f5cd9ca)

### Requirements

[](#requirements)

- PHP 7+

### Installation

[](#installation)

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

- composer install somnambulist/aggregate-root

### Using

[](#using)

An Aggregate is a Domain Driven Design concept that encapsulates a set of related domain concepts that should be managed together. See [Fowler: Aggregate Root](https://martinfowler.com/bliki/DDD_Aggregate.html)Examples include: Order, User, Customer. In your domain code, only the aggregate should be loaded.

First identify what you aggregate roots are within your domain objects. Then extend the abstract AggregateRoot into your root entity. This is the entry point for changes to that tree of objects.

Next: implement your domain logic and raise appropriate events for each of the changes that your aggregate should allow / manage.

### Raising Events

[](#raising-events)

To raise an event, decide which actions should result in a domain event. These should coincide with state changes in the domain objects and the events should originate from your main entities (aggregate roots).

For example: you may want to raise an event when a new User entity is created or that a role was added to the user.

This does necessitate some changes to how you typically work with entities and Doctrine in that you should remove setters and nullable constructor arguments. Instead you will need to manage changes to your entity through specific methods, for example:

- completeOrder()
- updatePermissions()
- revokePermissions()
- publishStory()

Internally, after updating the entity state, call: `$this->raise(new NameOfEvent([]))`and pass any specific parameters into the event that you want to make available to the listener. This could be the old vs new or the entire entity reference, it is entirely up to you.

```
public function __construct($id, $name, $another)
{
    $this->id        = $id;
    $this->name      = $name;
    $this->another   = $another;

    $this->>initializeTimestamps();

    $this->raise(new MyEntityCreatedEvent(['id' => $id, 'name' => $name, 'another' => $another]));
}
```

Generally it is better to not raise events in the constructor but instead to use named constructors for primary object creation:

```
private function __construct($id, $name, $another)
{
    $this->id        = $id;
    $this->name      = $name;
    $this->another   = $another;

    $this->>initializeTimestamps();
}

public static function create($id, $name, $another)
{
    $entity = new static($id, $name, $another, new DateTime());
    $entity->raise(new MyEntityCreatedEvent(['id' => $id, 'name' => $name, 'another' => $another]));

    return $entity;
}
```

### Dealing with Timestamps

[](#dealing-with-timestamps)

When dealing with Aggregates, the aggregate should maintain its state; this includes any timestamps. If these are deferred to the database or ORM layer, then your Aggregate is being changed outside separately to when the state was changed.

Instead of relying on the ORM or database, you should use the `initializeTimestamps()` and `updateTimestamps()` methods from the `Timestampable` trait, or implement similar logic yourself. Then in your aggregate (and other entities), be sure to call `updatedTimestamps()` whenever a change is made

### Firing Domain Events

[](#firing-domain-events)

See [Domain Events](https://github.com/dave-redfern/somnambulist-domain-events) for integrating various strategies for dispatching domain events raised from the aggregate root.

Be sure to read the posts by Benjamin Eberlei mentioned earlier and check out his [Assertion library](https://github.com/beberlei/assert) for low dependency entity validation.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity62

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

Unknown

Total

1

Last Release

2893d ago

### 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 (2 commits)")

---

Tags

doctrinedomain-eventsaggregate-root

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/somnambulist-aggregate-root/health.svg)

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

###  Alternatives

[doctrine/common

PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.

5.8k363.3M1.2k](/packages/doctrine-common)[gedmo/doctrine-extensions

Doctrine behavioral extensions

4.1k118.8M365](/packages/gedmo-doctrine-extensions)[symfony/property-info

Extracts information about PHP class' properties using metadata of popular sources

2.2k256.7M851](/packages/symfony-property-info)[beberlei/doctrineextensions

A set of extensions to Doctrine 2 that add support for additional query functions available in MySQL, Oracle, PostgreSQL and SQLite.

2.1k75.1M146](/packages/beberlei-doctrineextensions)[ramsey/uuid-doctrine

Use ramsey/uuid as a Doctrine field type.

90340.3M209](/packages/ramsey-uuid-doctrine)[carbonphp/carbon-doctrine-types

Types to use Carbon in Doctrine

213220.4M8](/packages/carbonphp-carbon-doctrine-types)

PHPackages © 2026

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