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

Protecting Invariants

24 views 0

Written by Joshua
August 14, 2024

An invariant is something that holds true about your domain no matter what. Invariants ensure consistency within the domain.

As an example using our Post aggregate, an invariant we could probably protect is that on insert, a title should not be empty or null.

TDD

First, let’s write out a test to prove that a TitleWasNullException is thrown when we violate the invariant.

<?php

use App\Domain\Post\Post;
use App\Domain\Post\TitleWasNullException;
use App\Domain\Post\ValueObject\PostId;
use App\Domain\Post\ValueObject\Title;
use App\Domain\Post\ValueObject\Content;

it('should not allow a null title.', function () use ($event) {
    return Post::createPost(
        postId: new PostId(value: '760b7c16-b28e-4d31-9f93-7a2f0d3a1c51'),
        title: new Title(value: ''),
        content: new Content(value: 'A null title is not allowed'),
    );
})->throws(exception: TitleWasNullException::class, exceptionMessage: 'Title cannot be null.');

Method Updates

In the last section, we introduced the Post aggregate. We will now update the methods createPost and changeTitle to meet our invariant exception. As mentioned in the previous section when we created some value objects, the Title value object inherits a few methods from the base class StringLiteral. One of those methods is isEmpty(). We can use this method to protect our invariant.

<?php

/**
 * @throws TitleWasNullException
 */
public static function createPost(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 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)
    );
}

Now that our methods have been updated, our tests should now pass.

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
  • Value Objects
  • Records Events
  • Identifies Aggregate

Didn't find your answer? Check out the Forum

  Records Events

Event Sourcing  

  • Copyright 2025 CodefyPHP.com. All Rights Reserved

Popular Search:installation, codex, mail