Passed
Push — master ( 877150...53e563 )
by Atanas
07:02
created

HttpKernel::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 18
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * @package   WPEmerge
4
 * @author    Atanas Angelov <[email protected]>
5
 * @copyright 2017-2019 Atanas Angelov
6
 * @license   https://www.gnu.org/licenses/gpl-2.0.html GPL-2.0
7
 * @link      https://wpemerge.com/
8
 */
9
10
namespace WPEmerge\Kernels;
11
12
use Exception;
13
use Pimple\Container;
14
use Psr\Http\Message\ResponseInterface;
15
use WP_Query;
16
use WPEmerge\Application\GenericFactory;
17
use WPEmerge\Exceptions\ConfigurationException;
18
use WPEmerge\Exceptions\ErrorHandlerInterface;
19
use WPEmerge\Helpers\Handler;
20
use WPEmerge\Helpers\HandlerFactory;
21
use WPEmerge\Middleware\ExecutesMiddlewareTrait;
22
use WPEmerge\Middleware\HasMiddlewareDefinitionsTrait;
23
use WPEmerge\Middleware\ReadsHandlerMiddlewareTrait;
24
use WPEmerge\Requests\RequestInterface;
25
use WPEmerge\Responses\ConvertsToResponseTrait;
26
use WPEmerge\Responses\ResponseService;
27
use WPEmerge\Routing\HasQueryFilterInterface;
28
use WPEmerge\Routing\RouteInterface;
29
use WPEmerge\Routing\Router;
30
use WPEmerge\Routing\SortsMiddlewareTrait;
31
use WPEmerge\View\ViewService;
32
33
/**
34
 * Describes how a request is handled.
35
 */
36
class HttpKernel implements HttpKernelInterface {
37
	use HasMiddlewareDefinitionsTrait;
38
	use SortsMiddlewareTrait;
39
	use ConvertsToResponseTrait;
40
	use ReadsHandlerMiddlewareTrait;
41
	use ExecutesMiddlewareTrait;
42
43
	/**
44
	 * Container.
45
	 *
46
	 * @var Container
47
	 */
48
	protected $container = null;
49
50
	/**
51
	 * Injection factory.
52
	 *
53
	 * @var GenericFactory
54
	 */
55
	protected $factory = null;
56
57
	/**
58
	 * Handler factory.
59
	 *
60
	 * @var HandlerFactory
61
	 */
62
	protected $handler_factory = null;
63
64
	/**
65
	 * Response service.
66
	 *
67
	 * @var ResponseService
68
	 */
69
	protected $response_service = null;
70
71
	/**
72
	 * Request.
73
	 *
74
	 * @var RequestInterface
75
	 */
76
	protected $request = null;
77
78
	/**
79
	 * Router.
80
	 *
81
	 * @var Router
82
	 */
83
	protected $router = null;
84
85
	/**
86
	 * View Service.
87
	 *
88
	 * @var ViewService
89
	 */
90
	protected $view_service = null;
91
92
	/**
93
	 * Error handler.
94
	 *
95
	 * @var ErrorHandlerInterface
96
	 */
97
	protected $error_handler = null;
98
99
	/**
100
	 * Template WordPress attempted to load.
101
	 *
102
	 * @var string
103
	 */
104
	protected $template = '';
105
106
	/**
107
	 * Constructor.
108
	 *
109
	 * @codeCoverageIgnore
110
	 * @param Container             $container
111
	 * @param GenericFactory        $factory
112
	 * @param HandlerFactory        $handler_factory
113
	 * @param ResponseService       $response_service
114
	 * @param RequestInterface      $request
115
	 * @param Router                $router
116
	 * @param ViewService           $view_service
117
	 * @param ErrorHandlerInterface $error_handler
118
	 */
119
	public function __construct(
120
		Container $container,
121
		GenericFactory $factory,
122
		HandlerFactory $handler_factory,
123
		ResponseService $response_service,
124
		RequestInterface $request,
125
		Router $router,
126
		ViewService $view_service,
127
		ErrorHandlerInterface $error_handler
128
	) {
129
		$this->container = $container;
130
		$this->factory = $factory;
131
		$this->handler_factory = $handler_factory;
132
		$this->response_service = $response_service;
133
		$this->request = $request;
134
		$this->router = $router;
135
		$this->view_service = $view_service;
136
		$this->error_handler = $error_handler;
137
	}
138
139
	/**
140
	 * Get the current response.
141
	 *
142
	 * @codeCoverageIgnore
143
	 * @return ResponseInterface|null
144
	 */
145
	protected function getResponse() {
146
		return isset( $this->container[ WPEMERGE_RESPONSE_KEY ] ) ? $this->container[ WPEMERGE_RESPONSE_KEY ] : null;
147
	}
148
149
	/**
150
	 * Get a Response Service instance.
151
	 *
152
	 * @codeCoverageIgnore
153
	 * @return ResponseService
154
	 */
155
	protected function getResponseService() {
156
		return $this->response_service;
157
	}
158
159 2
	/**
160 2
	 * Make a middleware class instance.
161 2
	 *
162
	 * @codeCoverageIgnore
163 2
	 * @param  string $class
164 1
	 * @return object
165
	 */
166 1
	protected function makeMiddleware( $class ) {
167 1
		return $this->factory->make( $class );
168
	}
169
170 1
	/**
171
	 * Execute a handler.
172
	 *
173
	 * @param  Handler           $handler
174
	 * @param  array             $arguments
175
	 * @return ResponseInterface
176 2
	 */
177 2
	protected function executeHandler( Handler $handler, $arguments = [] ) {
178
		$response = call_user_func_array( [$handler, 'execute'], $arguments );
179
		$response = $this->toResponse( $response );
180 2
181
		if ( ! $response instanceof ResponseInterface ) {
182 2
			throw new ConfigurationException(
183 2
				'Response returned by controller is not valid ' .
184 2
				'(expected ' . ResponseInterface::class . '; received ' . gettype( $response ) . ').'
185 2
			);
186
		}
187 2
188 2
		return $response;
189 2
	}
190 2
191 1
	/**
192
	 * {@inheritDoc}
193
	 */
194 1
	public function run( RequestInterface $request, $middleware, $handler, $arguments = [] ) {
195
		$this->error_handler->register();
196 1
197
		try {
198
			$handler = $handler instanceof Handler ? $handler : $this->handler_factory->make( $handler );
199
200
			$middleware = array_merge( $middleware, $this->getHandlerMiddleware( $handler ) );
201
			$middleware = $this->expandMiddleware( $middleware );
202 2
			$middleware = $this->uniqueMiddleware( $middleware );
203 2
			$middleware = $this->sortMiddleware( $middleware );
204
205 2
			$response = $this->executeMiddleware( $middleware, $request, function () use ( $handler, $arguments ) {
206 1
				return $this->executeHandler( $handler, $arguments );
207
			} );
208
		} catch ( Exception $exception ) {
209 1
			$response = $this->error_handler->getResponse( $request, $exception );
210
		}
211
212 1
		$this->error_handler->unregister();
213 1
214
		return $response;
215 1
	}
216 1
217 1
	/**
218 1
	 * {@inheritDoc}
219 1
	 */
220 1
	public function handle( RequestInterface $request, $arguments = [] ) {
221 1
		$route = $this->router->execute( $request );
222
223 1
		if ( $route === null ) {
224 1
			return null;
225
		}
226 1
227
		$route_arguments = $route->getArguments( $request );
228 1
229
		$request = $request
230
			->withAttribute( 'route', $route )
231
			->withAttribute( 'route_arguments', $route_arguments );
232
233
		$response = $this->run(
234
			$request,
235
			$route->getMiddleware(),
236 2
			$route->getHandler(),
237 2
			array_merge(
238
				[$request],
239 2
				$arguments,
240 1
				$route_arguments
241
			)
242
		);
243 1
244 1
		$this->container[ WPEMERGE_RESPONSE_KEY ] = $response;
245
246
		return $response;
247
	}
248
249
	/**
250
	 * Respond with the current response.
251
	 *
252
	 * @return void
253
	 */
254
	public function respond() {
255
		$response = $this->getResponse();
256
257
		if ( ! $response instanceof ResponseInterface ) {
258
			return;
259
		}
260
261
		$this->response_service->respond( $response );
262
	}
263
264
	/**
265
	 * Output the current view outside of the routing flow.
266
	 *
267
	 * @return void
268
	 */
269
	public function compose() {
270 2
		$view = $this->view_service->make( $this->template );
271
272 2
		echo $view->toString();
273
	}
274 2
275 2
	/**
276 2
	 * {@inheritDoc}
277
	 * @codeCoverageIgnore
278
	 */
279 2
	public function bootstrap() {
280 1
		// Web. Use 3100 so it's high enough and has uncommonly used numbers
281
		// before and after. For example, 1000 is too common and it would have 999 before it
282
		// which is too common as well.).
283 2
		add_action( 'request', [$this, 'filterRequest'], 3100 );
284 2
		add_action( 'template_include', [$this, 'filterTemplateInclude'], 3100 );
285 2
286
		// Ajax.
287 2
		add_action( 'admin_init', [$this, 'registerAjaxAction'] );
288
289
		// Admin.
290
		add_action( 'admin_init', [$this, 'registerAdminAction'] );
291
	}
292
293
	/**
294
	 * Filter the main query vars.
295
	 *
296 3
	 * @param  array $query_vars
297
	 * @return array
298 3
	 */
299
	public function filterRequest( $query_vars ) {
300 3
		/** @var $routes RouteInterface[] */
301
		$routes = $this->router->getRoutes();
302 3
303 2
		foreach ( $routes as $route ) {
304 1
			if ( ! $route instanceof HasQueryFilterInterface ) {
305 1
				continue;
306
			}
307 2
308
			if ( ! $route->isSatisfied( $this->request ) ) {
309 2
				continue;
310
			}
311
312 1
			$query_vars = $route->applyQueryFilter( $this->request, $query_vars );
313
			break;
314
		}
315
316
		return $query_vars;
317
	}
318
319
	/**
320
	 * Filter the main template file.
321
	 *
322
	 * @param  string $template
323
	 * @return string
324
	 */
325
	public function filterTemplateInclude( $template ) {
326
		/** @var $wp_query WP_Query */
327
		global $wp_query;
328
329
		$this->template = $template;
330
331
		$response = $this->handle( $this->request, [$template] );
332
333
		if ( $response instanceof ResponseInterface ) {
334
			if ( $response->getStatusCode() === 404 ) {
335
				$wp_query->set_404();
336
			}
337
338
			add_action( 'wpemerge.kernels.http_kernel.respond', [$this, 'respond'] );
339
340
			return WPEMERGE_DIR . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'view.php';
341
		}
342
343
		$composers = $this->view_service->getComposersForView( $template );
344
345
		if ( ! empty( $composers ) ) {
346
			add_action( 'wpemerge.kernels.http_kernel.respond', [$this, 'compose'] );
347
348
			return WPEMERGE_DIR . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'view.php';
349
		}
350
351
		return $template;
352
	}
353
354
	/**
355
	 * Register ajax action to hook into current one.
356
	 *
357
	 * @return void
358
	 */
359
	public function registerAjaxAction() {
360
		if ( ! wp_doing_ajax() ) {
361
			return;
362
		}
363
364
		$action = $this->request->body( 'action', $this->request->query( 'action' ) );
365
		$action = sanitize_text_field( $action );
366
367
		add_action( "wp_ajax_{$action}", [$this, 'actionAjax'] );
368
		add_action( "wp_ajax_nopriv_{$action}", [$this, 'actionAjax'] );
369
	}
370
371
	/**
372
	 * Act on ajax action.
373
	 *
374
	 * @return void
375
	 */
376
	public function actionAjax() {
377
		$response = $this->handle( $this->request, [''] );
378
379
		if ( ! $response instanceof ResponseInterface ) {
380
			return;
381
		}
382
383
		$this->response_service->respond( $response );
384
385
		wp_die( '', '', ['response' => null] );
386
	}
387
388
	/**
389
	 * Get page hook.
390
	 * Slightly modified version of code from wp-admin/admin.php.
391
	 *
392
	 * @return string
393
	 */
394
	protected function getAdminPageHook() {
395
		global $pagenow, $typenow, $plugin_page;
396
397
		$page_hook = '';
398
399
		if ( isset( $plugin_page ) ) {
400
			$the_parent = $pagenow;
401
402
			if ( ! empty( $typenow ) ) {
403
				$the_parent = $pagenow . '?post_type=' . $typenow;
404
			}
405
406
			$page_hook = get_plugin_page_hook( $plugin_page, $the_parent );
407
		}
408
409
		return $page_hook;
410
	}
411
412
	/**
413
	 * Get admin page hook.
414
	 * Slightly modified version of code from wp-admin/admin.php.
415
	 *
416
	 * @param  string $page_hook
417
	 * @return string
418
	 */
419
	protected function getAdminHook( $page_hook ) {
420
		global $pagenow, $plugin_page;
421
422
		if ( ! empty( $page_hook ) ) {
423
			return $page_hook;
424
		}
425
426
		if ( isset( $plugin_page ) ) {
427
			return $plugin_page;
428
		}
429
430
		if ( isset( $pagenow ) ) {
431
			return $pagenow;
432
		}
433
434
		return '';
435
	}
436
437
	/**
438
	 * Register admin action to hook into current one.
439
	 *
440
	 * @return void
441
	 */
442
	public function registerAdminAction() {
443
		$page_hook = $this->getAdminPageHook();
444
		$hook_suffix = $this->getAdminHook( $page_hook );
445
446
		add_action( "load-{$hook_suffix}", [$this, 'actionAdminLoad'] );
447
		add_action( $hook_suffix, [$this, 'actionAdmin'] );
448
	}
449
450
	/**
451
	 * Act on admin action load.
452
	 *
453
	 * @return void
454
	 */
455
	public function actionAdminLoad() {
456
		$response = $this->handle( $this->request, [''] );
457
458
		if ( ! $response instanceof ResponseInterface ) {
459
			return;
460
		}
461
462
		if ( ! headers_sent() ) {
463
			$this->response_service->sendHeaders( $response );
464
		}
465
	}
466
467
	/**
468
	 * Act on admin action.
469
	 *
470
	 * @return void
471
	 */
472
	public function actionAdmin() {
473
		$response = $this->getResponse();
474
475
		if ( ! $response instanceof ResponseInterface ) {
476
			return;
477
		}
478
479
		$this->response_service->sendBody( $response );
480
	}
481
}
482