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