Coder Social home page Coder Social logo

prooph / event-store Goto Github PK

View Code? Open in Web Editor NEW
548.0 548.0 74.0 2.03 MB

PHP 7.4 EventStore Implementation

Home Page: http://getprooph.org

License: BSD 3-Clause "New" or "Revised" License

PHP 100.00%
cqrs ddd event-sourcing event-store php prooph

event-store's People

Contributors

anthonysterling avatar basz avatar bgaleotti avatar camuthig avatar codeliner avatar danizord avatar darrylhein avatar dependabot-preview[bot] avatar dottorbabba avatar dropdevcoding avatar enumag avatar fjogeleit avatar fritz-gerneth avatar jiripudil avatar jsor avatar localheinz avatar mattketmo avatar nek- avatar oqq avatar prolic avatar rabbl avatar rodion-k avatar sandrokeil avatar sbacelic avatar shochdoerfer avatar tomcizek avatar unixslayer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

event-store's Issues

Proposal of adapter constructor changes

Currently we pass an array of options to any adapter constructor.
What would you think of passing a configuration object? You can still have an array of options, but you would pass them to the config object, instead of the adapter directly.

Something like this:

$config = new Config($someArray);
$adapter = new SomeAdapter();
$config->configureAdapter($adapter);

This is the same approach zf2 takes for the service manager, see: https://github.com/zendframework/zend-servicemanager/blob/master/src/Config.php

Downsides: We have to add public getters and setters to any adapter. For security reasons, we could disallow setting them twice (throwing an exception).

If accepted I could take this job over the weekend.

Thoughts?

Decouple ES from Aggregates

This is the epic for a major change in the EventStore library. From version 0.5.0 on the ES will only handle event streams. The repository and aggregate type concept will be removed. But the library will continue to support aggregates and their repositories. Different StreamStrategies will be available to support translation from aggregates to streams and back and to organize events of the aggregates in one or more streams.

Tasks

  • #20 - Remove AggregateType
  • #22 - Remove Repository Handling
  • #23 - Default Stream Strategies
  • #24 - Link Events In Projection Streams
  • #25 - Handle Event Meta Data

Support nested transactions

If you want to handle follow up commands in the same transaction the event store needs to support nested transactions.

Adapter::commit should only be called when the last open transaction is going to be commited and the commit.post event should only be triggered when all transactions are closed. On the other hand the commit.pre event should be triggered on every EventStore::commit call. The EventStore should set a is_nested_transaction flag in the commit.pre event to give listeners the chance to do their work only on real transaction commit.

For the AggregateRepositories it is important, that the commit.pre event is triggered on every commit call because a repository can register to the event in a nested transaction and is otherwise not called.

StreamName and EventName should normalize class names

Instead of using php namespace separator both VOs should normalize a namespace so that it is separated by dots instead of backslashes.

Please consider to change persistent adpaters and EventSourcing\AggregateChangedEventHydrator, too!

Introduce concept of EventFormatters

We should provide possibilities to format event data before it gets persisted. Not everybody is happy with the current way of persisting information f.e. the format used to store datetimes or the column type for UUIDs (allow binary type for DoctrineDBAL >=2.5).

See datetime discussion for zend-log

Feature required to create streams on the fly

Adapters should implement the FeatureInterface CreateStreamIfNotExists when they provide such a functionality. It should be possible to turn the mechanism on or off.

EventStore has to check if adapter can handle on the fly generation and throw an exception if not.

EventStore should trigger the creation only when a new entity should be persisted and the store has no entity of same type in the identity map.

EventStore provide event-driven possiblity to abort the try.

Convert DefaultAggregateTranslator to ConfigurableAggregateTranslator

Based on the new factories we should now also provide a more flexible AggregateTranslator.
In DDD you don't want to couple your model with the infrastructure so prooph/event-sourcing is out.
What we can do instead is to provide a configurable AggregateTranslator.
The translator should provide:

  • Option to change name and visibility of method to get the aggregate id
  • Option to change name and visibility of method to get pending stream events
  • Option to change name, visibility and static = true/false of method to reconstitute an aggregate

We can work with inheritance here to provide defaults but allow overriding them.

Note: The AggregateTranslator no longer needs to provide DomainEvents but instead Messages

MappedSuperclassStreamStrategy::__constructor has wrong initialization sequence

    public function __construct(EventStore $eventStore, AggregateType $superclass, array $aggregateTypeStreamMap = array())
    {
        $this->eventStore = $eventStore;

        $this->streamName = $this->buildStreamName($superclass);

        $this->aggregateTypeStreamMap = $aggregateTypeStreamMap;
    }

The MappedSuperclassStreamStrategy constructor executes streamName attribute initialization before aggregateTypeStreamMap attribute initialization, but buildStreamName uses aggregateTypeStreamMap attribute.
Given that order of inizialization $aggregateTypeStreamMap parameter is never considered and the streamName isn't inizialized properly.

Move event-store related factories from proophessor to this repo

Since zend-servicemanager v2.6 the zend service manager implements ContainerInterface.
So a zend specific factory is no longer needed and we can provide invokable factories instead. This allows the usage in any environment working with a ContainerInterface. The only requirement is is that a application wide config is registered as a service in the container. But this is a common and useful feature anyway.

Example Factory

final class EventStoreFactory
{
    public function __invoke(ContainerInterface $container)
    {
        $eventStoreConfig = $container->get(\Prooph\EventStore\Configuration\Configuration::class);

        if ($container->has(\Prooph\Common\Messaging\MessageFactory::class) {
            $eventStoreConfig->setMessageFactory(
                $container->get(\Prooph\Common\Messaging\MessageFactory::class);
            );
        }

        //get ES Adapter and other aspects ...

        return new EventStore($eventStoreConfig);
    }
}

Such a factory will centralize the event store initialization and increase re usability of the event-store component a lot.

Inject MessageFactory and Converter via adapter options

The event store Configuration should pass a Prooph\Common\Messaging\MessageFactory and a Prooph\Common\Messaging\MessageConverter as options to the event store adapter.
If no custom implementations were given the default implementations provided by prooph/common should be used.

Support snapshots

We need snapshots to replay Aggregates but also to regenerate read models

Implement EventStream as an iterator

Avoid loading all events from database at once. Allow the use of an iterator so event store adapters can provide a \Traversable instead of a domain event collection.

Enable configuration of the stream schema

In preparation for a message tracking component the event store should provide the possibility to customize the stream schema. This allows to add status flags like stream event was published etc.

A simple schema configuration with property name => property data type mapping should be enough for a first version.

This issue depends on:

and is related to prooph/service-bus#24

Document/Wiki

I'm wanting to learn using events stores, can you provide wiki/documentation for using this package?

Also if there is any resources that you can link that would be great I've read lots from what Greg Young has said.

RepositoryInterface

Here is my first feedback (as requested in #14 ๐Ÿ˜ƒ).

I find the naming of Prooph\EventStore\Repository\RepositoryInterface a bit confusing since it describes not a repository (at least as i understand it) but rather an adapter (or something) which the event store uses to extract event streams from an AR and to create AR's from event streams. It acts like a bridge between the event store and and the domain model.

I stumbled over this while integrating ProophEventStore with my application and i looked at how ProophEventSourcing integrates with ProophEventStore.

The EventSourcingRepository implements the RepositoryInterface and acts both as a repository (as i understand it) and a bridge for ProophEventStore.

A side effect is, that if you use a DIC, it would create a circular dependency as the EventSourcingRepository requires an EventStore instance and the EventStore requires a RepositoryInterface instance if you pass it through the $repositoryMap configuration.

Just a side note: The intergration of ProophEventSourcing into ProophEventStore is cluttered over 3 namspaces (Prooph\EventSourcing\EventStoreFeature, Prooph\EventSourcing\Mapping, Prooph\EventSourcing\Repository) which was a little bit confusing.

Other than that, nice work! ๐Ÿ‘
Once i figured that out, integrating ProophEventStore into my application was pretty straightforward.

Add replay functionality

Maybe #37 + some documentation about how to use the event store to replay read models is enough.

We need to think about the following questions:

  • List of common replay scenarios
  • Is it possible to replay all events of all streams in a single operation and does it make sense?
  • Is it ok to replay streams one after another?
  • Are the methods load and loadEventsByMetadataFrom enough to handle common replay scenarios?

Get rid of ZF2\Event dependency

Currently, the Pre- and PostCommitEvents are based on ZF2\Event. In PES 5.0 they should only extend Prooph\Common\ActionEvent.

Support mapped super class

It should be possible to define a super class as AggregateType for a repository but use the concret class of the passed aggregate to store it. A special form of the SingleStreamStrategy (maybe a MappedSuperClassStreamStrategy) and AggregateTranslator are required to store and load an aggregate without considering the AggregateType of the super class but the concret class.

Introduce DomainEventHydratorManager

It is not enough to only use the FQCN of an Event as identifier to reconstruct the event from a stream. A DomainEventHydratorManager could provide more strategies to reconstruct events.

Posibilities could be:

  • different Versions of same event
  • Shared Events
  • ...

FQCN should be translated to dot notation or events implement EventNameProviderInterface

Improve Readme

  • Better explain the concept behind prooph/event-store.
  • Underline the loose coupling with other prooph components and frameworks.
  • Better explain the event system + features and show some usage examples.
  • Migration path from PES v4.0 Not needed

Improve event-driven support of getRepository

The whole EventStore#getRepository implementation should be event-driven.

Checking for a special repo of an aggregate should be a listener with priority 100. Default behavior should be added as listener with low priority like -100. A third party component can then register a listener with prio 0 and provide a custom repo for a group of entities but not all entities.

Introduce AggregateManager

The AggregateManager should be reponsible for managing current state of an aggregate. It knows if aggregate is already persisted, holds the current version of the aggregate to detect concurrent logging issues and is responsible for making and providing snapshots of aggregates.

Add support for AggregateTypeProviders

Currently the AggregateType equals to the FQCN of the Aggregate. To support proxies it is necessary to introduce an AggregateTypeProviderInterface. If an Aggregate implements the interface, the AggregateType is taken from the method aggregateType() instead of using the FQCN.

Reduce hard dependencies on ZF2?

Would it be possible to reduce the dependencies on ZF2? I am trying to integrate the event-store into Symfony2. Event-store depends on prooph/common which has hard dependencies on several ZF2 modules.

Right now, installing event-store drags in 7 zend modules as required dependencies

  • zend/event-manager
  • zend/json
  • zend/log
  • zend/math
  • zend/serializer
  • zend/service-manager
  • zend/stdlib

Surely these aren't all required just to use the event-store in a non-ZF2 app? Can't a bunch of these be turned into "suggests"?

Find strategy to add custom metadata like causation id to events

With stream strategies you can add metaddata to events but currently this is only done insight a respository. Try to find ways of how this could be done from the outside. Let's say the id of the command should be added as a causation id to related events.
The command handler could pass metadata as additional argument to a repo::save method. Another idea is to have global context and use this within a special Stream Strategy.

Provide default stream strategies

A stream strategy is responsible for organizing events of an aggregate in one or more streams.

Sub-Task of #19

Default StreamStrategies

  • - One Stream Per Aggregate
  • - One Stream Per AggregateType
  • - One Stream for all Aggregates

AggregateRepository::aggregateType attribute not initialized in the constructor

Hi, I'm constructing my instance of AggregateRepository in this way:

class EventSourcingProjectService extends AggregateRepository implements ProjectService
{
    public function __construct(EventStore $eventStore, StreamStrategyInterface $eventStoreStrategy) {
        parent::__construct($eventStore, new AggregateTranslator(), $eventStoreStrategy, new AggregateType('Ora\ProjectManagement\Project'));
    }

    public function findProject($id)
    {
        $project = $this->getAggregateRoot($this->aggregateType, $id);
        return $project;
    }
} 

but when I call findProject, I got the following error:

Argument 1 passed to Prooph\EventStore\Aggregate\AggregateRepository::getAggregateRoot() must be an instance of Prooph\EventStore\Aggregate\AggregateType, null given"

Looking at the source code, the constructor of AggregateRepository does not initialize aggregateType attribute with the value passed to. Is it correct?

Thank you very much
Andrea

Use different repository types to decouple domain from ES

You can use diffrent repos for diffrent event sourcing contracts. See (Buttercup.protects)[http://buttercup-php.github.io/protects/] as an example for such a contract.

Move the logic of extracting and populating the DomainEvents to the repository implementation.

Configurable streaming strategy

It should be possible to configure the streaming strategy. Two options should be available:

  • One stream per AggregateRoot
  • A single stream for all Events

Write docu of pros and cons of both aproaches:

  • Read-Model depends on the order of events of different Aggregates
  • A single stream may cause partition problems
  • ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.