简体   繁体   中英

Symfony DDD + Event Sourcing work with related object

I use for my project boilerplate: https://github.com/jorge07/symfony-4-es-cqrs-boilerplate

I have some problems with save and fetch object with related field, but some example:

  • User
  • Stream

Stream has owner User, so mapping:

stream

    <entity name="App\Infrastructure\Stream\Query\Projections\StreamView" table="streams">
        <id name="uuid" type="uuid_binary" column="uuid"/>
        (...)
        <many-to-one field="user" target-entity="App\Infrastructure\User\Query\Projections\UserView" inversed-by="streams">
            <join-column nullable="false" referenced-column-name="uuid" />
        </many-to-one>
    </entity>

user

    <entity name="App\Infrastructure\User\Query\Projections\UserView" table="users">
        <id name="uuid" type="uuid_binary" column="uuid"/>
        (...)
        <one-to-many field="streams" target-entity="App\Infrastructure\Stream\Query\Projections\StreamView" mapped-by="user">
        </one-to-many>
    </entity>

I want to create new stream, related to User. So, I create CreateStreamCommand and Handler, like this:

    public function __invoke(CreateStreamCommand $command): void
    {
        $stream = $this->streamFactory->register($command->uuid, $command->user, $command->parameters);

        $this->streamRepository->store($stream);
    }

    public function __construct(StreamFactory $streamFactory, StreamRepositoryInterface $streamRepository)
    {
        $this->streamFactory    = $streamFactory;
        $this->streamRepository = $streamRepository;
    }

register method from StreamFactory

    public function register(UuidInterface $uuid, UserViewInterface $user, Parameters $parameters): Stream
    {
        return Stream::create($uuid, $user, $parameters);
    }
create method from Stream
    public function __construct(UuidInterface $uuid, UserViewInterface $user, Parameters $parameters)
    {
        $this->uuid         = $uuid;
        $this->user         = $user;
        $this->parameters   = $parameters;
    }

    /**
     * @throws \Assert\AssertionFailedException
     */
    public static function deserialize(array $data): self
    {
        Assertion::keyExists($data, 'uuid');
        Assertion::keyExists($data, 'user');
        Assertion::keyExists($data, 'parameters');

        return new self(
            Uuid::fromString($data['uuid']),
            $data['user'],
            Parameters::fromArray($data['parameters'])
        );
    }

    public function serialize(): array
    {
        return [
            'uuid'          => $this->uuid->toString(),
            'user'          => $this->user,
            'parameters'    => $this->parameters->toArray()
        ];
    }

And StreamWasCreated Event

PHP Fatal error:  Uncaught Symfony\Component\Debug\Exception\FatalThrowableError: Argument 2 passed to App\Domain\Stream\Event\StreamWasCreated::__construct() must implement interface App\Domain\User\Query\Projections\UserViewInterface, array given, called in /app/src/Domain/Stream/Event/StreamWasCreated.php on line 51 in /app/src/Domain/Stream/Event/StreamWasCreated.php:32
Stack trace:
#0 /app/src/Domain/Stream/Event/StreamWasCreated.php(51): App\Domain\Stream\Event\StreamWasCreated->__construct(Object(Ramsey\Uuid\Uuid), Array, Object(App\Domain\Stream\ValueObject\Parameters))
#1 /app/vendor/broadway/broadway/src/Broadway/Serializer/SimpleInterfaceSerializer.php(58): App\Domain\Stream\Event\StreamWasCreated::deserialize(Array)
#2 /app/vendor/broadway/event-store-dbal/src/DBALEventStore.php(234): Broadway\Serializer\SimpleInterfaceSerializer->deserialize(Array)
#3 /app/vendor/broadway/event-store-dbal/src/DBALEventStore.php(93): Broadway\EventStore\Dbal\DBALEventStore->deserializeEvent(Array)
#4 /app/vendor/broadway/broadway/s in /app/src/Domain/Stream/Event/StreamWasCreated.php on line 32

At this step I don't serialize user, and everything is fine. But... When I want to get this Stream record, I see error:

 PHP Fatal error: Uncaught Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Argument 2 passed to App\\Domain\\Stream\\Event\\StreamWasCreated::__construct() must implement interface App\\Domain\\User\\Query\\Projections\\UserViewInterface, array given, called in /app/src/Domain/Stream/Event/StreamWasCreated.php on line 51 in /app/src/Domain/Stream/Event/StreamWasCreated.php:32 Stack trace: #0 /app/src/Domain/Stream/Event/StreamWasCreated.php(51): App\\Domain\\Stream\\Event\\StreamWasCreated->__construct(Object(Ramsey\\Uuid\\Uuid), Array, Object(App\\Domain\\Stream\\ValueObject\\Parameters)) #1 /app/vendor/broadway/broadway/src/Broadway/Serializer/SimpleInterfaceSerializer.php(58): App\\Domain\\Stream\\Event\\StreamWasCreated::deserialize(Array) #2 /app/vendor/broadway/event-store-dbal/src/DBALEventStore.php(234): Broadway\\Serializer\\SimpleInterfaceSerializer->deserialize(Array) #3 /app/vendor/broadway/event-store-dbal/src/DBALEventStore.php(93): Broadway\\EventStore\\Dbal\\DBALEventStore->deserializeEvent(Array) #4 /app/vendor/broadway/broadway/s in /app/src/Domain/Stream/Event/StreamWasCreated.php on line 32 

I checked second argument, and it is empty array. So I think, problem is in unserialize event data.

So my second try was serialize User object, but then I can't save Stream object, because doctrine thinks user is new object and try to cascade persist.

What is the propper way to work with relationship?

Sorry my english ;)

it may be too late, but I think your problem comes from your method that deserializes the StreamWasCreated object.

You return an object of the type StreamWasCreated that must take a UserViewInterface as a second parameter, so we have to make sure that $data['user'] contains a UserViewInterface .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM