Route::assert_properties_are_valid()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 6
c 1
b 0
f 1
nc 2
nop 2
dl 0
loc 12
rs 9.4285
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie\Routing;
13
14
use ICanBoogie\Accessor\AccessorTrait;
15
16
/**
17
 * A route.
18
 *
19
 * @property-read Pattern $pattern The pattern of the route.
20
 * @property-read string $controller The class name of the controller.
21
 * @property-read string|null $action Controller action.
22
 * @property-read string $id Route identifier.
23
 * @property-read string|null $location Redirection destination.
24
 * @property-read string|array|null $via The supported HTTP methods.
25
 * @property-read string $url The contextualized URL of the route.
26
 * @property-read string $absolute_url The contextualized absolute URL of the route.
27
 * @property-read mixed $formatting_value The value used to format the route.
28
 * @property-read bool $has_formatting_value `true` if the route has a formatting value, `false` otherwise.
29
 */
30
class Route
31
{
32
	use AccessorTrait;
33
34
	static protected $invalid_construct_properties = [ 'formatting_value', 'url', 'absolute_url' ];
35
36
	/**
37
	 * Creates a new {@link Route} instance from a route definition.
38
	 *
39
	 * @param array $definition
40
	 *
41
	 * @return static
42
	 */
43
	static public function from(array $definition)
44
	{
45
		$class = get_called_class();
46
47
		if (isset($definition[RouteDefinition::CONSTRUCTOR]))
48
		{
49
			$class = $definition[RouteDefinition::CONSTRUCTOR];
50
		}
51
52
		return new $class($definition[RouteDefinition::PATTERN], $definition);
53
	}
54
55
	/**
56
	 * Pattern of the route.
57
	 *
58
	 * @var Pattern
59
	 */
60
	private $pattern;
61
62
	protected function get_pattern()
63
	{
64
		return $this->pattern;
65
	}
66
67
	/**
68
	 * Controller's class name or function.
69
	 *
70
	 * @var string
71
	 */
72
	private $controller;
73
74
	protected function get_controller()
75
	{
76
		return $this->controller;
77
	}
78
79
	/**
80
	 * Controller action.
81
	 *
82
	 * @var string
83
	 */
84
	private $action;
85
86
	protected function get_action()
87
	{
88
		return $this->action;
89
	}
90
91
	/**
92
	 * Identifier of the route.
93
	 *
94
	 * @var string
95
	 */
96
	private $id;
97
98
	protected function get_id()
99
	{
100
		return $this->id;
101
	}
102
103
	/**
104
	 * Redirect location.
105
	 *
106
	 * If the property is defined the route is considered an alias.
107
	 *
108
	 * @var string
109
	 */
110
	private $location;
111
112
	protected function get_location()
113
	{
114
		return $this->location;
115
	}
116
117
	/**
118
	 * Request methods accepted by the route.
119
	 *
120
	 * @var string
121
	 */
122
	private $via;
123
124
	protected function get_via()
125
	{
126
		return $this->via;
127
	}
128
129
	/**
130
	 * Formatting value.
131
	 *
132
	 * @var mixed
133
	 */
134
	private $formatting_value;
135
136
	/**
137
	 * Returns the formatting value.
138
	 *
139
	 * @return mixed
140
	 */
141
	protected function get_formatting_value()
142
	{
143
		return $this->formatting_value;
144
	}
145
146
	/**
147
	 * Whether the route has a formatting value.
148
	 *
149
	 * @return bool `true` if the route has a formatting value, `false` otherwise.
150
	 */
151
	protected function get_has_formatting_value()
152
	{
153
		return $this->formatting_value !== null;
154
	}
155
156
	/**
157
	 * Returns relative URL.
158
	 *
159
	 * @return string
160
	 */
161
	protected function get_url()
162
	{
163
		return $this->format($this->formatting_value)->url;
164
	}
165
166
	/**
167
	 * Returns absolute URL.
168
	 *
169
	 * @return string
170
	 */
171
	protected function get_absolute_url()
172
	{
173
		return $this->format($this->formatting_value)->absolute_url;
174
	}
175
176
	/**
177
	 * Initializes the {@link $pattern} property and the properties provided.
178
	 *
179
	 * @param string $pattern
180
	 * @param array $properties
181
	 */
182
	public function __construct($pattern, array $properties)
183
	{
184
		$this->pattern = Pattern::from($pattern);
185
186
		unset($properties['pattern']);
187
188
		$this->assert_properties_are_valid($properties, self::$invalid_construct_properties);
189
190
		foreach ($properties as $property => $value)
191
		{
192
			$this->$property = $value;
193
		}
194
	}
195
196
	public function __clone()
197
	{
198
		$this->formatting_value = null;
199
	}
200
201
	/**
202
	 * Formats a route into a relative URL using its formatting value.
203
	 *
204
	 * @return string
205
	 */
206
	public function __toString()
207
	{
208
		return (string) $this->url;
209
	}
210
211
	/**
212
	 * Asserts that properties are valid.
213
	 *
214
	 * @param array $properties
215
	 * @param array $invalid
216
	 *
217
	 * @throws \InvalidArgumentException if a property is not valid.
218
	 */
219
	protected function assert_properties_are_valid(array $properties, array $invalid)
220
	{
221
		$invalid = array_combine($invalid, $invalid);
222
		$invalid = array_intersect_key($properties, $invalid);
223
224
		if (!$invalid)
225
		{
226
			return;
227
		}
228
229
		throw new \InvalidArgumentException("Invalid construct property: " . implode(', ', $invalid));
230
	}
231
232
	/**
233
	 * Formats the route with the specified values.
234
	 *
235
	 * Note: The formatting of the route is deferred to its {@link Pattern} instance.
236
	 *
237
	 * @param object|array|null $values
238
	 *
239
	 * @return FormattedRoute
240
	 */
241
	public function format($values = null)
242
	{
243
		return new FormattedRoute($this->pattern->format($values), $this);
244
	}
245
246
	/**
247
	 * Assigns a formatting value to a route.
248
	 *
249
	 * @param mixed $formatting_value A formatting value.
250
	 *
251
	 * @return Route A new route bound to a formatting value.
252
	 */
253
	public function assign($formatting_value)
254
	{
255
		$clone = clone $this;
256
257
		#
258
		# We could write directly to `formatting_value`, but since it is marked _read-only_
259
		# we resort to shenanigans to keep the IDE happy :)
260
		#
261
262
		$ref = &$clone->formatting_value;
263
		$ref = $formatting_value;
264
265
		return $clone;
266
	}
267
}
268