Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
39 / 39
96.30% covered (success)
96.30%
26 / 27
85.71% covered (warning)
85.71%
18 / 21
93.75% covered (success)
93.75%
15 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
App
100.00% covered (success)
100.00%
39 / 39
96.30% covered (success)
96.30%
26 / 27
85.71% covered (warning)
85.71%
18 / 21
100.00% covered (success)
100.00%
16 / 16
21.17
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 load
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 router
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 factory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addRoute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 group
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 staticRoute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMiddleware
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 errorHandler
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
50.00% covered (danger)
50.00%
1 / 2
100.00% covered (success)
100.00%
1 / 1
2.50
 middleware
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 logger
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 container
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 register
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 initializeContainer
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 run
100.00% covered (success)
100.00%
12 / 12
85.71% covered (warning)
85.71%
6 / 7
50.00% covered (danger)
50.00%
2 / 4
100.00% covered (success)
100.00%
1 / 1
4.12
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Core;
6
7use Celemas\Container\Container;
8use Celemas\Container\Entry;
9use Celemas\Core\Error\Handler as ErrorHandler;
10use Celemas\Core\Factory\Discovery;
11use Celemas\Core\Factory\Factory;
12use Celemas\Router\AddsBeforeAfter;
13use Celemas\Router\AddsRoutes;
14use Celemas\Router\Dispatcher;
15use Celemas\Router\Route;
16use Celemas\Router\RouteAdder;
17use Celemas\Router\Router;
18use Celemas\Router\RoutingHandler;
19use Closure;
20use Override;
21use Psr\Container\ContainerInterface as PsrContainer;
22use Psr\Http\Message\ResponseInterface as Response;
23use Psr\Http\Message\ServerRequestInterface as Request;
24use Psr\Http\Server\MiddlewareInterface as Middleware;
25use Psr\Log\LoggerInterface as Logger;
26
27/** @api */
28class App implements RouteAdder
29{
30    use AddsRoutes;
31    use AddsBeforeAfter;
32
33    protected readonly Dispatcher $dispatcher;
34    protected ?ErrorHandler $errorHandler = null;
35
36    public function __construct(
37        protected readonly Factory $factory,
38        protected readonly Router $router,
39        protected readonly Container $container,
40    ) {
41        $this->dispatcher = new Dispatcher();
42        $this->initializeContainer();
43    }
44
45    public function load(Plugin $plugin): void
46    {
47        $plugin->load($this);
48    }
49
50    public static function create(?PsrContainer $container = null): self
51    {
52        return new self(
53            Discovery::create(),
54            new Router(),
55            new Container(container: $container),
56        );
57    }
58
59    public function router(): Router
60    {
61        return $this->router;
62    }
63
64    public function factory(): Factory
65    {
66        return $this->factory;
67    }
68
69    #[Override]
70    public function addRoute(Route $route): Route
71    {
72        return $this->router->addRoute($route);
73    }
74
75    #[Override]
76    public function group(
77        string $patternPrefix,
78        Closure $createClosure,
79        string $namePrefix = '',
80    ): void {
81        $this->router->group($patternPrefix, $createClosure, $namePrefix);
82    }
83
84    public function staticRoute(
85        string $prefix,
86        string $path,
87        string $name = '',
88    ): void {
89        $this->router->addStatic($prefix, $path, $name);
90    }
91
92    public function getMiddleware(): array
93    {
94        return $this->dispatcher->getMiddleware();
95    }
96
97    public function errorHandler(?ErrorHandler $handler = null): ?ErrorHandler
98    {
99        if ($handler !== null) {
100            $this->errorHandler = $handler;
101        }
102
103        return $this->errorHandler;
104    }
105
106    public function middleware(Middleware ...$middleware): void
107    {
108        $this->dispatcher->middleware(...$middleware);
109    }
110
111    public function logger(Logger|callable $logger): void
112    {
113        if ($logger instanceof Logger) {
114            $this->container->add(Logger::class, $logger);
115        } else {
116            $this->container->add(Logger::class, Closure::fromCallable($logger));
117        }
118    }
119
120    public function container(): Container
121    {
122        return $this->container;
123    }
124
125    /**
126     * @param non-empty-string $key
127     * @param class-string|object $value
128     */
129    public function register(string $key, object|string $value): Entry
130    {
131        return $this->container->add($key, $value);
132    }
133
134    public function initializeContainer(): void
135    {
136        $this->container->add(Router::class, $this->router);
137        $this->container->add($this->router::class, $this->router);
138
139        $this->container->add(Factory::class, $this->factory);
140        $this->container->add($this->factory::class, $this->factory);
141    }
142
143    public function run(?Request $request = null): Response|false
144    {
145        $request ??= $this->factory->serverRequest();
146        $this->dispatcher->setBeforeHandlers($this->beforeHandlers);
147        $this->dispatcher->setAfterHandlers($this->afterHandlers);
148        $handler = new RoutingHandler(
149            $this->router,
150            $this->dispatcher,
151            $this->container,
152        );
153        $response = $this->errorHandler
154            ? $this->errorHandler->process($request, $handler)
155            : $handler->handle($request);
156
157        return new Emitter()->emit($response) ? $response : false;
158    }
159}

Branches

Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

App->__construct
37        protected readonly Factory $factory,
38        protected readonly Router $router,
39        protected readonly Container $container,
40    ) {
41        $this->dispatcher = new Dispatcher();
42        $this->initializeContainer();
43    }
App->addRoute
70    public function addRoute(Route $route): Route
71    {
72        return $this->router->addRoute($route);
73    }
App->container
122        return $this->container;
123    }
App->create
50    public static function create(?PsrContainer $container = null): self
51    {
52        return new self(
53            Discovery::create(),
54            new Router(),
55            new Container(container: $container),
56        );
57    }
App->errorHandler
97    public function errorHandler(?ErrorHandler $handler = null): ?ErrorHandler
98    {
99        if ($handler !== null) {
100            $this->errorHandler = $handler;
101        }
102
103        return $this->errorHandler;
103        return $this->errorHandler;
104    }
App->factory
66        return $this->factory;
67    }
App->getMiddleware
94        return $this->dispatcher->getMiddleware();
95    }
App->group
77        string $patternPrefix,
78        Closure $createClosure,
79        string $namePrefix = '',
80    ): void {
81        $this->router->group($patternPrefix, $createClosure, $namePrefix);
82    }
App->initializeContainer
136        $this->container->add(Router::class, $this->router);
137        $this->container->add($this->router::class, $this->router);
138
139        $this->container->add(Factory::class, $this->factory);
140        $this->container->add($this->factory::class, $this->factory);
141    }
App->load
45    public function load(Plugin $plugin): void
46    {
47        $plugin->load($this);
48    }
App->logger
111    public function logger(Logger|callable $logger): void
112    {
113        if ($logger instanceof Logger) {
113        if ($logger instanceof Logger) {
114            $this->container->add(Logger::class, $logger);
116            $this->container->add(Logger::class, Closure::fromCallable($logger));
117        }
118    }
118    }
App->middleware
106    public function middleware(Middleware ...$middleware): void
107    {
108        $this->dispatcher->middleware(...$middleware);
109    }
App->register
129    public function register(string $key, object|string $value): Entry
130    {
131        return $this->container->add($key, $value);
132    }
App->router
61        return $this->router;
62    }
App->run
143    public function run(?Request $request = null): Response|false
144    {
145        $request ??= $this->factory->serverRequest();
146        $this->dispatcher->setBeforeHandlers($this->beforeHandlers);
147        $this->dispatcher->setAfterHandlers($this->afterHandlers);
148        $handler = new RoutingHandler(
149            $this->router,
150            $this->dispatcher,
151            $this->container,
152        );
153        $response = $this->errorHandler
154            ? $this->errorHandler->process($request, $handler)
153        $response = $this->errorHandler
154            ? $this->errorHandler->process($request, $handler)
155            : $handler->handle($request);
153        $response = $this->errorHandler
154            ? $this->errorHandler->process($request, $handler)
155            : $handler->handle($request);
156
157        return new Emitter()->emit($response) ? $response : false;
157        return new Emitter()->emit($response) ? $response : false;
157        return new Emitter()->emit($response) ? $response : false;
157        return new Emitter()->emit($response) ? $response : false;
158    }
App->staticRoute
85        string $prefix,
86        string $path,
87        string $name = '',
88    ): void {
89        $this->router->addStatic($prefix, $path, $name);
90    }