PluginProbe
Depicter — Popup & Slider Builder / 1.3.3
Depicter — Popup & Slider Builder v1.3.3
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / vendor / htmlburger / wpemerge / src / Routing / Router.php

Router.php in Depicter — Popup & Slider Builder 1.3.3, at vendor/htmlburger/wpemerge/src/Routing/Router.php

395 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package WPEmerge
4 * @author Atanas Angelov <hi@atanas.dev>
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\Routing;
11
12 use Closure;
13 use WPEmerge\Exceptions\ConfigurationException;
14 use WPEmerge\Helpers\Handler;
15 use WPEmerge\Helpers\HandlerFactory;
16 use WPEmerge\Requests\RequestInterface;
17 use WPEmerge\Routing\Conditions\ConditionFactory;
18 use WPEmerge\Routing\Conditions\ConditionInterface;
19 use WPEmerge\Routing\Conditions\UrlableInterface;
20 use WPEmerge\Support\Arr;
21
22 /**
23 * Provide routing for site requests (i.e. all non-api requests).
24 */
25 class Router implements HasRoutesInterface {
26 use HasRoutesTrait;
27
28 /**
29 * Condition factory.
30 *
31 * @var ConditionFactory
32 */
33 protected $condition_factory = null;
34
35 /**
36 * Handler factory.
37 *
38 * @var HandlerFactory
39 */
40 protected $handler_factory = null;
41
42 /**
43 * Group stack.
44 *
45 * @var array<array<string, mixed>>
46 */
47 protected $group_stack = [];
48
49 /**
50 * Current active route.
51 *
52 * @var RouteInterface|null
53 */
54 protected $current_route = null;
55
56 /**
57 * Constructor.
58 *
59 * @codeCoverageIgnore
60 * @param ConditionFactory $condition_factory
61 * @param HandlerFactory $handler_factory
62 */
63 public function __construct( ConditionFactory $condition_factory, HandlerFactory $handler_factory ) {
64 $this->condition_factory = $condition_factory;
65 $this->handler_factory = $handler_factory;
66 }
67
68 /**
69 * Get the current route.
70 *
71 * @return RouteInterface
72 */
73 public function getCurrentRoute() {
74 return $this->current_route;
75 }
76
77 /**
78 * Set the current route.
79 *
80 * @param RouteInterface $current_route
81 * @return void
82 */
83 public function setCurrentRoute( RouteInterface $current_route ) {
84 $this->current_route = $current_route;
85 }
86
87 /**
88 * Merge the methods attribute combining values.
89 *
90 * @param string[] $old
91 * @param string[] $new
92 * @return string[]
93 */
94 public function mergeMethodsAttribute( $old, $new ) {
95 return array_merge( $old, $new );
96 }
97
98 /**
99 * Merge the condition attribute.
100 *
101 * @param string|array|Closure|ConditionInterface|null $old
102 * @param string|array|Closure|ConditionInterface|null $new
103 * @return ConditionInterface|string
104 */
105 public function mergeConditionAttribute( $old, $new ) {
106 try {
107 $condition = $this->condition_factory->merge( $old, $new );
108 } catch ( ConfigurationException $e ) {
109 throw new ConfigurationException( 'Route condition is not a valid route string or condition.' );
110 }
111
112 return $condition;
113 }
114
115 /**
116 * Merge the middleware attribute combining values.
117 *
118 * @param string[] $old
119 * @param string[] $new
120 * @return string[]
121 */
122 public function mergeMiddlewareAttribute( $old, $new ) {
123 return array_merge( $old, $new );
124 }
125
126 /**
127 * Merge the namespace attribute taking the latest value.
128 *
129 * @param string $old
130 * @param string $new
131 * @return string
132 */
133 public function mergeNamespaceAttribute( $old, $new ) {
134 return ! empty( $new ) ? $new : $old;
135 }
136
137 /**
138 * Merge the handler attribute taking the latest value.
139 *
140 * @param string|Closure $old
141 * @param string|Closure $new
142 * @return string|Closure
143 */
144 public function mergeHandlerAttribute( $old, $new ) {
145 return ! empty( $new ) ? $new : $old;
146 }
147
148 /**
149 * Merge the handler attribute taking the latest value.
150 *
151 * @param callable|null $old
152 * @param callable|null $new
153 * @return string|Closure
154 */
155 public function mergeQueryAttribute( $old, $new ) {
156 if ( $new === null ) {
157 return $old;
158 }
159
160 if ( $old === null ) {
161 return $new;
162 }
163
164 return function ( $query_vars ) use ( $old, $new ) {
165 return call_user_func( $new, call_user_func( $old, $query_vars ) );
166 };
167 }
168
169 /**
170 * Merge the name attribute combining values with a dot.
171 *
172 * @param string $old
173 * @param string $new
174 * @return string
175 */
176 public function mergeNameAttribute( $old, $new ) {
177 $name = implode( '.', array_filter( [$old, $new] ) );
178
179 // Trim dots.
180 $name = preg_replace( '/^\.+|\.+$/', '', $name );
181
182 // Reduce multiple dots to a single one.
183 $name = preg_replace( '/\.{2,}/', '.', $name );
184
185 return $name;
186 }
187
188 /**
189 * Merge attributes into route.
190 *
191 * @param array<string, mixed> $old
192 * @param array<string, mixed> $new
193 * @return array<string, mixed>
194 */
195 public function mergeAttributes( $old, $new ) {
196 return [
197 'methods' => $this->mergeMethodsAttribute(
198 (array) Arr::get( $old, 'methods', [] ),
199 (array) Arr::get( $new, 'methods', [] )
200 ),
201
202 'condition' => $this->mergeConditionAttribute(
203 Arr::get( $old, 'condition', null ),
204 Arr::get( $new, 'condition', null )
205 ),
206
207 'middleware' => $this->mergeMiddlewareAttribute(
208 (array) Arr::get( $old, 'middleware', [] ),
209 (array) Arr::get( $new, 'middleware', [] )
210 ),
211
212 'namespace' => $this->mergeNamespaceAttribute(
213 Arr::get( $old, 'namespace', '' ),
214 Arr::get( $new, 'namespace', '' )
215 ),
216
217 'handler' => $this->mergeHandlerAttribute(
218 Arr::get( $old, 'handler', '' ),
219 Arr::get( $new, 'handler', '' )
220 ),
221
222 'query' => $this->mergeQueryAttribute(
223 Arr::get( $old, 'query', null ),
224 Arr::get( $new, 'query', null )
225 ),
226
227 'name' => $this->mergeNameAttribute(
228 Arr::get( $old, 'name', '' ),
229 Arr::get( $new, 'name', '' )
230 ),
231 ];
232 }
233
234 /**
235 * Get the top group from the stack.
236 *
237 * @codeCoverageIgnore
238 * @return array<string, mixed>
239 */
240 protected function getGroup() {
241 return Arr::last( $this->group_stack, null, [] );
242 }
243
244 /**
245 * Add a group to the group stack, merging all previous attributes.
246 *
247 * @codeCoverageIgnore
248 * @param array<string, mixed> $group
249 * @return void
250 */
251 protected function pushGroup( $group ) {
252 $this->group_stack[] = $this->mergeAttributes( $this->getGroup(), $group );
253 }
254
255 /**
256 * Remove last group from the group stack.
257 *
258 * @codeCoverageIgnore
259 * @return void
260 */
261 protected function popGroup() {
262 array_pop( $this->group_stack );
263 }
264
265 /**
266 * Create a route group.
267 *
268 * @codeCoverageIgnore
269 * @param array<string, mixed> $attributes
270 * @param Closure|string $routes Closure or path to file.
271 * @return void
272 */
273 public function group( $attributes, $routes ) {
274 $this->pushGroup( $attributes );
275
276 if ( is_string( $routes ) ) {
277 /** @noinspection PhpIncludeInspection */
278 /** @codeCoverageIgnore */
279 require_once $routes;
280 } else {
281 $routes();
282 }
283
284 $this->popGroup();
285 }
286
287 /**
288 * Make a route condition.
289 *
290 * @param mixed $condition
291 * @return ConditionInterface
292 */
293 protected function routeCondition( $condition ) {
294 if ( $condition === null ) {
295 throw new ConfigurationException( 'No route condition specified. Did you miss to call url() or where()?' );
296 }
297
298 if ( ! $condition instanceof ConditionInterface ) {
299 $condition = $this->condition_factory->make( $condition );
300 }
301
302 return $condition;
303 }
304
305 /**
306 * Make a route handler.
307 *
308 * @codeCoverageIgnore
309 * @param string|Closure|null $handler
310 * @param string $namespace
311 * @return Handler
312 */
313 protected function routeHandler( $handler, $namespace ) {
314 if ( $handler === null ) {
315 throw new ConfigurationException( 'No route handler specified. Did you miss to call handle()?' );
316 }
317
318 return $this->handler_factory->make( $handler, '', $namespace );
319 }
320
321 /**
322 * Make a route.
323 *
324 * @param array<string, mixed> $attributes
325 * @return RouteInterface
326 */
327 public function route( $attributes ) {
328 $attributes = $this->mergeAttributes( $this->getGroup(), $attributes );
329 $attributes = array_merge(
330 $attributes,
331 [
332 'condition' => $this->routeCondition( $attributes['condition'] ),
333 'handler' => $this->routeHandler( $attributes['handler'], $attributes['namespace'] ),
334 ]
335 );
336
337 if ( empty( $attributes['methods'] ) ) {
338 throw new ConfigurationException(
339 'Route does not have any assigned request methods. ' .
340 'Did you miss to call get() or post() on your route definition, for example?'
341 );
342 }
343
344 return (new Route())->attributes( $attributes );
345 }
346
347 /**
348 * Assign and return the first satisfied route (if any) as the current one for the given request.
349 *
350 * @param RequestInterface $request
351 * @return RouteInterface|null
352 */
353 public function execute( $request ) {
354 $routes = $this->getRoutes();
355
356 foreach ( $routes as $route ) {
357 if ( $route->isSatisfied( $request ) ) {
358 $this->setCurrentRoute( $route );
359 return $route;
360 }
361 }
362
363 return null;
364 }
365
366 /**
367 * Get the url for a named route.
368 *
369 * @param string $name
370 * @param array $arguments
371 * @return string
372 */
373 public function getRouteUrl( $name, $arguments = [] ) {
374 $routes = $this->getRoutes();
375
376 foreach ( $routes as $route ) {
377 if ( $route->getAttribute( 'name' ) !== $name ) {
378 continue;
379 }
380
381 $condition = $route->getAttribute( 'condition' );
382
383 if ( ! $condition instanceof UrlableInterface ) {
384 throw new ConfigurationException(
385 'Route condition is not resolvable to a URL.'
386 );
387 }
388
389 return $condition->toUrl( $arguments );
390 }
391
392 throw new ConfigurationException( "No route registered with the name \"$name\"." );
393 }
394 }
395