Skip to content

Commit

Permalink
step 9: introduce the query bus
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Lelaisant authored and AntoineGonzalez committed Apr 29, 2024
1 parent db7781c commit a394968
Show file tree
Hide file tree
Showing 21 changed files with 472 additions and 41 deletions.
2 changes: 2 additions & 0 deletions config/packages/messenger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ framework:
command.bus:
middleware:
- doctrine_transaction

query.bus: ~
5 changes: 5 additions & 0 deletions config/services/messenger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ services:
Application\MessageBus\CommandBus:
alias: Infrastructure\Symfony\Messenger\CommandBus

Infrastructure\Symfony\Messenger\QueryBus:
$messageBus: '@query.bus'

Application\MessageBus\QueryBus:
alias: Infrastructure\Symfony\Messenger\QueryBus
11 changes: 11 additions & 0 deletions config/services/queries.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Domain\Query\:
resource: '%kernel.project_dir%/src/Domain/Query/**/Handler.php'
tags:
- { name: messenger.message_handler, bus: query.bus }
36 changes: 15 additions & 21 deletions src/Application/Controller/DinosaursController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
use Application\Form\Type\DinosaurType;
use Application\Form\Type\SearchType;
use Application\MessageBus\CommandBus;
use Domain\Collection\DinosaursCollection;
use Application\MessageBus\QueryBus;
use Domain\Exception\DinosaurNotFoundException;
use Domain\Query\GetSingleDinosaur;
use Domain\Query\GetAllDinosaurs;
use Domain\UseCase\CreateDinosaur;
use Domain\UseCase\EditDinosaur;
use Domain\UseCase\RemoveDinosaur;
Expand All @@ -18,8 +21,8 @@
final class DinosaursController extends AbstractController
{
public function __construct(
private DinosaursCollection $dinosaursCollection,
private CommandBus $commandBus
private CommandBus $commandBus,
private QueryBus $queryBus
) {
}

Expand All @@ -37,9 +40,7 @@ public function list(Request $request): Response
$q = $search['q'];
}

$dinosaurs = $this
->dinosaursCollection
->search($q);
$dinosaurs = $this->queryBus->dispatch(new GetAllDinosaurs\Query($q));

return $this->render('dinosaurs-list.html.twig', [
'dinosaurs' => $dinosaurs,
Expand Down Expand Up @@ -108,29 +109,22 @@ public function create(Request $request): Response
)]
public function edit(Request $request, int $id): Response
{
$dinosaur = $this
->dinosaursCollection
->find($id);

if (false === $dinosaur) {
throw $this->createNotFoundException('The dinosaur you are looking for does not exists.');
try {
$dinosaur = $this->queryBus->dispatch(new GetSingleDinosaur\Query($id));
} catch (DinosaurNotFoundException $e) {
throw $this->createNotFoundException(
'The dinosaur you are looking for does not exists.'
);
}

$form = $this->createForm(DinosaurType::class, $dinosaur->toArray());
$form = $this->createForm(DinosaurType::class, $dinosaur);

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$dinosaur = $form->getData();

$input = new EditDinosaur\Input(
$id,
$dinosaur['name'],
$dinosaur['gender'],
$dinosaur['species']->getId(),
$dinosaur['age'],
$dinosaur['eyesColor']
);
$input = EditDinosaur\Input::fromReadModel($dinosaur);

try {
$this->commandBus->dispatch($input);
Expand Down
35 changes: 15 additions & 20 deletions src/Application/Controller/SpeciesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

use Application\Form\Type\SpeciesType;
use Application\MessageBus\CommandBus;
use Domain\Collection\SpeciesCollection;
use Application\MessageBus\QueryBus;
use Domain\Exception\SpeciesAlreadyExistsException;
use Domain\Exception\SpeciesNotFoundException;
use Domain\Query\GetAllSpecies;
use Domain\Query\GetSingleSpecies;
use Domain\UseCase\CreateSpecies;
use Domain\UseCase\EditSpecies;
use Domain\UseCase\RemoveSpecies;
Expand All @@ -20,17 +22,15 @@
final class SpeciesController extends AbstractController
{
public function __construct(
private SpeciesCollection $speciesCollection,
private CommandBus $commandBus
private CommandBus $commandBus,
private QueryBus $queryBus
) {
}

#[Route('/species', name: 'app_list_species')]
public function list(): Response
{
$speciesList = $this
->speciesCollection
->findAll();
$speciesList = $this->queryBus->dispatch(new GetAllSpecies\Query());

return $this->render('species-list.html.twig', [
'speciesList' => $speciesList,
Expand Down Expand Up @@ -76,26 +76,21 @@ public function create(Request $request): Response
)]
public function edit(Request $request, string $id): Response
{
$species = $this
->speciesCollection
->find($id);

if (false === $species) {
throw $this->createNotFoundException('The species you are looking for does not exists.');
try {
$species = $this->queryBus->dispatch(new GetSingleSpecies\Query($id));
} catch (SpeciesNotFoundException $e) {
throw $this->createNotFoundException(
'The species you are looking for does not exists.'
);
}

$form = $this->createForm(SpeciesType::class, $species->toArray());
$form = $this->createForm(SpeciesType::class, $species);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$rawSpecies = $form->getData();
$species = $form->getData();

$input = new EditSpecies\Input(
speciesId: $id,
name: $rawSpecies['name'],
habitats: $rawSpecies['habitats'],
feeding: $rawSpecies['feeding']
);
$input = EditSpecies\Input::fromReadModel($species);

try {
$this->commandBus->dispatch($input);
Expand Down
45 changes: 45 additions & 0 deletions src/Application/Form/DataTransformer/SpeciesReadToModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Application\Form\DataTransformer;

use Domain\Collection\SpeciesCollection;
use Domain\Exception\SpeciesNotFoundException;
use Domain\Model\Species as ModelSpecies;
use Domain\ReadModel\Species;
use Symfony\Component\Form\DataTransformerInterface;

class SpeciesReadToModel implements DataTransformerInterface
{
public function __construct(
private SpeciesCollection $speciesCollection
) {
}

public function transform(mixed $value)
{
if (!$value instanceof Species) {
return $value;
}

$speciesId = (string) $value->getId();

$species = $this->speciesCollection->find($speciesId);

if ($species === null) {
throw new SpeciesNotFoundException($speciesId);
}

return $species;
}

public function reverseTransform(mixed $value)
{
if (!$value instanceof ModelSpecies) {
return $value;
}

return new Species($value);
}
}
8 changes: 8 additions & 0 deletions src/Application/Form/Type/DinosaurType.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Application\Form\Type;

use Application\Form\DataTransformer\SpeciesReadToModel;
use Domain\Model\Species;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
Expand All @@ -13,6 +14,11 @@

final class DinosaurType extends AbstractType
{
public function __construct(
private SpeciesReadToModel $speciesReadToModel
) {
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
Expand All @@ -30,5 +36,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
->add('age', NumberType::class)
->add('eyesColor', ColorType::class)
->add('submit', SubmitType::class);

$builder->get('species')->addModelTransformer($this->speciesReadToModel);
}
}
10 changes: 10 additions & 0 deletions src/Application/MessageBus/QueryBus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Application\MessageBus;

interface QueryBus
{
public function dispatch(object $input): mixed;
}
27 changes: 27 additions & 0 deletions src/Domain/Query/GetAllDinosaurs/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetAllDinosaurs;

use Domain\Collection\DinosaursCollection;
use Domain\Model\Dinosaur as ModelDinosaur;
use Domain\ReadModel\Dinosaur;

class Handler
{
public function __construct(
private DinosaursCollection $dinosaursCollection
) {
}

public function __invoke(Query $query): array
{
$dinosaurs = $this->dinosaursCollection->search($query->search);

return array_map(
fn (ModelDinosaur $dinosaur) => new Dinosaur($dinosaur),
$dinosaurs
);
}
}
13 changes: 13 additions & 0 deletions src/Domain/Query/GetAllDinosaurs/Query.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetAllDinosaurs;

final class Query
{
public function __construct(
public readonly ?string $search = null
) {
}
}
27 changes: 27 additions & 0 deletions src/Domain/Query/GetAllSpecies/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetAllSpecies;

use Domain\Collection\SpeciesCollection;
use Domain\Model\Species as ModelSpecies;
use Domain\ReadModel\Species;

class Handler
{
public function __construct(
private SpeciesCollection $speciesCollection
) {
}

public function __invoke(Query $query): array
{
$species = $this->speciesCollection->findAll();

return array_map(
fn (ModelSpecies $species) => new Species($species),
$species
);
}
}
12 changes: 12 additions & 0 deletions src/Domain/Query/GetAllSpecies/Query.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetAllSpecies;

final class Query
{
public function __construct(
) {
}
}
28 changes: 28 additions & 0 deletions src/Domain/Query/GetSingleDinosaur/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetSingleDinosaur;

use Domain\Collection\DinosaursCollection;
use Domain\Exception\DinosaurNotFoundException;
use Domain\ReadModel\Dinosaur;

class Handler
{
public function __construct(
private DinosaursCollection $dinosaursCollection
) {
}

public function __invoke(Query $query): Dinosaur
{
$dinosaur = $this->dinosaursCollection->find($query->id);

if ($dinosaur === null) {
throw new DinosaurNotFoundException($query->id);
}

return new Dinosaur($dinosaur);
}
}
13 changes: 13 additions & 0 deletions src/Domain/Query/GetSingleDinosaur/Query.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Domain\Query\GetSingleDinosaur;

final class Query
{
public function __construct(
public readonly string $id,
) {
}
}
Loading

0 comments on commit a394968

Please sign in to comment.