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

IlyasDeckers / ody-core / 13532154862

25 Feb 2025 10:24PM UTC coverage: 30.374% (+1.7%) from 28.706%
13532154862

push

github

web-flow
Update php.yml

544 of 1791 relevant lines covered (30.37%)

9.13 hits per line

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

66.29
/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

92
        $app = self::create();
×
93
        $app->addBodyParsingMiddleware();
×
94
        $app->addRoutingMiddleware();
×
95
        $app->addErrorMiddleware($debug, $debug, $debug);
×
96
        Facade::setFacadeApplication($app);
×
97

98
        /**
99
         * Register routes
100
         */
101
        require base_path('App/routes.php');
×
102

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

111
        return $app;
×
112
    }
113

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

119
        $callableResolver = new InvokerCallableResolver($container);
×
120

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

124
        $container->set(Kernel::class, $app);
×
125

126
        $controllerInvoker = static::createControllerInvoker($container);
×
127
        $app->getRouteCollector()->setDefaultInvocationStrategy($controllerInvoker);
×
128

129
        return $app;
×
130
    }
131

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

144
        $invoker = new Invoker(new ResolverChain($resolvers), $container);
×
145

146
        return new ControllerInvoker($invoker);
×
147
    }
148

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

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

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

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

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

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

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

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

260
        $response = $this->handle($request);
2✔
261
        $responseEmitter = new ResponseEmitter();
2✔
262
        $responseEmitter->emit($response);
2✔
263
    }
264

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

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

291
        return $response;
41✔
292
    }
293
}
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