Skip to content

Latest commit

 

History

History
92 lines (68 loc) · 2.4 KB

handler.md

File metadata and controls

92 lines (68 loc) · 2.4 KB

Handler examples

Interfaces

The interfaces are simple marker interfaces.

/** @method void __invoke(Command $command) */
interface CommandHandlerInterface
{
}
/** @method void __invoke(Query $query) */
interface QueryHandlerInterface
{
}

See position in process

Command handler

A command handler implementation to create a new user account might look like this:

final class CreateUserAccountCommandHandler implements CommandHandlerInterface
{
    public function __construct(
        private readonly PasswordHasherFactoryInterface $passwordHasherFactory,
        private readonly EntityManagerInterface $entityManager,
        private readonly UserRepository $userRepository,
    ) {
    }

    public function __invoke(CreateUserAccountCommand $command): void
    {
      $this->requestingUserMustBeAdmin($command);

      $this->noUserWithTheSameEmailAddressMustExist($command);

      $this->createNewUser($command);

      $this->sendUserWasCreatedInAppNotificationsToAllAdminUsersExceptRequestingUser($command);

      $this->sendUserWasCreatedEmailNotificationsToAllAdminUsersExceptRequestingUser($command);
    }

    ...

}

Query handler

The query handler always returns a value (if there is no exception). This return value can be anything from an object, array or even a callable. When it returns data, it must not return entities, but always custom read models instead. This is an example where the query handler would return a user read model.

final readonly class GetUserQueryHandler implements QueryHandlerInterface
{
    public function __construct(
        private UserRepository $userRepository,
    ) {
    }

    public function __invoke(GetUserQuery $query): ReadModel\User
    {
        $this->requestingUserMustBeAdmin($query);

        return $this->getTargetUser($query);
    }

    ...

    private function getTargetUser(GetUserQuery $query): ReadModel\User
    {
        $targetUser = $this->userRepository->findOneById($query->targetUserId);
        if ($targetUser === null) {
            throw new TargetUserNotFound();
        }

        return new ReadModel\User(
            $targetUser->userId,
            $targetUser->name,
            $targetUser->emailAddress,
        );
    }
}

Whatever is returned is not send to the client but rather transformed to a response object through the configured response constructor.