Failed Conditions
Branch refactor/kernels (f9ae97)
by Atanas
01:58
created

Router::addGroupToStack()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 1
dl 0
loc 21
ccs 0
cts 12
cp 0
crap 6
rs 9.8333
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 WPEmerge\Requests\RequestInterface;
13
use WPEmerge\Routing\Conditions\ConditionFactory;
14
use WPEmerge\Routing\Conditions\ConditionInterface;
15
use WPEmerge\Routing\Conditions\HasUrlWhereInterface;
16
use WPEmerge\Routing\Conditions\InvalidRouteConditionException;
17
use WPEmerge\Support\Arr;
18
19
/**
20
 * Provide routing for site requests (i.e. all non-api requests).
21
 */
22
class Router implements HasRoutesInterface {
23
	use HasRoutesTrait {
24
		addRoute as traitAddRoute;
25
	}
26
27
	/**
28
	 * Condition factory.
29
	 *
30
	 * @var ConditionFactory
31
	 */
32
	protected $condition_factory = null;
33
34
	/**
35
	 * Current active route.
36
	 *
37
	 * @var RouteInterface
38
	 */
39
	protected $current_route = null;
40
41
	/**
42
	 * Group stack.
43
	 *
44
	 * @var array<array<string, mixed>>
45
	 */
46
	protected $group_stack = [];
47
48
	/**
49
	 * Constructor.
50
	 *
51
	 * @codeCoverageIgnore
52
	 * @param ConditionFactory      $condition_factory
53
	 */
54
	public function __construct( ConditionFactory $condition_factory ) {
55
		$this->condition_factory = $condition_factory;
56
	}
57
58
	/**
59
	 * Get the current route.
60
	 *
61
	 * @return RouteInterface
62
	 */
63
	public function getCurrentRoute() {
64
		return $this->current_route;
65
	}
66 1
67 1
	/**
68
	 * Set the current route.
69
	 *
70
	 * @param  RouteInterface
71
	 * @return void
72
	 */
73
	public function setCurrentRoute( RouteInterface $current_route ) {
74
		$this->current_route = $current_route;
75
	}
76 1
77 1
	/**
78 1
	 * Add a group to the group stack, merging all previous attributes.
79
	 *
80
	 * @param array<string, mixed> $attributes
81
	 * @return void
82
	 */
83
	protected function addGroupToStack( $attributes ) {
84
		$previous = Arr::last( $this->group_stack, null, [] );
85
86
		$condition = $this->condition_factory->merge(
87
			Arr::get( $previous, 'condition', '' ),
88
			Arr::get( $attributes, 'condition', '' )
89
		);
90
91
		$attributes = [
92
			'condition' => $condition !== null ? $condition : '',
93
			'where' => array_merge(
94
				Arr::get( $previous, 'where', [] ),
95
				Arr::get( $attributes, 'where', [] )
96
			),
97
			'middleware' => array_merge(
98
				(array) Arr::get( $previous, 'middleware', [] ),
99
				(array) Arr::get( $attributes, 'middleware', [] )
100
			),
101
		];
102
103
		$this->group_stack[] = $attributes;
104
	}
105
106
	/**
107
	 * Remove last group from the group stack.
108
	 *
109
	 * @return void
110
	 */
111
	protected function removeLastGroupFromStack() {
112
		array_pop( $this->group_stack );
113
	}
114
115
	/**
116
	 * Create a new route group.
117
	 *
118
	 * @param array<string, mixed> $attributes
119
	 * @param \Closure|string      $routes Closure or path to file.
120
	 * @return void
121
	 */
122
	public function group( $attributes, $routes ) {
123
		$this->addGroupToStack( $attributes );
124
125 1
		if ( is_string( $routes ) ) {
126 1
			require_once $routes;
127
		} else {
128 1
			$routes();
129
		}
130
131 1
		$this->removeLastGroupFromStack();
132
	}
133
134 1
	/**
135 1
	 * {@inheritDoc}
136
	 */
137
	public function makeRoute( $methods, $condition, $handler ) {
138
		if ( ! $condition instanceof ConditionInterface ) {
139
			try {
140 3
				$condition = $this->condition_factory->make( $condition );
141 3
			} catch ( InvalidRouteConditionException $e ) {
142
				throw new InvalidRouteConditionException( 'Route condition is not a valid route string or condition.' );
143 2
			}
144 1
		}
145 1
146
		return new Route( $methods, $condition, $handler );
147
	}
148
149 2
	/**
150
	 * {@inheritDoc}
151
	 */
152
	public function addRoute( $route ) {
153
		$group = Arr::last( $this->group_stack, null, [] );
154
		$condition = $route->getCondition();
155 2
156 2
		if ( $condition instanceof HasUrlWhereInterface ) {
157 2
			$condition->setUrlWhere( array_merge(
158
				Arr::get( $group, 'where', [] ),
159 2
				$condition->getUrlWhere()
160 1
			) );
161 1
		}
162 1
163
		$condition = $this->condition_factory->merge(
164
			Arr::get( $group, 'condition', '' ),
165
			$condition
166 2
		);
167 2
168 2
		$route->setCondition( $condition );
169
170
		$route->setMiddleware( array_merge(
171 2
			Arr::get( $group, 'middleware', [] ),
172
			$route->getMiddleware()
173 2
		) );
174 2
175 2
		return $this->traitAddRoute( $route );
176
	}
177
178 2
	/**
179
	 * Handle ALL requests.
180
	 *
181
	 * @param  string|\Closure|null $handler
182
	 * @return RouteInterface
183
	 */
184
	public function all( $handler = null ) {
185
		// Match ANY request method.
186
		// Match ANY url.
187 1
		// By default, use built-in WordPress controller.
188
		return $this->any( '*', $handler );
189
	}
190
191 1
	/**
192
	 * Assign and return the first satisfied route (if any) as the current one for the given request.
193
	 *
194
	 * @param  RequestInterface $request
195
	 * @param  array            $arguments
196
	 * @return RouteInterface
197
	 */
198
	public function execute( $request, $arguments = [] ) {
199
		$routes = $this->getRoutes();
200
201 2
		foreach ( $routes as $route ) {
202 2
			if ( $route->isSatisfied( $request ) ) {
203
				$this->setCurrentRoute( $route );
204 2
				return $route;
205 2
			}
206 1
		}
207 2
208
		return null;
209
	}
210
}
211