CodefyPHP FrameworkCodefyPHP Framework
  • Home
  • Community
    • Forum
    • Github
    • YouTube
  • News
  • Home
  • Community
    • Forum
    • Github
    • YouTube
  • News
home/Knowledge Base/Aggregates/Aggregates
Popular Search:installation, codex, mail

Aggregates

90 views 0

Written by Joshua
August 14, 2024

Aggregates are the most important part of Domain-Driven Design. They are not just plain old PHP objects (POPO), but rich models that help with the complexity of business rules and invariants.

Throughout the aggregates section, you will learn how to build a domain rich eventsourced aggregate. Here is an example of an eventsourced Post aggregate:

<?php

use App\Domain\Post\Exceptions\TitleWasNullException;
use App\Domain\Post\ValueObject\PostId;
use App\Domain\Post\ValueObject\Title;
use App\Domain\Post\ValueObject\Content;
use Codefy\Domain\Aggregate\AggregateRoot;
use Codefy\Domain\Aggregate\EventSourcedAggregate;
use Qubus\Exception\Data\TypeException;

use function Qubus\Inheritance\Helpers\tap;

final class Post extends EventSourcedAggregate implements AggregateRoot
{
    private PostId $postId;

    private Title $title;

    private Content $content;

    /**
     * @throws TitleWasNullException
     */
    public static function createPostWithoutTap(PostId $postId, Title $title, Content $content): Post
    {
        if ($title->isEmpty()) {
            throw new TitleWasNullException(message: 'Title cannot be null.');
        }

        $post = self::root(aggregateId: $postId);

        $post->recordApplyAndPublishThat(
            event: PostWasCreated::withData($postId, $title, $content)
        );

        return $post;
    }

    /**
     * @throws TitleWasNullException
     */
    public static function createPostWithTap(PostId $postId, Title $title, Content $content): Post
    {
        if ($title->isEmpty()) {
            throw new TitleWasNullException(message: 'Title cannot be null.');
        }

        return tap(
            value: self::root($postId),
            callback: fn($post) => $post->recordApplyAndPublishThat(
                PostWasCreated::withData(postId: $postId, title: $title, content: $content)
            )
        );
    }

    public static function fromNative(PostId $postId): Post
    {
        return self::root(aggregateId: $postId);
    }

    /**S
     * @throws TitleWasNullException
     */
    public function changeTitle(Title $title): void
    {
        if ($title->isEmpty()) {
            throw new TitleWasNullException(message: 'Title cannot be null.');
        }
        if ($title->__toString() === $this->title->__toString()) {
            return;
        }
        $this->recordApplyAndPublishThat(
            event: TitleWasChanged::withData(postId: $this->postId, title: $title)
        );
    }

    public function title(): Title
    {
        return $this->title;
    }

    public function content(): Content
    {
        return $this->content;
    }

    /**
     * @throws TypeException
     */
    protected function whenPostWasCreated(PostWasCreated $event): void
    {
        $this->postId = $event->aggregateId();
        $this->title = $event->title();
        $this->content = $event->content();
    }

    /**
     * @throws TypeException
     */
    protected function whenTitleWasChanged(TitleWasChanged $event): void
    {
        $this->postId = $event->aggregateId();
        $this->title = $event->title();
    }
}

There is a lot to unpack in the Post aggregate, but as you go through the rest of this section, you will begin to understand its parts as it's broken down and explained.

Forum

If you have any questions or issues, please feel free to post to the Documentation Forum.

SLA Support

If you are needing more hands on support, needing consultation, or help with setup, support me on Github at $60 or more. Once you've sponsored me, you will receive an email on the best way to contact me to start your support.

Edit on Github

Last Updated on August 14, 2024 by Joshua

Related Articles
  • Aggregate Repository
  • Event Store
  • Event Sourcing
  • Protecting Invariants
  • Value Objects
  • Records Events

Didn't find your answer? Check out the Forum

Identifies Aggregate  

  • Copyright 2025 CodefyPHP.com. All Rights Reserved

Popular Search:installation, codex, mail