Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
CreateBookController
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
4 / 4
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 showCreateForm
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 createBook
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
2
 renderFormResponse
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10namespace AppDemo\Library\Application\Http;
11
12use AppDemo\Library\Application\Command\CreateBookCommand;
13use AppDemo\Library\Application\Query\CreateBookQuery;
14use AppDemo\Library\Presentation\CreateBookHtmlPresenter;
15use AppDemo\Library\Presentation\Request\CreateBookRequest;
16use AppDemo\Shared\Application\AbstractHttpController;
17use AppDemo\Shared\Domain\Interface\SessionServiceInterface;
18use Phexium\Application\ControllerInterface;
19use Phexium\Plugin\CommandBus\Port\CommandBusInterface;
20use Phexium\Plugin\IdGenerator\Port\IdGeneratorInterface;
21use Phexium\Plugin\Logger\Port\LoggerInterface;
22use Phexium\Plugin\QueryBus\Port\QueryBusInterface;
23use Phexium\Presentation\ResponseBuilderInterface;
24use Psr\Http\Message\ResponseInterface;
25use Psr\Http\Message\ServerRequestInterface;
26use Twig\Environment;
27
28final readonly class CreateBookController extends AbstractHttpController implements ControllerInterface
29{
30    public function __construct(
31        private CommandBusInterface $commandBus,
32        private QueryBusInterface $queryBus,
33        private SessionServiceInterface $sessionService,
34        private CreateBookHtmlPresenter $presenter,
35        private Environment $twig,
36        private ResponseBuilderInterface $responseBuilder,
37        private IdGeneratorInterface $idGenerator,
38        private LoggerInterface $logger,
39    ) {}
40
41    public function showCreateForm(
42        ServerRequestInterface $request, // NOSONAR - Slim Framework PSR-15 contract
43        ResponseInterface $response
44    ): ResponseInterface {
45        $this->logger->info('CreateBookController: Showing create book form');
46
47        return $this->renderFormResponse($response);
48    }
49
50    public function createBook(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
51    {
52        $this->logger->info('CreateBookController: Processing request');
53
54        $requestDto = CreateBookRequest::fromHttpRequest($request);
55        $errors = $requestDto->validate();
56
57        if ($errors === []) {
58            $bookId = $this->idGenerator->generate();
59
60            $command = new CreateBookCommand(
61                $bookId,
62                $requestDto->title,
63                $requestDto->author,
64                $requestDto->isbn
65            );
66
67            $this->commandBus->dispatch($command);
68
69            $this->sessionService->addFlashMessage('success', 'Book created successfully!');
70
71            return $this->responseBuilder
72                ->withResponse($response)
73                ->withStatus(302)
74                ->withHeader('Location', '/books/'.$bookId->getValue())
75                ->build()
76            ;
77        }
78
79        $this->logger->warning('CreateBookController: Validation errors', ['errors' => $errors]);
80
81        return $this->renderFormResponse($response, $requestDto->toArray(), $errors);
82    }
83
84    private function renderFormResponse(ResponseInterface $response, array $formValues = [], array $errors = []): ResponseInterface
85    {
86        $query = new CreateBookQuery($formValues, $errors);
87        $queryResponse = $this->queryBus->dispatch($query);
88        $viewModel = $this->presenter->present($queryResponse)->getViewModel();
89
90        $html = $this->twig->render('CreateBook.html.twig', (array) $viewModel);
91
92        return $this->responseBuilder
93            ->withResponse($response)
94            ->withHtml($html)
95            ->build()
96        ;
97    }
98}