Passed
Push — master ( 685651...ff2960 )
by Atanas
02:52
created

Route::where()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

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