Passed
Branch refactor/route-groups (c18eda)
by Atanas
01:54
created

Route::where()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 2
dl 0
loc 13
ccs 8
cts 8
cp 1
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
	 * @codeCoverageIgnore
101
	 */
102
	public function setCondition( $condition ) {
103
		$this->condition = $condition;
104
	}
105
106
	/**
107
	 * Get pipeline.
108
	 *
109
	 * @return Pipeline
110
	 */
111 1
	public function getPipeline() {
112 1
		return $this->pipeline;
113
	}
114
115
	/**
116
	 * Set custom partial regex matching for the specified parameter.
117
	 *
118
	 * @param  string $parameter
119
	 * @param  string $regex
120
	 * @return static $this
121
	 */
122 2
	public function where( $parameter, $regex ) {
123 2
		$condition = $this->getCondition();
124
125 2
		if ( ! $condition instanceof UrlCondition ) {
126 1
			throw new Exception( 'Only routes with URL conditions can specify parameter regex matching.' );
127
		}
128
129 1
		$condition->setUrlWhere( array_merge(
130 1
			$condition->getUrlWhere(),
131 1
			[$parameter => $regex]
132
		) );
133
134 1
		return $this;
135
	}
136
137
	/**
138
	 * Get the main WordPress query vars filter, if any.
139
	 *
140
	 * @return callable|null
141
	 */
142 1
	public function getQueryFilter() {
143 1
		return $this->query_filter;
144
	}
145
146
	/**
147
	 * Set the main WordPress query vars filter and add it to the appropriate WordPress action.
148
	 *
149
	 * @param  callable|null $query_filter
150
	 * @return void
151
	 */
152 1
	public function setQueryFilter( $query_filter ) {
153 1
		$this->query_filter = $query_filter;
154 1
	}
155
156
	/**
157
	 * Add the query filter to the appropriate WordPress action.
158
	 *
159
	 * @return void
160
	 */
161 1
	public function addQueryFilter() {
162 1
		$filter = [$this, 'applyQueryFilter'];
163
164 1
		if ( ! has_action( 'request', $filter ) ) {
165 1
			add_action( 'request', $filter, $this->query_filter_priority );
166
		}
167 1
	}
168
169
	/**
170
	 * Remove the query filter from the appropriate WordPress action.
171
	 *
172
	 * @return void
173
	 */
174 1
	public function removeQueryFilter() {
175 1
		$filter = [$this, 'applyQueryFilter'];
176
177 1
		if ( has_action( 'request', $filter ) ) {
178 1
			remove_action( 'request', $filter, $this->query_filter_priority );
179
		}
180 1
	}
181
182
	/**
183
	 * Apply the query filter, if any.
184
	 *
185
	 * @throws Exception
186
	 * @param  array<string, mixed> $query_vars
187
	 * @return array<string, mixed>
188
	 */
189 4
	public function applyQueryFilter( $query_vars ) {
190 4
		$request = Framework::resolve( WPEMERGE_REQUEST_KEY );
191 4
		$condition = $this->getCondition();
192
193 4
		if ( ! is_callable( $this->getQueryFilter() ) ) {
194 1
			return $query_vars;
195
		}
196
197 3
		if ( ! $condition instanceof UrlCondition ) {
198 1
			throw new Exception(
199
				'Routes with queries can only use URL conditions. ' .
200 1
				'Is the route in a non-URL route group?'
201
			);
202
		}
203
204 2
		if ( $this->getCondition()->isSatisfied( $request ) ) {
205 1
			$arguments = $this->getCondition()->getArguments( $request );
206 1
			$query_vars = call_user_func_array( $this->getQueryFilter(), array_merge( [$query_vars], array_values( $arguments ) ) );
207
		}
208
209 2
		return $query_vars;
210
	}
211
212
	/**
213
	 * Set the main WordPress query vars filter.
214
	 *
215
	 * @codeCoverageIgnore
216
	 * @param  callable $query_filter
217
	 * @return self     $this
218
	 */
219
	public function query( $query_filter ) {
220
		$this->setQueryFilter( $query_filter );
221
		$this->addQueryFilter();
222
		return $this;
223
	}
224
225
	/**
226
	 * {@inheritDoc}
227
	 */
228 2
	public function isSatisfied( RequestInterface $request ) {
229 2
		if ( ! in_array( $request->getMethod(), $this->methods ) ) {
230 1
			return false;
231
		}
232 2
		return $this->condition->isSatisfied( $request );
233
	}
234
235
	/**
236
	 * {@inheritDoc}
237
	 */
238 1
	public function getArguments( RequestInterface $request ) {
239 1
		return $this->getCondition()->getArguments( $request );
240
	}
241
242
	/**
243
	 * {@inheritDoc}
244
	 */
245 1
	public function handle( RequestInterface $request, $view ) {
246 1
		$arguments = array_merge( [$request, $view], array_values( $this->condition->getArguments( $request ) ) );
247
248 1
		return $this->getPipeline()->run( $request, $arguments );
249
	}
250
251
	/**
252
	 * {@inheritDoc}
253
	 * @codeCoverageIgnore
254
	 */
255
	public function getMiddleware() {
256
		return $this->getPipeline()->getMiddleware();
257
	}
258
259
	/**
260
	 * {@inheritDoc}
261
	 * @codeCoverageIgnore
262
	 */
263
	public function setMiddleware( $middleware ) {
264
		$this->getPipeline()->setMiddleware( $middleware );
265
	}
266
267
	/**
268
	 * {@inheritDoc}
269
	 * @codeCoverageIgnore
270
	 * @throws Exception
271
	 */
272
	public function addMiddleware( $middleware ) {
273
		$this->getPipeline()->addMiddleware( $middleware );
274
275
		return $this;
276
	}
277
278
	/**
279
	 * {@inheritDoc}
280
	 * @codeCoverageIgnore
281
	 */
282
	public function middleware( $middleware ) {
283
		$this->getPipeline()->middleware( $middleware );
284
285
		return $this;
286
	}
287
288
	/**
289
	 * {@inheritDoc}
290
	 * @codeCoverageIgnore
291
	 */
292
	public function executeMiddleware( $middleware, RequestInterface $request, Closure $next ) {
293
		return $this->getPipeline()->executeMiddleware( $middleware, $request, $next );
294
	}
295
}
296