> For the complete documentation index, see [llms.txt](https://docs.ecotone.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ecotone.tech/modelling/event-sourcing/event-sourcing-introduction/event-sourcing-aggregates/applying-events.md).

# Applying Events

As [mentioned earlier](/modelling/event-sourcing/event-sourcing-introduction.md), Events are stored in form of a Event Stream.\
Event Stream is audit of Events, which happened in the past.\
However to protect our business invariants, we may want to work with current state of the Aggregate to know, if given action is possible or not (business invariants).

## Business Invariants

Business Invariants in short are our simple "**if"** statements inside the Command Handler in the Aggregate. Those protect our Aggregate from moving into incorrect state.\
With State-Stored Aggregates, we always have current state of the Aggregate, therefore we can check the invariants right away.\
With Event-Sourcing Aggregates, we store them in form of an Events, therefore we need to rebuild our Aggregate, in order to protect the invariants.

Suppose we have Ticket Event Sourcing Aggregate.

```php
#[EventSourcingAggregate]
class Ticket
{
    use WithAggregateVersioning;

    #[Identifier]
    private string $ticketId;

    (...)

    #[CommandHandler]
    public function assign(AssignPerson $command) : array
    {
        return [new PersonWasAssigned($this->ticketId, $command->personId)];
    }
}
```

For this Ticket we do allow for assigning an Person to handle the Ticket.\
Let's suppose however, that Business asked us to allow only one Person to be assigned to the Ticket at time. With current code we could assign unlimited people to the Ticket, therefore we need to protect this invariant.

To check if whatever Ticket was already assigned to a Person, our Aggregate need to have state applied which will tell him whatever the Ticket was already assigned.\
To do this we use **EventSourcingHandler attribute passing as first argument given Event class.** This method will be called on reconstruction of this Aggregate. So when this Aggregate will be loaded, if given Event was recorded in the Event Stream, method will be called:

```php
#[EventSourcingAggregate]
class Ticket
{
    use WithAggregateVersioning;

    #[Identifier]
    private string $ticketId;
    private bool $isAssigned;

    #[CommandHandler]
    public function assign(AssignPerson $command) : array
    {
        if ($this->isAssigned) {
           throw new \InvalidArgumentException("Ticket already assigned");
        }
    
        return [new PersonWasAssigned($this->ticketId, $command->personId)];
    }

    #[EventSourcingHandler]
    public function applyPersonWasAssigned(PersonWasAssigned $event) : void
    {
        $this->isAssigned = true;
    }
}
```

Then this state, can be used in the Command Handler to decide whatever we can trigger an action or not:

```php
if ($this->isAssigned) {
  throw new \InvalidArgumentException("Ticket already assigned");
}
```

{% hint style="success" %}
As you can see, it make sense to only assign to the state attributes that protect our invariants. This way the Aggregate stays readable and clean of unused information.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ecotone.tech/modelling/event-sourcing/event-sourcing-introduction/event-sourcing-aggregates/applying-events.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
