Passed
Branch refactor/route-groups (411840)
by Atanas
01:44
created

Route::middleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
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\Routing;
11
12
use Closure;
13
use WPEmerge\Exceptions\Exception;
14
use WPEmerge\Facades\Framework;
15
use WPEmerge\Facades\RouteCondition;
16
use WPEmerge\Requests\RequestInterface;
17
use WPEmerge\Routing\Conditions\ConditionInterface;
18
use WPEmerge\Routing\Conditions\InvalidRouteConditionException;
19
use WPEmerge\Routing\Conditions\UrlCondition;
20
21
/**
22
 * Represent a route
23
 */
24
class Route implements RouteInterface {
25
	/**
26
	 * Allowed methods.
27
	 *
28
	 * @var string[]
29
	 */
30
	protected $methods = [];
31
32
	/**
33
	 * Route condition.
34
	 *
35
	 * @var ConditionInterface
36
	 */
37
	protected $condition = null;
38
39
	/**
40
	 * Route pipeline.
41
	 *
42
	 * @var Pipeline
43
	 */
44
	protected $pipeline = null;
45
46
	/**
47
	 * Query filter.
48
	 *
49
	 * @var callable
50
	 */
51
	protected $query_filter = null;
52
53
	/**
54
	 * Query filter action priority.
55
	 *
56
	 * @var integer
57
	 */
58
	protected $query_filter_priority = 1000;
59
60
	/**
61
	 * Constructor.
62
	 *
63
	 * @throws Exception
64
	 * @param  string[]        $methods
65
	 * @param  mixed           $condition
66
	 * @param  string|\Closure $handler
67
	 */
68 3
	public function __construct( $methods, $condition, $handler ) {
69 3
		if ( ! $condition instanceof ConditionInterface ) {
70
			try {
71 2
				$condition = RouteCondition::make( $condition );
72 1
			} catch ( InvalidRouteConditionException $e ) {
73 1
				throw new Exception( 'Route condition is not a valid route string or condition.' );
74
			}
75
		}
76
77 2
		$this->methods = $methods;
78 2
		$this->setCondition( $condition );
79 2
		$this->pipeline = new Pipeline( $handler );
80 2
	}
81
82
	/**
83
	 * Get allowed methods.
84
	 *
85
	 * @return string[]
86
	 */
87 1
	public function getMethods() {
88 1
		return $this->methods;
89
	}
90
91
	/**
92
	 * {@inheritDoc}
93
	 */
94 1
	public function getCondition() {
95 1
		return $this->condition;
96
	}
97
98
	/**
99
	 * {@inheritDoc}
100
	 */
101
	public function setCondition( $condition ) {
102
		$this->condition = $condition;
103
	}
104
105
	/**
106
	 * Get pipeline.
107
	 *
108
	 * @return Pipeline
109
	 */
110 1
	public function getPipeline() {
111 1
		return $this->pipeline;
112
	}
113
114
	/**
115
	 * Set custom partial regex matching for the specified parameter.
116
	 *
117
	 * @param  string $parameter
118
	 * @param  string $regex
119
	 * @return static $this
120
	 */
121
	public function where( $parameter, $regex ) {
122
		$condition = $this->getCondition();
123
124
		if ( ! $condition instanceof UrlCondition ) {
125
			throw new Exception( 'Only routes with URL conditions can specify parameter regex matching.' );
126
		}
127
128
		$condition->setUrlWhere( array_merge(
129
			$condition->getUrlWhere(),
130
			[$parameter => $regex]
131
		) );
132
133
		return $this;
134
	}
135
136
	/**
137
	 * Get the main WordPress query vars filter, if any.
138
	 *
139
	 * @return callable|null
140
	 */
141 1
	public function getQueryFilter() {
142 1
		return $this->query_filter;
143
	}
144
145
	/**
146
	 * Set the main WordPress query vars filter and add it to the appropriate WordPress action.
147
	 *
148
	 * @param  callable|null $query_filter
149
	 * @return void
150
	 */
151 1
	public function setQueryFilter( $query_filter ) {
152 1
		$this->query_filter = $query_filter;
153 1
	}
154
155
	/**
156
	 * Add the query filter to the appropriate WordPress action.
157
	 *
158
	 * @return void
159
	 */
160 1
	public function addQueryFilter() {
161 1
		$filter = [$this, 'applyQueryFilter'];
162
163 1
		if ( ! has_action( 'request', $filter ) ) {
164 1
			add_action( 'request', $filter, $this->query_filter_priority );
165
		}
166 1
	}
167
168
	/**
169
	 * Remove the query filter from the appropriate WordPress action.
170
	 *
171
	 * @return void
172
	 */
173 1
	public function removeQueryFilter() {
174 1
		$filter = [$this, 'applyQueryFilter'];
175
176 1
		if ( has_action( 'request', $filter ) ) {
177 1
			remove_action( 'request', $filter, $this->query_filter_priority );
178
		}
179 1
	}
180
181
	/**
182
	 * Apply the query filter, if any.
183
	 *
184
	 * @throws Exception
185
	 * @param  array<string, mixed> $query_vars
186
	 * @return array<string, mixed>
187
	 */
188 4
	public function applyQueryFilter( $query_vars ) {
189 4
		$request = Framework::resolve( WPEMERGE_REQUEST_KEY );
190 4
		$condition = $this->getCondition();
191
192 4
		if ( ! is_callable( $this->getQueryFilter() ) ) {
193 1
			return $query_vars;
194
		}
195
196 3
		if ( ! $condition instanceof UrlCondition ) {
197 1
			throw new Exception(
198
				'Routes with queries can only use URL conditions. ' .
199 1
				'Is the route in a non-URL route group?'
200
			);
201
		}
202
203 2
		if ( $this->getCondition()->isSatisfied( $request ) ) {
204 1
			$arguments = $this->getCondition()->getArguments( $request );
205 1
			$query_vars = call_user_func_array( $this->getQueryFilter(), array_merge( [$query_vars], array_values( $arguments ) ) );
206
		}
207
208 2
		return $query_vars;
209
	}
210
211
	/**
212
	 * Set the main WordPress query vars filter.
213
	 *
214
	 * @codeCoverageIgnore
215
	 * @param  callable $query_filter
216
	 * @return self     $this
217
	 */
218
	public function query( $query_filter ) {
219
		$this->setQueryFilter( $query_filter );
220
		$this->addQueryFilter();
221
		return $this;
222
	}
223
224
	/**
225
	 * {@inheritDoc}
226
	 */
227 2
	public function isSatisfied( RequestInterface $request ) {
228 2
		if ( ! in_array( $request->getMethod(), $this->methods ) ) {
229 1
			return false;
230
		}
231 2
		return $this->condition->isSatisfied( $request );
232
	}
233
234
	/**
235
	 * {@inheritDoc}
236
	 */
237 1
	public function getArguments( RequestInterface $request ) {
238 1
		return $this->getCondition()->getArguments( $request );
239
	}
240
241
	/**
242
	 * {@inheritDoc}
243
	 */
244 1
	public function handle( RequestInterface $request, $view ) {
245 1
		$arguments = array_merge( [$request, $view], array_values( $this->condition->getArguments( $request ) ) );
246
247 1
		return $this->getPipeline()->run( $request, $arguments );
248
	}
249
250
	/**
251
	 * {@inheritDoc}
252
	 * @codeCoverageIgnore
253
	 */
254
	public function getMiddleware() {
255
		return $this->getPipeline()->getMiddleware();
256
	}
257
258
	/**
259
	 * {@inheritDoc}
260
	 * @codeCoverageIgnore
261
	 */
262
	public function setMiddleware( $middleware ) {
263
		$this->getPipeline()->setMiddleware( $middleware );
264
	}
265
266
	/**
267
	 * {@inheritDoc}
268
	 * @codeCoverageIgnore
269
	 * @throws Exception
270
	 */
271
	public function addMiddleware( $middleware ) {
272
		$this->getPipeline()->addMiddleware( $middleware );
273
274
		return $this;
275
	}
276
277
	/**
278
	 * {@inheritDoc}
279
	 * @codeCoverageIgnore
280
	 */
281
	public function middleware( $middleware ) {
282
		$this->getPipeline()->middleware( $middleware );
283
284
		return $this;
285
	}
286
287
	/**
288
	 * {@inheritDoc}
289
	 * @codeCoverageIgnore
290
	 */
291
	public function executeMiddleware( $middleware, RequestInterface $request, Closure $next ) {
292
		return $this->getPipeline()->executeMiddleware( $middleware, $request, $next );
293
	}
294
}
295