Kernel   A
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 430
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 88
dl 0
loc 430
rs 9.2
c 4
b 0
f 1
wmc 40

23 Methods

Rating   Name   Duplication   Size   Complexity  
A terminate_middleware() 0 18 5
A terminate() 0 5 1
A prepend_to_middleware_priority() 0 9 2
A bootstrappers() 0 3 1
A bootstrap() 0 2 1
A append_middleware_to_group() 0 13 3
A get_route_middleware() 0 3 1
A handle() 0 15 2
A report_exception() 0 3 1
A append_to_middleware_priority() 0 9 2
A prepend_middleware() 0 7 2
A get_application() 0 3 1
A sync_middleware_to_router() 0 10 3
A push_middleware() 0 7 2
A has_middleware() 0 3 1
A parse_middleware() 0 9 2
A prepend_middleware_to_group() 0 13 3
A __construct() 0 6 1
A send_request_through_router() 0 12 1
A dispatch_to_router() 0 6 1
A gather_route_middleware() 0 8 2
A render_exception() 0 3 1
A get_middleware_groups() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like Kernel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Kernel, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * The file handle the request.
4
 *
5
 * @link       https://github.com/maab16
6
 * @since      1.0.0
7
 */
8
9
namespace WPB\Http;
10
11
use Illuminate\Contracts\Container\Container;
12
use Illuminate\Contracts\Debug\ExceptionHandler;
13
use Illuminate\Routing\Pipeline;
14
use Illuminate\Routing\Router;
15
use Illuminate\Support\Facades\Facade;
16
use InvalidArgumentException;
17
use Throwable;
18
use WPB\Contracts\Http\Kernel as KernelContract;
19
use WPB\Http\Events\RequestHandled;
20
21
/**
22
 * The request handler.
23
 *
24
 * @since      1.0.0
25
 *
26
 * @author     Md Abu Ahsan basir <[email protected]>
27
 */
28
class Kernel implements KernelContract
29
{
30
    /**
31
     * The application implementation.
32
     *
33
     * @var \Illuminate\Contracts\Foundation\Application
34
     */
35
    protected $app;
36
37
    /**
38
     * The router instance.
39
     *
40
     * @var \Illuminate\Routing\Router
41
     */
42
    protected $router;
43
44
    /**
45
     * The bootstrap classes for the application.
46
     *
47
     * @var array
48
     */
49
    protected $bootstrappers = [];
50
51
    /**
52
     * The application's middleware stack.
53
     *
54
     * @var array
55
     */
56
    protected $middleware = [];
57
58
    /**
59
     * The application's route middleware groups.
60
     *
61
     * @var array
62
     */
63
    protected $middleware_groups = [];
64
65
    /**
66
     * The application's route middleware.
67
     *
68
     * @var array
69
     */
70
    protected $route_middleware = [];
71
72
    /**
73
     * The priority-sorted list of middleware.
74
     *
75
     * Forces non-global middleware to always be in the given order.
76
     *
77
     * @var array
78
     */
79
    protected $middleware_priority = [];
80
81
    /**
82
     * Create a new HTTP kernel instance.
83
     *
84
     * @param \Illuminate\Contracts\Container\Container $app    The app.
85
     * @param \Illuminate\Routing\Router                $router The app router.
86
     *
87
     * @return void
88
     */
89
    public function __construct(Container $app, Router $router)
90
    {
91
        $this->app = $app;
0 ignored issues
show
Documentation Bug introduced by
$app is of type Illuminate\Contracts\Container\Container, but the property $app was declared to be of type Illuminate\Contracts\Foundation\Application. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
92
        $this->router = $router;
93
94
        $this->sync_middleware_to_router();
95
    }
96
97
    /**
98
     * Handle an incoming HTTP request.
99
     *
100
     * @param \Illuminate\Http\Request $request The app http request.
101
     *
102
     * @throws \Exception The throwable exception.
103
     *
104
     * @return \Illuminate\Http\Response
105
     */
106
    public function handle($request)
107
    {
108
        try {
109
            $request->enableHttpMethodParameterOverride();
110
            $response = $this->send_request_through_router($request);
111
        } catch (Throwable $e) {
112
            $this->report_exception($e);
113
            $response = $this->render_exception($request, $e);
114
        }
115
116
        $this->app['events']->dispatch(
117
            new RequestHandled($request, $response)
118
        );
119
120
        return $response;
121
    }
122
123
    /**
124
     * Send the given request through the middleware / router.
125
     *
126
     * @param \Illuminate\Http\Request $request The app http request.
127
     *
128
     * @return \Illuminate\Http\Response
129
     */
130
    protected function send_request_through_router($request)
131
    {
132
        $this->app->instance('request', $request);
133
134
        Facade::clearResolvedInstance('request');
135
136
        $this->bootstrap();
137
138
        return ( new Pipeline($this->app) )
139
                    ->send($request)
140
                    ->through($this->middleware)
141
                    ->then($this->dispatch_to_router());
142
    }
143
144
    /**
145
     * Bootstrap the application for HTTP requests.
146
     *
147
     * @return void
148
     */
149
    public function bootstrap()
150
    {
151
    }
152
153
    /**
154
     * Get the route dispatcher callback.
155
     *
156
     * @return \Closure
157
     */
158
    protected function dispatch_to_router()
159
    {
160
        return function ($request) {
161
            $this->app->instance('request', $request);
162
163
            return $this->router->dispatch($request);
164
        };
165
    }
166
167
    /**
168
     * Call the terminate method on any terminable middleware.
169
     *
170
     * @param \Illuminate\Http\Request  $request  The app http request.
171
     * @param \Illuminate\Http\Response $response The app http response.
172
     *
173
     * @return void
174
     */
175
    public function terminate($request, $response)
176
    {
177
        $this->terminate_middleware($request, $response);
178
179
        $this->app->terminate();
180
    }
181
182
    /**
183
     * Call the terminate method on any terminable middleware.
184
     *
185
     * @param \Illuminate\Http\Request  $request  The app http request.
186
     * @param \Illuminate\Http\Response $response The app http response.
187
     *
188
     * @return void
189
     */
190
    protected function terminate_middleware($request, $response)
191
    {
192
        $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge(
193
            $this->gather_route_middleware($request),
194
            $this->middleware
195
        );
196
197
        foreach ($middlewares as $middleware) {
198
            if (!is_string($middleware)) {
199
                continue;
200
            }
201
202
            list($name) = $this->parse_middleware($middleware);
203
204
            $instance = $this->app->make($name);
205
206
            if (method_exists($instance, 'terminate')) {
207
                $instance->terminate($request, $response);
208
            }
209
        }
210
    }
211
212
    /**
213
     * Gather the route middleware for the given request.
214
     *
215
     * @param \Illuminate\Http\Request $request The app http request.
216
     *
217
     * @return array
218
     */
219
    protected function gather_route_middleware($request)
220
    {
221
        $route = $request->route();
222
        if ($route) {
223
            return $this->router->gatherRouteMiddleware($route);
0 ignored issues
show
Bug introduced by
It seems like $route can also be of type string; however, parameter $route of Illuminate\Routing\Router::gatherRouteMiddleware() does only seem to accept Illuminate\Routing\Route, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

223
            return $this->router->gatherRouteMiddleware(/** @scrutinizer ignore-type */ $route);
Loading history...
224
        }
225
226
        return [];
227
    }
228
229
    /**
230
     * Parse a middleware string to get the name and parameters.
231
     *
232
     * @param string $middleware The app middleware.
233
     *
234
     * @return array
235
     */
236
    protected function parse_middleware($middleware)
237
    {
238
        list($name, $parameters) = array_pad(explode(':', $middleware, 2), 2, []);
239
240
        if (is_string($parameters)) {
241
            $parameters = explode(',', $parameters);
242
        }
243
244
        return [$name, $parameters];
245
    }
246
247
    /**
248
     * Determine if the kernel has a given middleware.
249
     *
250
     * @param string $middleware The app middleware.
251
     *
252
     * @return bool
253
     */
254
    public function has_middleware($middleware)
255
    {
256
        return in_array($middleware, $this->middleware);
257
    }
258
259
    /**
260
     * Add a new middleware to beginning of the stack if it does not already exist.
261
     *
262
     * @param string $middleware The app middleware.
263
     *
264
     * @return $this
265
     */
266
    public function prepend_middleware($middleware)
267
    {
268
        if (array_search($middleware, $this->middleware) === false) {
269
            array_unshift($this->middleware, $middleware);
270
        }
271
272
        return $this;
273
    }
274
275
    /**
276
     * Add a new middleware to end of the stack if it does not already exist.
277
     *
278
     * @param string $middleware The app middleware.
279
     *
280
     * @return $this
281
     */
282
    public function push_middleware($middleware)
283
    {
284
        if (array_search($middleware, $this->middleware) === false) {
285
            $this->middleware[] = $middleware;
286
        }
287
288
        return $this;
289
    }
290
291
    /**
292
     * Prepend the given middleware to the given middleware group.
293
     *
294
     * @param string $group      The app group.
295
     * @param string $middleware The app middleware.
296
     *
297
     * @throws \InvalidArgumentException The invalid argument exception.
298
     *
299
     * @return $this
300
     */
301
    public function prepend_middleware_to_group($group, $middleware)
302
    {
303
        if (!isset($this->middleware_groups[$group])) {
304
            throw new InvalidArgumentException("The [{$group}] middleware group has not been defined.");
305
        }
306
307
        if (array_search($middleware, $this->middleware_groups[$group]) === false) {
308
            array_unshift($this->middleware_groups[$group], $middleware);
309
        }
310
311
        $this->sync_middleware_to_router();
312
313
        return $this;
314
    }
315
316
    /**
317
     * Append the given middleware to the given middleware group.
318
     *
319
     * @param string $group      The app group.
320
     * @param string $middleware The app middleware.
321
     *
322
     * @throws \InvalidArgumentException The invalid argument exception.
323
     *
324
     * @return $this
325
     */
326
    public function append_middleware_to_group($group, $middleware)
327
    {
328
        if (!isset($this->middleware_groups[$group])) {
329
            throw new InvalidArgumentException("The [{$group}] middleware group has not been defined.");
330
        }
331
332
        if (array_search($middleware, $this->middleware_groups[$group]) === false) {
333
            $this->middleware_groups[$group][] = $middleware;
334
        }
335
336
        $this->sync_middleware_to_router();
337
338
        return $this;
339
    }
340
341
    /**
342
     * Prepend the given middleware to the middleware priority list.
343
     *
344
     * @param string $middleware The app middleware.
345
     *
346
     * @return $this
347
     */
348
    public function prepend_to_middleware_priority($middleware)
349
    {
350
        if (!in_array($middleware, $this->middleware_priority)) {
351
            array_unshift($this->middleware_priority, $middleware);
352
        }
353
354
        $this->sync_middleware_to_router();
355
356
        return $this;
357
    }
358
359
    /**
360
     * Append the given middleware to the middleware priority list.
361
     *
362
     * @param string $middleware The app middleware.
363
     *
364
     * @return $this
365
     */
366
    public function append_to_middleware_priority($middleware)
367
    {
368
        if (!in_array($middleware, $this->middleware_priority)) {
369
            $this->middleware_priority[] = $middleware;
370
        }
371
372
        $this->sync_middleware_to_router();
373
374
        return $this;
375
    }
376
377
    /**
378
     * Sync the current state of the middleware to the router.
379
     *
380
     * @return void
381
     */
382
    protected function sync_middleware_to_router()
383
    {
384
        $this->router->middlewarePriority = $this->middleware_priority;
385
386
        foreach ($this->middleware_groups as $key => $middleware) {
387
            $this->router->middlewareGroup($key, $middleware);
388
        }
389
390
        foreach ($this->route_middleware as $key => $middleware) {
391
            $this->router->aliasMiddleware($key, $middleware);
392
        }
393
    }
394
395
    /**
396
     * Get the bootstrap classes for the application.
397
     *
398
     * @return array
399
     */
400
    protected function bootstrappers()
401
    {
402
        return $this->bootstrappers;
403
    }
404
405
    /**
406
     * Report the exception to the exception handler.
407
     *
408
     * @param \Throwable $e The throwable exception.
409
     *
410
     * @return void
411
     */
412
    protected function report_exception(Throwable $e)
413
    {
414
        $this->app[ExceptionHandler::class]->report($e);
415
    }
416
417
    /**
418
     * Render the exception to a response.
419
     *
420
     * @param \Illuminate\Http\Request $request The app http request.
421
     * @param \Throwable               $e       The throwable exception.
422
     *
423
     * @return \Symfony\Component\HttpFoundation\Response
424
     */
425
    protected function render_exception($request, Throwable $e)
426
    {
427
        return $this->app[ExceptionHandler::class]->render($request, $e);
428
    }
429
430
    /**
431
     * Get the application's route middleware groups.
432
     *
433
     * @return array
434
     */
435
    public function get_middleware_groups()
436
    {
437
        return $this->middleware_groups;
438
    }
439
440
    /**
441
     * Get the application's route middleware.
442
     *
443
     * @return array
444
     */
445
    public function get_route_middleware()
446
    {
447
        return $this->route_middleware;
448
    }
449
450
    /**
451
     * Get the Laravel application instance.
452
     *
453
     * @return \Illuminate\Contracts\Foundation\Application
454
     */
455
    public function get_application()
456
    {
457
        return $this->app;
458
    }
459
}
460