Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recording events from AggregatePartial #373

Closed
giorgiopogliani opened this issue Oct 21, 2022 · 0 comments
Closed

Recording events from AggregatePartial #373

giorgiopogliani opened this issue Oct 21, 2022 · 0 comments

Comments

@giorgiopogliani
Copy link

giorgiopogliani commented Oct 21, 2022

Hello, to give some context the scenario I was in is: trying to send a notification when a user is tagged in some content.

I created the EntryAggregateRoot which has a method to update the content updateEntryContent(string $content).

class EntryAggregateRoot extends AggregateRoot 
{
    public function updateEntryContent(string $content): self
    {
        $this->recordThat(new EntryContentUpdated($content));
        
        return $this;
    }
}

Next I created a MentionsAggregatePartial to keep things separated because I might use it on some other content column

class MentionsAggregatePartial extends AggregatePartial
{
    protected array $mentionedUsersId = [];

    public function onMentionsAdded(EntryContentUpdated $event)
    {
         // When user is tagged in content for the first time
         $this->recordThat(new UserMentioned($userId));
    }
}

Also, to be able to add partials from packages I overrode the method resolvePartials like so:

class EntryAggregateRoot extends AggregateRoot 
{
    protected function resolvePartials(): Collection
    {
        if (! isset($this->entities)) {
            return collect(static::$partials)->map(function ($partial) {
                return new $partial($this);
            });
        }
    
        return $this->entities;
    }
    // ....
}

Everything seemed to work perfectly! But only the first time, the second update triggered the exception: Could not persist aggregate EntryAggregateRoot .... because it seems to be changed by another process after it was retrieved in the current process. Expect to persist events after version 21, but version 20 was already persisted.

So I inspected the source code and I come up this change that fixed the problem:

abstract class AggregateRoot
{
    // ...
    public function recordThat(ShouldBeStored $domainEvent): static
    {
        $domainEvent
            ->setAggregateRootUuid($this->uuid)
            ->setCreatedAt(CarbonImmutable::now());
    
        $this->recordedEvents[] = $domainEvent;
    
        $this->apply($domainEvent);
    
        $domainEvent->setAggregateRootVersion($this->aggregateVersion);
    
        // Moved here the apply on the aggregate partials outside the main apply and 
        // after the set for the aggregate root version above
        foreach ($this->resolvePartials() as $partial) {
            $partial->apply($domainEvent);
        }
    
        return $this;
    }
   // ...
}

Now everything works but I am not sure if this has some consequences. Also, I cannot really do that change without reflection magic because some property on the abstract class are private.

I'll wait some comments/feedbacks, thanks!

@spatie spatie locked and limited conversation to collaborators Oct 21, 2022
@freekmurze freekmurze converted this issue into discussion #374 Oct 21, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant