Passed
Branch refactor/kernels (6aa266)
by Atanas
01:51
created

HttpKernel::getAdminPageHook()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 15
ccs 0
cts 9
cp 0
crap 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package   WPEmerge
4
 * @author    Atanas Angelov <[email protected]>
5
 * @copyright 2018 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 Psr\Http\Message\ResponseInterface;
14
use WPEmerge\Application\Application;
15
use WPEmerge\Exceptions\ErrorHandlerInterface;
16
use WPEmerge\Facades\Response;
17
use WPEmerge\Middleware\HasMiddlewareDefinitionsTrait;
18
use WPEmerge\Requests\RequestInterface;
19
use WPEmerge\Routing\HasQueryFilterInterface;
20
use WPEmerge\Routing\Pipeline;
21
use WPEmerge\Routing\Router;
22
use WPEmerge\Routing\SortsMiddlewareTrait;
23
24
/**
25
 * Describes how a request is handled.
26
 */
27
class HttpKernel implements HttpKernelInterface {
28
	use HasMiddlewareDefinitionsTrait;
29
	use SortsMiddlewareTrait;
30
31
	/**
32
	 * Application.
33
	 *
34
	 * @var Application
35
	 */
36
	protected $app = null;
37
38
	/**
39
	 * Request.
40
	 *
41
	 * @var RequestInterface
42
	 */
43
	protected $request = null;
44
45
	/**
46
	 * Router.
47
	 *
48
	 * @var Router
49
	 */
50
	protected $router = null;
51
52
	/**
53
	 * Error handler.
54
	 *
55
	 * @var ErrorHandlerInterface
56
	 */
57
	protected $error_handler = null;
58
59
	/**
60
	 * Constructor.
61
	 *
62
	 * @codeCoverageIgnore
63
	 * @param Application           $app
64
	 * @param RequestInterface      $request
65
	 * @param Router                $router
66
	 * @param ErrorHandlerInterface $error_handler
67
	 */
68
	public function __construct( Application $app, RequestInterface $request, Router $router, ErrorHandlerInterface $error_handler ) {
69
		$this->app = $app;
70
		$this->request = $request;
71
		$this->router = $router;
72
		$this->error_handler = $error_handler;
73
	}
74
75
	/**
76
	 * {@inheritDoc}
77
	 * @codeCoverageIgnore
78
	 */
79
	public function bootstrap() {
80
		// Web.
81
		add_action( 'request', [$this, 'filterRequest'], 1000 );
82
		add_action( 'template_include', [$this, 'filterTemplateInclude'], 1000 );
83
84
		// Ajax.
85
		add_action( 'admin_init', [$this, 'registerAjaxAction'] );
86
87
		// Admin.
88
		add_action( 'admin_init', [$this, 'registerAdminAction'] );
89
	}
90
91
	/**
92
	 * {@inheritDoc}
93
	 */
94 2
	public function handle( RequestInterface $request, $arguments = [] ) {
95 2
		$route = $this->router->execute( $request );
96
97 2
		if ( $route === null ) {
98 1
			return null;
99
		}
100
101 1
		$handler = function () use ( $route ) {
102 1
			$arguments = func_get_args();
103 1
			$request = array_shift( $arguments );
104 1
			return call_user_func( [$route, 'handle'], $request, $arguments );
105 1
		};
106
107 1
		$response = $this->run( $request, $route->getMiddleware(), $handler, $arguments );
108
109 1
		$container = $this->app->getContainer();
110 1
		$container[ WPEMERGE_RESPONSE_KEY ] = $response;
111
112 1
		return $response;
113
	}
114
115
	/**
116
	 * {@inheritDoc}
117
	 */
118 2
	public function run( RequestInterface $request, $middleware, $handler, $arguments = [] ) {
119 2
		$this->error_handler->register();
120
121
		try {
122 2
			$middleware = $this->expandMiddleware( $middleware );
123 2
			$middleware = $this->uniqueMiddleware( $middleware );
124 2
			$middleware = $this->sortMiddleware( $middleware );
125
126 2
			$response = ( new Pipeline() )
127 2
				->pipe( $middleware )
128 2
				->to( $handler )
129 2
				->run( $request, array_merge( [$request], $arguments ) );
130 1
		} catch ( Exception $exception ) {
131 1
			$response = $this->error_handler->getResponse( $request, $exception );
132
		}
133
134 1
		$this->error_handler->unregister();
135
136 1
		return $response;
137
	}
138
139
	/**
140
	 * Filter the main query vars.
141
	 *
142
	 * @param  array $query_vars
143
	 * @return array
144
	 */
145 2
	public function filterRequest( $query_vars ) {
146 2
		$routes = $this->router->getRoutes();
147
148 2
		foreach ( $routes as $route ) {
149 2
			if ( ! $route instanceof HasQueryFilterInterface ) {
150 2
				continue;
151
			}
152
153 2
			if ( ! $route->isSatisfied( $this->request ) ) {
154 1
				continue;
155
			}
156
157 2
			$query_vars = $route->applyQueryFilter( $this->request, $query_vars );
158 2
			break;
159
		}
160
161 2
		return $query_vars;
162
	}
163
164
	/**
165
	 * Filter the main template file.
166
	 *
167
	 * @param  string $view
168
	 * @return string
169
	 */
170 3
	public function filterTemplateInclude( $view ) {
171 3
		global $wp_query;
172
173 3
		$response = $this->handle( $this->request, [$view] );
174
175 3
		if ( $response instanceof ResponseInterface ) {
176 2
			if ( $response->getStatusCode() === 404 ) {
177 1
				$wp_query->set_404();
178
			}
179
180 2
			return WPEMERGE_DIR . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'view.php';
181
		}
182
183 1
		return $view;
184
	}
185
186
	/**
187
	 * Register ajax action to hook into current one.
188
	 *
189
	 * @return void
190
	 */
191
	public function registerAjaxAction() {
192
		if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
193
			return;
194
		}
195
196
		$action = $this->request->post( 'action', $this->request->get( 'action' ) );
197
		$action = sanitize_text_field( $action );
198
199
		add_action( "wp_ajax_{$action}", [$this, 'actionAjax'] );
200
		add_action( "wp_ajax_nopriv_{$action}", [$this, 'actionAjax'] );
201
	}
202
203
	/**
204
	 * Act on ajax action.
205
	 *
206
	 * @return void
207
	 */
208
	public function actionAjax() {
209
		$response = $this->handle( $this->request, [''] );
210
211
		if ( ! $response instanceof ResponseInterface ) {
212
			return;
213
		}
214
215
		Response::respond( $response );
216
		wp_die( '', '', ['response' => null] );
217
	}
218
219
	/**
220
	 * Get page hook.
221
	 * Slightly modified version of code from wp-admin/admin.php.
222
	 *
223
	 * @return string
224
	 */
225
	protected function getAdminPageHook() {
226
		global $pagenow, $typenow, $plugin_page;
227
228
		$page_hook = '';
229
		if ( isset( $plugin_page ) ) {
230
			if ( ! empty( $typenow ) ) {
231
				$the_parent = $pagenow . '?post_type=' . $typenow;
232
			} else {
233
				$the_parent = $pagenow;
234
			}
235
236
			$page_hook = get_plugin_page_hook( $plugin_page, $the_parent );
237
		}
238
239
		return $page_hook;
240
	}
241
242
	/**
243
	 * Get admin page hook.
244
	 * Slightly modified version of code from wp-admin/admin.php.
245
	 *
246
	 * @param  string $page_hook
247
	 * @return string
248
	 */
249
	protected function getAdminHook( $page_hook ) {
250
		global $pagenow, $plugin_page;
251
252
		$hook_suffix = '';
253
		if ( ! empty( $page_hook ) ) {
254
			$hook_suffix = $page_hook;
255
		} else if ( isset( $plugin_page ) ) {
256
			$hook_suffix = $plugin_page;
257
		} else if ( isset( $pagenow ) ) {
258
			$hook_suffix = $pagenow;
259
		}
260
261
		return $hook_suffix;
262
	}
263
264
	/**
265
	 * Register admin action to hook into current one.
266
	 *
267
	 * @return void
268
	 */
269
	public function registerAdminAction() {
270
		global $pagenow;
271
272
		if ( $pagenow !== 'admin.php' ) {
273
			return;
274
		}
275
276
		$page_hook = $this->getAdminPageHook();
277
		$hook_suffix = $this->getAdminHook( $page_hook );
278
279
		add_action( "load-{$hook_suffix}", [$this, 'actionAdminLoad'] );
280
		add_action( $hook_suffix, [$this, 'actionAdmin'] );
281
	}
282
283
	/**
284
	 * Act on admin action load.
285
	 *
286
	 * @return void
287
	 */
288
	public function actionAdminLoad() {
289
		$response = $this->handle( $this->request, [''] );
290
291
		if ( ! $response instanceof ResponseInterface ) {
292
			return;
293
		}
294
295
		if ( ! headers_sent() ) {
296
			Response::sendHeaders( $response );
297
		}
298
	}
299
300
	/**
301
	 * Act on admin action.
302
	 *
303
	 * @return void
304
	 */
305
	public function actionAdmin() {
306
		$response = $this->app->resolve( WPEMERGE_RESPONSE_KEY );
307
308
		if ( $response === null ) {
309
			return;
310
		}
311
312
		Response::sendBody( $response );
313
	}
314
}
315