Passed
Branch refactor/kernels (20f9a7)
by Atanas
01:42
created

Router::handle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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