Passed
Push — main ( 8347d6...d9426f )
by Thomas
02:39
created

App::routes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Conia\Chuck;
6
7
use Closure;
8
use Conia\Chuck\Http\Factory;
9
use Conia\Chuck\MiddlewareInterface;
10
use Conia\Chuck\Registry\Entry;
11
use Conia\Chuck\Registry\Registry;
12
use Conia\Chuck\Renderer\JsonRenderer;
13
use Conia\Chuck\Renderer\Renderer;
14
use Conia\Chuck\Renderer\TextRenderer;
15
use Conia\Chuck\Routing\AddsRoutes;
16
use Conia\Chuck\Routing\Group;
17
use Conia\Chuck\Routing\Route;
18
use Conia\Chuck\Routing\RouteAdderInterface;
19
use Conia\Chuck\Routing\Router;
20
use Psr\Container\ContainerInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Log\LoggerInterface;
23
24
/** @psalm-consistent-constructor */
25
class App implements RouteAdderInterface
26
{
27
    use AddsRoutes;
28
29 31
    public function __construct(
30
        protected Config $config,
31
        protected Router $router,
32
        protected Registry $registry,
33
    ) {
34 31
        $this->initializeRegistry();
35
    }
36
37 28
    public static function create(?Config $config = null, ?ContainerInterface $container = null): static
38
    {
39 28
        if (!$config) {
40 21
            $config = new Config('chuck', debug: false);
41
        }
42
43 28
        $registry = new Registry($container);
44 28
        $router = new Router();
45
46 28
        $errorHandler = new ErrorHandler($config, $registry);
47 28
        $errorHandler->setup();
48
49 28
        return new static($config, $router, $registry);
50
    }
51
52 14
    public function router(): Router
53
    {
54 14
        return $this->router;
55
    }
56
57 2
    public function config(): Config
58
    {
59 2
        return $this->config;
60
    }
61
62 8
    public function registry(): Registry
63
    {
64 8
        return $this->registry;
65
    }
66
67
    /** @psalm-param Closure(Router $router):void $creator */
68 1
    public function routes(Closure $creator, string $cacheFile = '', bool $shouldCache = true): void
69
    {
70 1
        $this->router->routes($creator, $cacheFile, $shouldCache);
71
    }
72
73 19
    public function addRoute(Route $route): Route
74
    {
75 19
        return $this->router->addRoute($route);
76
    }
77
78 1
    public function addGroup(Group $group): void
79
    {
80 1
        $this->router->addGroup($group);
81
    }
82
83 1
    public function group(
84
        string $patternPrefix,
85
        Closure $createClosure,
86
        string $namePrefix = '',
87
    ): Group {
88 1
        $group = new Group($patternPrefix, $createClosure, $namePrefix);
89 1
        $this->router->addGroup($group);
90
91 1
        return $group;
92
    }
93
94 1
    public function staticRoute(
95
        string $prefix,
96
        string $path,
97
        string $name = '',
98
    ): void {
99 1
        $this->router->addStatic($prefix, $path, $name);
100
    }
101
102
    /**
103
     * @param MiddlewareInterface|callable(
104
     *     Request,
105
     *     callable
106
     * ):\Conia\Chuck\Response $middleware
107
     *
108
     * TODO: Why can't we import the custom psalm type MiddlewareCallable from MiddlewareInterface
109
     */
110 5
    public function middleware(MiddlewareInterface|callable ...$middleware): void
111
    {
112 5
        $this->router->middleware(...$middleware);
113
    }
114
115
    /**
116
     * @psalm-param non-empty-string $name
117
     * @psalm-param non-empty-string $class
118
     */
119 1
    public function renderer(string $name, string $class): Entry
120
    {
121 1
        return $this->registry->tag(Renderer::class)->add($name, $class)->asIs();
122
    }
123
124
    /** @param callable(mixed ...$args):LoggerInterface $callable */
125 1
    public function logger(callable $callback): void
126
    {
127 1
        $this->registry->add(LoggerInterface::class, Closure::fromCallable($callback));
128
    }
129
130
    /**
131
     * @psalm-param non-empty-string $key
132
     * @psalm-param class-string|object $value
133
     */
134 4
    public function register(string $key, object|string $value): Entry
135
    {
136 4
        return $this->registry->add($key, $value);
137
    }
138
139 10
    public function run(): Response
140
    {
141 10
        $factory = $this->registry->get(Factory::class);
142 10
        assert($factory instanceof Factory);
143 10
        $serverRequest = $factory->request();
144 10
        $request = new Request($serverRequest);
145
146 10
        $this->registry->add(ServerRequestInterface::class, $serverRequest);
147 10
        $this->registry->add($serverRequest::class, $serverRequest);
148 10
        $this->registry->add(Request::class, $request);
149
150 10
        $response = $this->router->dispatch($request, $this->registry);
151
152 10
        (new Emitter())->emit($response->psr7());
153
154 10
        return $response;
155
    }
156
157 31
    protected function initializeRegistry(): void
158
    {
159 31
        $registry = $this->registry;
160
161 31
        $registry->add(Config::class, $this->config);
162 31
        $registry->add($this->config::class, $this->config);
163 31
        $registry->add(Router::class, $this->router);
164 31
        $registry->add($this->router::class, $this->router);
165 31
        $registry->add(App::class, $this);
166
167 31
        $registry->add(Factory::class, \Conia\Chuck\Http\Nyholm::class);
168 31
        $registry->add(Response::class, function (Registry $registry): Response {
169 1
            $factory = $registry->get(Factory::class);
170 1
            assert($factory instanceof Factory);
171
172 1
            return new Response($factory->response(), $factory);
173 31
        });
174
175 31
        $registry->tag(Renderer::class)->add('text', TextRenderer::class)->asIs();
176 31
        $registry->tag(Renderer::class)->add('json', JsonRenderer::class)->asIs();
177
    }
178
}
179