• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IlyasDeckers / ody-core / 13568825142

27 Feb 2025 02:33PM UTC coverage: 28.348% (-0.07%) from 28.422%
13568825142

push

github

IlyasDeckers
Load services on boot and add a cache facade

0 of 6 new or added lines in 2 files covered. (0.0%)

544 of 1919 relevant lines covered (28.35%)

8.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.13
/src/Kernel.php
1
<?php
2
declare(strict_types=1);
3
namespace Ody\Core;
4

5
use DI\Container;
6
use Invoker\CallableResolver as InvokerCallableResolver;
7
use Invoker\Invoker;
8
use Invoker\ParameterResolver\AssociativeArrayResolver;
9
use Invoker\ParameterResolver\Container\TypeHintContainerResolver;
10
use Invoker\ParameterResolver\DefaultValueResolver;
11
use Invoker\ParameterResolver\ResolverChain;
12
use Ody\Core\DI\ControllerInvoker;
13
use Ody\Core\Facades\Facade;
14
use Ody\Core\Factory\KernelFactory;
15
use Ody\Core\Factory\ServerRequestCreatorFactory;
16
use Ody\Core\Interfaces\CallableResolverInterface;
17
use Ody\Core\Interfaces\MiddlewareDispatcherInterface;
18
use Ody\Core\Interfaces\RouteCollectorInterface;
19
use Ody\Core\Interfaces\RouteResolverInterface;
20
use Ody\Core\Middleware\BodyParsingMiddleware;
21
use Ody\Core\Middleware\ErrorMiddleware;
22
use Ody\Core\Middleware\RoutingMiddleware;
23
use Ody\Core\Routing\RouteCollectorProxy;
24
use Ody\Core\Routing\RouteResolver;
25
use Ody\Core\Routing\RouteRunner;
26
use Psr\Container\ContainerInterface;
27
use Psr\Http\Message\ResponseFactoryInterface;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Psr\Http\Server\MiddlewareInterface;
31
use Psr\Http\Server\RequestHandlerInterface;
32
use Psr\Log\LoggerInterface;
33

34
/**
35
 * @api
36
 * @template TContainerInterface of (ContainerInterface|null)
37
 * @template-extends RouteCollectorProxy<TContainerInterface>
38
 */
39
class Kernel extends RouteCollectorProxy implements RequestHandlerInterface
40
{
41
    /**
42
     * Current version
43
     *
44
     * @var string
45
     */
46
    public const VERSION = '0.0.1';
47

48
    protected RouteResolverInterface $routeResolver;
49

50
    protected MiddlewareDispatcherInterface $middlewareDispatcher;
51

52
    /**
53
     * @param ResponseFactoryInterface $responseFactory
54
     * @param ContainerInterface|null $container
55
     * @param CallableResolverInterface|null $callableResolver
56
     * @param RouteCollectorInterface|null $routeCollector
57
     * @param RouteResolverInterface|null $routeResolver
58
     * @param MiddlewareDispatcherInterface|null $middlewareDispatcher
59
     */
60
    public function __construct(
99✔
61
        ResponseFactoryInterface $responseFactory,
62
        ?ContainerInterface $container = null,
63
        ?CallableResolverInterface $callableResolver = null,
64
        ?RouteCollectorInterface $routeCollector = null,
65
        ?RouteResolverInterface $routeResolver = null,
66
        ?MiddlewareDispatcherInterface $middlewareDispatcher = null
67
    ) {
68
        parent::__construct(
99✔
69
            $responseFactory,
99✔
70
            $callableResolver ?? new CallableResolver($container),
99✔
71
            $container,
99✔
72
            $routeCollector
99✔
73
        );
99✔
74

75
        $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
99✔
76
        $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);
99✔
77

78
        if (!$middlewareDispatcher) {
99✔
79
            $middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
98✔
80
        } else {
81
            $middlewareDispatcher->seedMiddlewareStack($routeRunner);
1✔
82
        }
83

84
        $this->middlewareDispatcher = $middlewareDispatcher;
99✔
85
    }
86

87
    public static function init(): Kernel
×
88
    {
89
        Env::load(base_path());
×
90
        $debug = (bool) config('app.debug');
×
91

NEW
92
        $container = new Container([
×
NEW
93
            'di.service' => [...config('server.services', [])],
×
NEW
94
        ]);
×
NEW
95
        $app = self::create($container);
×
96
        $app->addBodyParsingMiddleware();
×
97
        $app->addRoutingMiddleware();
×
98
        $app->addErrorMiddleware($debug, $debug, $debug);
×
99
        Facade::setFacadeApplication($app);
×
100

101
        /**
102
         * Register routes
103
         */
104
        require base_path('App/routes.php');
×
105

106
        /**
107
         * Register DB
108
         */
109
        if (class_exists('Ody\DB\Eloquent')) {
×
110
            $dbConfig = config('database.environments')[$_ENV['APP_ENV']];
×
111
            \Ody\DB\Eloquent::boot($dbConfig);
×
112
        }
113

114
        return $app;
×
115
    }
116

117
    /** Bridge DI */
118
    public static function create(?ContainerInterface $container = null): Kernel
×
119
    {
120
        $container = $container ?: new Container;
×
121

122
        $callableResolver = new InvokerCallableResolver($container);
×
123

124
        $container->set(CallableResolverInterface::class, new \Ody\Core\DI\CallableResolver($callableResolver));
×
125
        $app = KernelFactory::createFromContainer($container);
×
126

127
        $container->set(Kernel::class, $app);
×
128

129
        $controllerInvoker = static::createControllerInvoker($container);
×
130
        $app->getRouteCollector()->setDefaultInvocationStrategy($controllerInvoker);
×
131

132
        return $app;
×
133
    }
134

135
    /** Bridge DI */
136
    private static function createControllerInvoker(ContainerInterface $container): ControllerInvoker
×
137
    {
138
        $resolvers = [
×
139
            // Inject parameters by name first
140
            new AssociativeArrayResolver,
×
141
            // Then inject services by type-hints for those that weren't resolved
142
            new TypeHintContainerResolver($container),
×
143
            // Then fall back on parameters default values for optional route parameters
144
            new DefaultValueResolver,
×
145
        ];
×
146

147
        $invoker = new Invoker(new ResolverChain($resolvers), $container);
×
148

149
        return new ControllerInvoker($invoker);
×
150
    }
151

152
    /**
153
     * @return RouteResolverInterface
154
     */
155
    public function getRouteResolver(): RouteResolverInterface
1✔
156
    {
157
        return $this->routeResolver;
1✔
158
    }
159

160
    /**
161
     * @return MiddlewareDispatcherInterface
162
     */
163
    public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface
1✔
164
    {
165
        return $this->middlewareDispatcher;
1✔
166
    }
167

168
    /**
169
     * @param MiddlewareInterface|string|callable $middleware
170
     * @return Kernel<TContainerInterface>
171
     */
172
    public function add($middleware): self
6✔
173
    {
174
        $this->middlewareDispatcher->add($middleware);
6✔
175
        return $this;
5✔
176
    }
177

178
    /**
179
     * @param MiddlewareInterface $middleware
180
     * @return Kernel<TContainerInterface>
181
     */
182
    public function addMiddleware(MiddlewareInterface $middleware): self
1✔
183
    {
184
        $this->middlewareDispatcher->addMiddleware($middleware);
1✔
185
        return $this;
1✔
186
    }
187

188
    /**
189
     * Add the built-in routing middleware to the app middleware stack
190
     *
191
     * This method can be used to control middleware order and is not required for default routing operation.
192
     *
193
     * @return RoutingMiddleware
194
     */
195
    public function addRoutingMiddleware(): RoutingMiddleware
1✔
196
    {
197
        $routingMiddleware = new RoutingMiddleware(
1✔
198
            $this->getRouteResolver(),
1✔
199
            $this->getRouteCollector()->getRouteParser()
1✔
200
        );
1✔
201
        $this->add($routingMiddleware);
1✔
202
        return $routingMiddleware;
1✔
203
    }
204

205
    /**
206
     * Add the built-in error middleware to the app middleware stack
207
     *
208
     * @param bool                 $displayErrorDetails
209
     * @param bool                 $logErrors
210
     * @param bool                 $logErrorDetails
211
     * @param LoggerInterface|null $logger
212
     *
213
     * @return ErrorMiddleware
214
     */
215
    public function addErrorMiddleware(
1✔
216
        bool $displayErrorDetails,
217
        bool $logErrors,
218
        bool $logErrorDetails,
219
        ?LoggerInterface $logger = null
220
    ): ErrorMiddleware {
221
        $errorMiddleware = new ErrorMiddleware(
1✔
222
            $this->getCallableResolver(),
1✔
223
            $this->getResponseFactory(),
1✔
224
            $displayErrorDetails,
1✔
225
            $logErrors,
1✔
226
            $logErrorDetails,
1✔
227
            $logger
1✔
228
        );
1✔
229
        $this->add($errorMiddleware);
1✔
230
        return $errorMiddleware;
1✔
231
    }
232

233
    /**
234
     * Add the body parsing middleware to the app middleware stack
235
     *
236
     * @param callable[] $bodyParsers
237
     *
238
     * @return BodyParsingMiddleware
239
     */
240
    public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware
1✔
241
    {
242
        $bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers);
1✔
243
        $this->add($bodyParsingMiddleware);
1✔
244
        return $bodyParsingMiddleware;
1✔
245
    }
246

247
    /**
248
     * Run application
249
     *
250
     * This method traverses the application middleware stack and then sends the
251
     * resultant Response object to the HTTP client.
252
     *
253
     * @param ServerRequestInterface|null $request
254
     * @return void
255
     */
256
    public function run(?ServerRequestInterface $request = null): void
2✔
257
    {
258
        if (!$request) {
2✔
259
            $serverRequestCreator = ServerRequestCreatorFactory::create();
1✔
260
            $request = $serverRequestCreator->createServerRequestFromGlobals();
1✔
261
        }
262

263
        $response = $this->handle($request);
2✔
264
        $responseEmitter = new ResponseEmitter();
2✔
265
        $responseEmitter->emit($response);
2✔
266
    }
267

268
    /**
269
     * Handle a request
270
     *
271
     * This method traverses the application middleware stack and then returns the
272
     * resultant Response object.
273
     *
274
     * @param ServerRequestInterface $request
275
     * @return ResponseInterface
276
     */
277
    public function handle(ServerRequestInterface $request): ResponseInterface
45✔
278
    {
279
        $response = $this->middlewareDispatcher->handle($request);
45✔
280

281
        /**
282
         * This is to be in compliance with RFC 2616, Section 9.
283
         * If the incoming request method is HEAD, we need to ensure that the response body
284
         * is empty as the request may fall back on a GET route handler due to FastRoute's
285
         * routing logic which could potentially append content to the response body
286
         * https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4
287
         */
288
        $method = strtoupper($request->getMethod());
42✔
289
        if ($method === 'HEAD') {
42✔
290
            $emptyBody = $this->responseFactory->createResponse()->getBody();
1✔
291
            return $response->withBody($emptyBody);
1✔
292
        }
293

294
        return $response;
41✔
295
    }
296
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc