1: <?php
2:
3: namespace Charcoal\App\Route;
4:
5: use InvalidArgumentException;
6:
7: // Dependency from 'charcoal-app'
8: use Charcoal\App\App;
9:
10: // Dependency from 'charcoal-config'
11: use Charcoal\Config\AbstractConfig;
12:
13: /**
14: * Base "Route" configuration.
15: */
16: class RouteConfig extends AbstractConfig
17: {
18: /**
19: * Route identifier/name
20: *
21: * @var string
22: */
23: private $ident;
24:
25: /**
26: * Route pattern
27: *
28: * @var string
29: */
30: private $route;
31:
32: /**
33: * HTTP methods supported by this route
34: *
35: * @var string[]
36: */
37: private $methods = [ 'GET' ];
38:
39: /**
40: * Response controller classname
41: *
42: * Should be the class-ident of an action, a script or a template controller.
43: *
44: * @var string
45: */
46: private $controller;
47:
48: /**
49: * Parent route groups
50: *
51: * @var string[]
52: */
53: private $groups = [];
54:
55: /**
56: * Set route identifier
57: *
58: * @param string $ident Route identifier.
59: * @throws InvalidArgumentException If the identifier is not a string.
60: * @return RouteConfig Chainable
61: */
62: public function setIdent($ident)
63: {
64: if (!is_string($ident)) {
65: throw new InvalidArgumentException(
66: 'Route identifier must be a string.'
67: );
68: }
69:
70: $this->ident = $ident;
71:
72: return $this;
73: }
74:
75: /**
76: * Get route identifier
77: *
78: * @return string
79: */
80: public function ident()
81: {
82: return $this->ident;
83: }
84:
85: /**
86: * Set route pattern.
87: *
88: * @param string $pattern Route pattern.
89: * @throws InvalidArgumentException If the pattern argument is not a string.
90: * @return RouteConfig Chainable
91: */
92: public function setRoute($pattern)
93: {
94: if (!is_string($pattern)) {
95: throw new InvalidArgumentException(
96: 'Route pattern must be a string.'
97: );
98: }
99:
100: $this->route = $pattern;
101:
102: return $this;
103: }
104:
105: /**
106: * Get route pattern
107: *
108: * @return string
109: */
110: public function route()
111: {
112: return $this->route;
113: }
114:
115: /**
116: * Set parent route groups
117: *
118: * @param string[]|RouteGroup[] $groups The parent route groups.
119: * @return RouteConfig Chainable
120: */
121: public function setGroups(array $groups)
122: {
123: $this->groups = [];
124:
125: foreach ($groups as $group) {
126: $this->addGroup($group);
127: }
128:
129: return $this;
130: }
131:
132: /**
133: * Add parent route group
134: *
135: * @param string|RouteGroup $group The parent route group.
136: * @throws InvalidArgumentException If the group is invalid.
137: * @return RouteConfig Chainable
138: */
139: public function addGroup($group)
140: {
141: if (!is_string($group)) {
142: throw new InvalidArgumentException(
143: 'Parent route group must be a string.'
144: );
145: }
146:
147: $this->groups[] = $group;
148:
149: return $this;
150: }
151:
152: /**
153: * Get parent route groups
154: *
155: * @return array
156: */
157: public function groups()
158: {
159: return $this->groups;
160: }
161:
162: /**
163: * Set route view controller classname
164: *
165: * @param string $controller Route controller name.
166: * @throws InvalidArgumentException If the route view controller is not a string.
167: * @return RouteConfig Chainable
168: */
169: public function setController($controller)
170: {
171: if (!is_string($controller)) {
172: throw new InvalidArgumentException(
173: 'Route view controller must be a string.'
174: );
175: }
176:
177: $this->controller = $controller;
178:
179: return $this;
180: }
181:
182: /**
183: * Get the view controller classname
184: *
185: * If not set, the `self::ident()` will be used by default.
186: *
187: * @return string
188: */
189: public function controller()
190: {
191: if (!isset($this->controller)) {
192: return $this->ident();
193: }
194:
195: return $this->controller;
196: }
197:
198: /**
199: * Set route methods
200: *
201: * @param string[] $methods The route's supported HTTP methods.
202: * @return RouteConfig Chainable
203: */
204: public function setMethods(array $methods)
205: {
206: $this->methods = [];
207:
208: foreach ($methods as $method) {
209: $this->addMethod($method);
210: }
211:
212: return $this;
213: }
214:
215: /**
216: * Add route HTTP method.
217: *
218: * @param string $method The route's supported HTTP method.
219: * @throws InvalidArgumentException If the HTTP method is invalid.
220: * @return RouteConfig Chainable
221: */
222: public function addMethod($method)
223: {
224: if (!is_string($method)) {
225: throw new InvalidArgumentException(
226: sprintf(
227: 'Unsupported HTTP method; must be a string, received %s',
228: (is_object($method) ? get_class($method) : gettype($method))
229: )
230: );
231: }
232:
233: // According to RFC, methods are defined in uppercase (See RFC 7231)
234: $method = strtoupper($method);
235:
236: $validHttpMethods = [
237: 'CONNECT',
238: 'DELETE',
239: 'GET',
240: 'HEAD',
241: 'OPTIONS',
242: 'PATCH',
243: 'POST',
244: 'PUT',
245: 'TRACE',
246: ];
247:
248: if (!in_array($method, $validHttpMethods)) {
249: throw new InvalidArgumentException(sprintf(
250: 'Unsupported HTTP method; must be one of "%s", received "%s"',
251: implode('","', $validHttpMethods),
252: $method
253: ));
254: }
255:
256: $this->methods[] = $method;
257:
258: return $this;
259: }
260:
261: /**
262: * Get route methods
263: *
264: * @return string[]
265: */
266: public function methods()
267: {
268: return $this->methods;
269: }
270: }
271: