Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
UpdateBookController
100.00% covered (success)
100.00%
34 / 34
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
 showEditForm
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 updateBook
100.00% covered (success)
100.00%
22 / 22
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\UpdateBookCommand;
13use AppDemo\Library\Application\Query\UpdateBookQuery;
14use AppDemo\Library\Presentation\Request\UpdateBookRequest;
15use AppDemo\Library\Presentation\UpdateBookHtmlPresenter;
16use AppDemo\Shared\Application\AbstractHttpController;
17use AppDemo\Shared\Domain\Interface\SessionServiceInterface;
18use Phexium\Application\ControllerInterface;
19use Phexium\Domain\Id\IdInterface;
20use Phexium\Plugin\CommandBus\Port\CommandBusInterface;
21use Phexium\Plugin\IdGenerator\Port\IdGeneratorInterface;
22use Phexium\Plugin\Logger\Port\LoggerInterface;
23use Phexium\Plugin\QueryBus\Port\QueryBusInterface;
24use Phexium\Presentation\ResponseBuilderInterface;
25use Psr\Http\Message\ResponseInterface;
26use Psr\Http\Message\ServerRequestInterface;
27use Twig\Environment;
28
29final readonly class UpdateBookController extends AbstractHttpController implements ControllerInterface
30{
31    public function __construct(
32        private CommandBusInterface $commandBus,
33        private QueryBusInterface $queryBus,
34        private SessionServiceInterface $sessionService,
35        private UpdateBookHtmlPresenter $presenter,
36        private Environment $twig,
37        private ResponseBuilderInterface $responseBuilder,
38        private IdGeneratorInterface $idGenerator,
39        private LoggerInterface $logger,
40    ) {}
41
42    public function showEditForm(
43        ServerRequestInterface $request, // NOSONAR - Slim Framework PSR-15 contract
44        ResponseInterface $response,
45        array $args = []
46    ): ResponseInterface {
47        $bookId = $this->idGenerator->from($args['id']);
48
49        return $this->renderFormResponse($response, $bookId);
50    }
51
52    public function updateBook(ServerRequestInterface $request, ResponseInterface $response, array $args = []): ResponseInterface
53    {
54        $this->logger->info('UpdateBookController: Processing request');
55
56        $bookId = $this->idGenerator->from($args['id']);
57
58        $requestDto = UpdateBookRequest::fromHttpRequest($request);
59        $errors = $requestDto->validate();
60
61        if ($errors === []) {
62            $command = new UpdateBookCommand(
63                $bookId,
64                $requestDto->title,
65                $requestDto->author,
66                $requestDto->isbn,
67                $requestDto->status
68            );
69
70            $this->commandBus->dispatch($command);
71
72            $this->sessionService->addFlashMessage('success', 'Book updated successfully!');
73
74            return $this->responseBuilder
75                ->withResponse($response)
76                ->withStatus(302)
77                ->withHeader('Location', '/books/'.$bookId->getValue())
78                ->build()
79            ;
80        }
81
82        $this->logger->warning('UpdateBookController: Validation errors', ['errors' => $errors]);
83
84        return $this->renderFormResponse($response, $bookId, $requestDto->toArray(), $errors);
85    }
86
87    private function renderFormResponse(ResponseInterface $response, IdInterface $bookId, array $formValues = [], array $errors = []): ResponseInterface
88    {
89        $query = new UpdateBookQuery($bookId, $formValues, $errors);
90        $queryResponse = $this->queryBus->dispatch($query);
91        $viewModel = $this->presenter->present($queryResponse)->getViewModel();
92
93        $html = $this->twig->render('UpdateBook.html.twig', (array) $viewModel);
94
95        return $this->responseBuilder
96            ->withResponse($response)
97            ->withHtml($html)
98            ->build()
99        ;
100    }
101}