Router::__call()   B
last analyzed

Complexity

Conditions 7
Paths 5

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 8.6026
c 0
b 0
f 0
cc 7
nc 5
nop 2
crap 7
1
<?php
2
namespace Intraxia\Jaxion\Http;
3
4
use Intraxia\Jaxion\Contract\Core\HasActions;
5
use InvalidArgumentException;
6
7
/**
8
 * Class Router
9
 *
10
 * A simplified interface for registering routes with the WP-API.
11
 *
12
 * @package Intraxia\Jaxion
13
 * @subpackage Http
14
 *
15
 * @method Endpoint get(string $route, callable $callback, array $options = array())
16
 * @method Endpoint post(string $route, callable $callback, array $options = array())
17
 * @method Endpoint put(string $route, callable $callback, array $options = array())
18
 * @method Endpoint patch(string $route, callable $callback, array $options = array())
19
 * @method Endpoint delete(string $route, callable $callback, array $options = array())
20
 * @method Endpoint editable(string $route, callable $callback, array $options = array())
21
 * @method Endpoint all(string $route, callable $callback, array $options = array())
22
 */
23
class Router implements HasActions {
24
	/**
25
	 * Resource's vendor prefix.
26
	 *
27
	 * @var string
28
	 */
29
	protected $vendor;
30
31
	/**
32
	 * Resource's version.
33
	 *
34
	 * @var int
35
	 */
36
	protected $version;
37
38
	/**
39
	 * Valid methods and their HTTP verb(s).
40
	 *
41
	 * @var array
42
	 */
43
	private $methods = array(
44
		'get'      => 'GET',
45
		'post'     => 'POST',
46
		'put'      => 'PUT',
47
		'patch'    => 'PATCH',
48
		'delete'   => 'DELETE',
49
		'editable' => 'POST, PUT, PATCH',
50
		'all'      => 'GET, POST, PUT, PATCH, DELETE',
51
	);
52
53
	/**
54
	 * Endpoints registered for the resource.
55
	 *
56
	 * @var Endpoint[]
57
	 */
58
	protected $endpoints = array();
59
60
	/**
61
	 * Returns all the resource endpoints.
62
	 *
63
	 * @return Endpoint[]
64
	 */
65 12
	public function get_endpoints() {
66 12
		return $this->endpoints;
67
	}
68
69
	/**
70
	 * Sets the resource's vendor prefix.
71
	 *
72
	 * @param string $vendor
73
	 *
74
	 * @return $this
75
	 */
76 63
	public function set_vendor( $vendor ) {
77 63
		$this->vendor = $vendor;
78
79 63
		return $this;
80
	}
81
82
	/**
83
	 * Sets the resource's version.
84
	 *
85
	 * @param int $version
86
	 *
87
	 * @return $this
88
	 */
89 63
	public function set_version( $version ) {
90 63
		$this->version = $version;
91
92 63
		return $this;
93
	}
94
95
	/**
96
	 * Registers all of the routes with the WP-API.
97
	 *
98
	 * Runs on the `rest_api_init` hook. Registers all of the routes loaded
99
	 * on the router into the WordPress REST API.
100
	 *
101
	 * @throws VendorNotSetException
102
	 * @throws VersionNotSetException
103
	 */
104 45
	public function register() {
105 45
		if ( ! $this->vendor ) {
106 3
			throw new VendorNotSetException;
107
		}
108
109 42
		if ( ! $this->version ) {
110 3
			throw new VersionNotSetException;
111
		}
112
113 39
		foreach ( $this->endpoints as $endpoint ) {
114 39
			register_rest_route(
115 39
				$this->get_namespace(),
116 39
				$endpoint->get_route(),
117 39
				$endpoint->get_options()
118 26
			);
119 26
		}
120 39
	}
121
122
	/**
123
	 * Registers a set of routes with a shared set of options.
124
	 *
125
	 * Allows you to group routes together with shared set of options, including
126
	 * a route prefix, shared guards, and common parameter validation or sanitization.
127
	 *
128
	 * @param array    $options
129
	 * @param callable $callback
130
	 */
131 12
	public function group( array $options, $callback ) {
132 12
		$router = new static;
133
134 12
		call_user_func( $callback, $router );
135
136 12
		foreach ( $router->get_endpoints() as $endpoint ) {
137 12
			$this->endpoints[] = $this->set_options( $endpoint, $options );
138 6
		}
139 9
	}
140
141
	/**
142
	 * Magic __call method.
143
	 *
144
	 * All of the endpoints registration method calls pass through here. This validates whether the method
145
	 * is a valid endpoint type to register, and creates a new endpoint with the passed options.
146
	 *
147
	 * @param string $name
148
	 * @param array  $arguments
149
	 *
150
	 * @return Endpoint
151
	 *
152
	 * @throws UnknownMethodException
153
	 * @throws MissingArgumentException
154
	 * @throws InvalidArgumentException
155
	 */
156 57
	public function __call( $name, $arguments ) {
157 57
		if ( ! in_array( $name, array_keys( $this->methods ) ) ) {
158 3
			throw new UnknownMethodException;
159
		}
160
161
		// array_merge ensures we have 3 elements
162 54
		list( $route, $callback, $options ) = array_merge( $arguments, array( null, null, null ) );
163
164 54
		if ( ! $route || ! $callback ) {
165 6
			throw new MissingArgumentException;
166
		}
167
168 48
		if ( ! is_callable( $callback ) ) {
169 3
			throw new InvalidArgumentException;
170
		}
171
172 45
		$endpoint = new Endpoint( $route, $this->methods[ $name ], $callback );
173
174 42
		if ( $options && is_array( $options ) ) {
175 9
			$endpoint = $this->set_options( $endpoint, $options );
176 6
		}
177
178 42
		return $this->endpoints[] = $endpoint;
179
	}
180
181
	/**
182
	 * Sets the passed options on the endpoint.
183
	 *
184
	 * Only sets endpoints matching setters in the Endpoint class.
185
	 *
186
	 * @param Endpoint $endpoint
187
	 * @param array    $options
188
	 *
189
	 * @return Endpoint
190
	 * @throws MalformedRouteException
191
	 */
192 21
	protected function set_options( Endpoint $endpoint, array $options ) {
193 21
		if ( isset( $options['guard'] ) ) {
194 6
			$endpoint->set_guard( $options['guard'] );
195 4
		}
196
197 21
		if ( isset( $options['filter'] ) ) {
198 6
			$endpoint->set_filter( $options['filter'] );
199 4
		}
200
201 21
		if ( isset( $options['prefix'] ) ) {
202 6
			$endpoint->set_prefix( $options['prefix'] );
203 2
		}
204
205 18
		return $endpoint;
206
	}
207
208
	/**
209
	 * Generates the resource's namespace.
210
	 *
211
	 * @return string
212
	 */
213 39
	protected function get_namespace() {
214 39
		return $this->vendor . '/v' . $this->version;
215
	}
216
217
	/**
218
	 * {@inheritDoc}
219
	 *
220
	 * @return array[]
221
	 */
222
	public function action_hooks() {
223
		return array(
224
			array(
225
				'method' => 'register',
226
				'hook'   => 'rest_api_init',
227
			),
228
		);
229
	}
230
}
231