Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.30% covered (success)
97.30%
36 / 37
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
HtmxCommentsRouteHandler
97.22% covered (success)
97.22%
35 / 36
83.33% covered (warning)
83.33%
5 / 6
21
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 handle
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 handleMentionsRoute
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 resolveMentionsResponse
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 handleCommentCrud
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 handleCommentModification
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Core\Bootstrap\Dispatcher\Handler;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Engine\Application\Security\PermissionContextFactory;
12use App\Core\Engine\Domain\Model\PermissionContext;
13use App\Modules\Comments\Presentation\Htmx\CommentsHtmxController;
14use App\Modules\Comments\Presentation\Htmx\MentionsHtmxController;
15use Nyholm\Psr7\Factory\Psr17Factory;
16use Psr\Http\Message\ResponseInterface;
17use Psr\Http\Message\ServerRequestInterface;
18use Psr\Http\Server\RequestHandlerInterface;
19
20final readonly class HtmxCommentsRouteHandler implements RequestHandlerInterface
21{
22    public function __construct(
23        private ?CommentsHtmxController $ctrl,
24        private ?MentionsHtmxController $mentionsCtrl,
25        private string $path,
26        private Psr17Factory $psr17,
27        private PermissionContextFactory $contextFactory
28    ) {
29    }
30
31    public function handle(ServerRequestInterface $request): ResponseInterface
32    {
33        if (str_starts_with($this->path, '/htmx/comments/mentions')) {
34            return $this->handleMentionsRoute($request);
35        }
36        if ($this->ctrl === null) {
37            return $this->psr17->createResponse(404);
38        }
39        $res = $this->handleCommentCrud($request) ?? $this->handleCommentModification($request);
40        return $res ?? $this->psr17->createResponse(404);
41    }
42
43    private function handleMentionsRoute(ServerRequestInterface $req): ResponseInterface
44    {
45        if ($this->mentionsCtrl === null) {
46            return $this->psr17->createResponse(404);
47        }
48        $ctx = $this->contextFactory->createFromRequest($req);
49        $res = $this->resolveMentionsResponse($req, $ctx);
50        return $res ?? $this->psr17->createResponse(404);
51    }
52
53    private function resolveMentionsResponse(
54        ServerRequestInterface $req,
55        PermissionContext $ctx
56    ): ?ResponseInterface {
57        if ($this->path === '/htmx/comments/mentions') {
58            return $this->mentionsCtrl->actionList($req, $ctx);
59        }
60        if ($this->path === '/htmx/comments/mentions/mark-all-read') {
61            return $this->mentionsCtrl->actionMarkAllRead($req, $ctx);
62        }
63        return preg_match('#^/htmx/comments/mentions/(\d+)/mark-read$#', $this->path, $m)
64            ? $this->mentionsCtrl->actionMarkRead($req, (int) $m[1], $ctx)
65            : null;
66    }
67
68    private function handleCommentCrud(ServerRequestInterface $req): ?ResponseInterface
69    {
70        if ($this->path === '/htmx/comments/autocomplete') {
71            return $this->ctrl->actionAutocomplete($req);
72        }
73        if (preg_match('#^/htmx/comments/([a-zA-Z0-9_-]+)/(\d+)$#', $this->path, $m)) {
74            return $req->getMethod() === 'POST'
75                ? $this->ctrl->actionCreate($req, $m[1], (int) $m[2])
76                : $this->ctrl->actionStream($req, $m[1], (int) $m[2]);
77        }
78        return null;
79    }
80
81    private function handleCommentModification(ServerRequestInterface $req): ?ResponseInterface
82    {
83        if (
84            preg_match('#^/htmx/comments/(\d+)/toggle-pin$#', $this->path, $m)
85            && $req->getMethod() === 'POST'
86        ) {
87            return $this->ctrl->actionTogglePin($req, (int) $m[1]);
88        }
89        if (
90            preg_match('#^/htmx/comments/(\d+)/toggle-verify$#', $this->path, $m)
91            && $req->getMethod() === 'POST'
92        ) {
93            return $this->ctrl->actionToggleVerify($req, (int) $m[1]);
94        }
95        return (
96            preg_match('#^/htmx/comments/(\d+)(?:/delete)?$#', $this->path, $m)
97            && in_array($req->getMethod(), ['DELETE', 'POST'], true)
98        ) ? $this->ctrl->actionDelete($req, (int) $m[1]) : null;
99    }
100}