Creating and registering projectors | laravel-event-sourcing | Spatie

 SPATIE

  Laravel Event Sourcing
=========================

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-event-sourcing](https://spatie.be/docs/laravel-event-sourcing/v6)  Using-projectors  Creating and registering projectors

 Version   v7   v6   v5   v4   v3   v2   v1

 Other versions for crawler [v7](https://spatie.be/docs/laravel-event-sourcing/v7) [v6](https://spatie.be/docs/laravel-event-sourcing/v6) [v5](https://spatie.be/docs/laravel-event-sourcing/v5) [v4](https://spatie.be/docs/laravel-event-sourcing/v4) [v3](https://spatie.be/docs/laravel-event-sourcing/v3) [v2](https://spatie.be/docs/laravel-event-sourcing/v2) [v1](https://spatie.be/docs/laravel-event-sourcing/v1)

- [ Introduction ](https://spatie.be/docs/laravel-event-sourcing/v6/introduction)
- [ Support us ](https://spatie.be/docs/laravel-event-sourcing/v6/support-us)
- [ Requirements ](https://spatie.be/docs/laravel-event-sourcing/v6/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-event-sourcing/v6/installation-setup)
- [ Questions and issues ](https://spatie.be/docs/laravel-event-sourcing/v6/questions-issues)
- [ Changelog ](https://spatie.be/docs/laravel-event-sourcing/v6/changelog)
- [ Upgrading ](https://spatie.be/docs/laravel-event-sourcing/v6/upgrading)
- [ Resources and alternatives ](https://spatie.be/docs/laravel-event-sourcing/v6/resources-and-alternatives)
- [ About us ](https://spatie.be/docs/laravel-event-sourcing/v6/about-us)

Getting familiar with event sourcing
------------------------------------

- [ Introduction ](https://spatie.be/docs/laravel-event-sourcing/v6/getting-familiar-with-event-sourcing/introduction)
- [ The traditional application ](https://spatie.be/docs/laravel-event-sourcing/v6/getting-familiar-with-event-sourcing/the-traditional-application)
- [ Using projectors to transform events ](https://spatie.be/docs/laravel-event-sourcing/v6/getting-familiar-with-event-sourcing/using-projectors-to-transform-events)
- [ Using aggregates to make decisions based on the past ](https://spatie.be/docs/laravel-event-sourcing/v6/getting-familiar-with-event-sourcing/using-aggregates-to-make-decisions-based-on-the-past)

Using projectors
----------------

- [ Writing your first projector ](https://spatie.be/docs/laravel-event-sourcing/v6/using-projectors/writing-your-first-projector)
- [ Creating and registering projectors ](https://spatie.be/docs/laravel-event-sourcing/v6/using-projectors/creating-and-configuring-projectors)
- [ Making sure events get handled in the right order ](https://spatie.be/docs/laravel-event-sourcing/v6/using-projectors/making-sure-events-get-handled-in-the-right-order)
- [ Thinking in events ](https://spatie.be/docs/laravel-event-sourcing/v6/using-projectors/thinking-in-events)

Using reactors
--------------

- [ Writing your first reactor ](https://spatie.be/docs/laravel-event-sourcing/v6/using-reactors/writing-your-first-reactor)
- [ Creating and configuring reactors ](https://spatie.be/docs/laravel-event-sourcing/v6/using-reactors/creating-and-configuring-reactors)

Using aggregates
----------------

- [ Writing your first aggregate ](https://spatie.be/docs/laravel-event-sourcing/v6/using-aggregates/writing-your-first-aggregate)
- [ Creating and configuring aggregates ](https://spatie.be/docs/laravel-event-sourcing/v6/using-aggregates/creating-and-configuring-aggregates)
- [ Testing aggregates ](https://spatie.be/docs/laravel-event-sourcing/v6/using-aggregates/testing-aggregates)
- [ Snapshots ](https://spatie.be/docs/laravel-event-sourcing/v6/using-aggregates/snapshots)

Advanced usage
--------------

- [ Preparing events ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/preparing-events)
- [ Replaying events ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/replaying-events)
- [ Storing metadata ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/storing-metadata)
- [ Handling exceptions ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/handling-exceptions)
- [ Discovering projectors and reactors ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/discovering-projectors-and-reactors)
- [ Using your own event storage model ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/using-your-own-event-storage-model)
- [ Using your own event storage repository ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/using-your-own-event-storage-repository)
- [ Using your own event serializer ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/using-your-own-event-serializer)
- [ Using aliases for stored event classes ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/using-aliases-for-stored-event-classes)
- [ Adding and Removing Projectors and Reactors ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/adding-and-removing-projectors-and-reactors)
- [ Aggregate Partials ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/aggregate-partials)
- [ Event Queries ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/event-queries)
- [ Commands ](https://spatie.be/docs/laravel-event-sourcing/v6/advanced-usage/commands)

      You are viewing the documentation for **an older version** of this package. You can check the version you are using with the following command:

 `                                    composer show spatie/laravel-event-sourcing                                                                                                                                                                                                                                    `

Creating and registering projectors
===================================

###  On this page

1. [ Creating projectors ](#content-creating-projectors)
2. [ Registering projectors ](#content-registering-projectors)
3. [ Using projectors ](#content-using-projectors)
4. [ Getting the uuid of an event ](#content-getting-the-uuid-of-an-event)
5. [ Manually registering event handling methods ](#content-manually-registering-event-handling-methods)
6. [ Using a class as an event handler ](#content-using-a-class-as-an-event-handler)
7. [ Using default event handling method names ](#content-using-default-event-handling-method-names)
8. [ Handling a single event ](#content-handling-a-single-event)
9. [ Want to know more? ](#content-want-to-know-more)

A projector is a class that listens for events that were stored. When it hears an event that it is interested in, it can perform some work.

Creating projectors
-----------------------------------------------------------------------------------------------------------------

Let's create a projector. You can perform this artisan command to create a projector in `app\Projectors`:

```
php artisan make:projector AccountBalanceProjector
```

Registering projectors
--------------------------------------------------------------------------------------------------------------------------

By default, the package will automatically find and register all projectors found in your application.

Alternatively, you can manually register projectors in the `projectors` key of the `event-sourcings` config file.

You can also add them to the `Projectionist`. This can be done anywhere, but typically you would do this in a ServiceProvider of your own.

```
namespace App\Providers;

use App\Projectors\AccountBalanceProjector;
use Illuminate\Support\ServiceProvider;
use Spatie\EventSourcing\Facades\Projectionist;

class EventSourcingServiceProvider extends ServiceProvider
{
    public function register()
    {
        // adding a single projector
        Projectionist::addProjector(AccountBalanceProjector::class);

        // you can also add multiple projectors in one go
        Projectionist::addProjectors([
            AnotherProjector::class,
            YetAnotherProjector::class,
        ]);
    }
}
```

Using projectors
--------------------------------------------------------------------------------------------------------

This is the contents of a class created by the artisan command mentioned in the section above.

```
namespace App\Projectors;

use Spatie\EventSourcing\EventHandlers\Projectors\Projector;

class MyProjector extends Projector
{
    public function onEventHappened(EventHappended $event)
    {
        // do some work
    }
}
```

Just by adding a typehint of the event you want to handle makes our package call that method when the typehinted event occurs. All methods specified in your projector can also make use of method injection, so you can resolve any dependencies you need in those methods as well.

Getting the uuid of an event
--------------------------------------------------------------------------------------------------------------------------------------------

In most cases you want to have access to the event that was fired. When [using aggregates](/laravel-event-sourcing/v5/using-aggregates/writing-your-first-aggregate) your events probably won't contain the uuid associated with that event. To get to the uuid of an event simply add a parameter called `$aggregateUuid` that typehinted as a string.

```
// ...

public function onMoneyAdded(MoneyAdded $event, string $aggregateUuid)
{
    $account = Account::findByUuid($aggregateUuid);

    $account->balance += $event->amount;

    $account->save();
}
```

The order of the parameters giving to an event handling method like `onMoneyAdded` does not matter. We'll simply pass the uuid to any arguments named `$aggregateUuid`.

Manually registering event handling methods
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

The `$handlesEvents` property is an array which has event class names as keys and method names as values. Whenever an event is fired that matches one of the keys in `$handlesEvents` the corresponding method will be fired. You can name your methods however you like.

Here's an example where we listen for a `MoneyAdded` event:

```
namespace App\Projectors;

use App\Account;
use App\Events\MoneyAdded;
use Spatie\EventSourcing\EventHandlers\Projectors\Projector;

class AccountBalanceProjector extends Projector
{
    /*
     * Here you can specify which event should trigger which method.
     */
    protected array $handlesEvents = [
        MoneyAdded::class => 'onMoneyAdded',
    ];

    public function onMoneyAdded(MoneyAdded $event)
    {
        // do some work
    }
}
```

When the package needs to call the projector, it will use the container to create that projector so you may inject any dependencies in the constructor. In fact, all methods specified in `$handlesEvent` can make use of method injection, so you can resolve any dependencies you need in those methods as well. Any variable in the method signature with the name `$event` will receive the event you're listening for.

Using a class as an event handler
-----------------------------------------------------------------------------------------------------------------------------------------------------------

Instead of letting a method on a projector handle an event you can use a dedicated class.

```
// in a projector

// ...

protected array $handlesEvents = [
    /*
     * If this event is passed to the projector, the `AddMoneyToAccount` class will be called.
     */
    MoneyAdded::class => AddMoneyToAccount::class,
];
```

Here's an example implementation of `AddMoneyToAccount`:

```
use App\Events\MoneyAdded;

class AddMoneyToAccount
{
    public function __invoke(MoneyAdded $event)
    {
        $event->account->addMoney($event->amount);
    }
}
```

Using default event handling method names
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

In the example above the events are mapped to methods on the projector using the `$handlesEvents` property.

```
// in a projector

// ...

protected array $handlesEvents = [
    MoneyAdded::class => 'onMoneyAdded',
];
```

You can write this a little shorter. Just put the class name of an event in that array. The package will infer the method name to be called. It will assume that there is a method called `on` followed by the name of the event. Here's an example:

```
// in a projector

// ...

protected array $handlesEvents = [
    /*
     * If this event is passed to the projector, the `onMoneyAdded` method will be called.
     */
    MoneyAdded::class,
];
```

Handling a single event
-----------------------------------------------------------------------------------------------------------------------------

You can `$handleEvent` to the class name of an event. When such an event comes in we'll call the `__invoke` method.

```
// in a projector

// ...

protected $handleEvent =  MoneyAdded::class,

public function __invoke(MoneyAdded $event)
{
}
```

Want to know more?
------------------------------------------------------------------------------------------------------------

We discuss projections and complex patterns such as CQRS in depth in our [Event Sourcing in Laravel](https://event-sourcing-laravel.com/) course. In practice, you want to check out these chapters:

- 5. Storing and Projecting Events
- 6. [Projectors in Depth](https://event-sourcing-laravel.com/projectors-in-depth)
- 14. CQRS
