This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Copyright 2016 - 2018, Cake Development Corporation (http://cakedc.com) |
||
4 | * |
||
5 | * Licensed under The MIT License |
||
6 | * Redistributions of files must retain the above copyright notice. |
||
7 | * |
||
8 | * @copyright Copyright 2016 - 2018, Cake Development Corporation (http://cakedc.com) |
||
9 | * @license MIT License (http://www.opensource.org/licenses/mit-license.php) |
||
10 | */ |
||
11 | |||
12 | namespace CakeDC\Api\Service; |
||
13 | |||
14 | use CakeDC\Api\Exception\ValidationException; |
||
15 | use CakeDC\Api\Routing\ApiRouter; |
||
16 | use CakeDC\Api\Service\Action\DummyAction; |
||
17 | use CakeDC\Api\Service\Action\Result; |
||
18 | use CakeDC\Api\Service\Exception\MissingActionException; |
||
19 | use CakeDC\Api\Service\Exception\MissingParserException; |
||
20 | use CakeDC\Api\Service\Exception\MissingRendererException; |
||
21 | use CakeDC\Api\Service\Renderer\BaseRenderer; |
||
22 | use CakeDC\Api\Service\RequestParser\BaseParser; |
||
23 | |||
24 | use Cake\Core\App; |
||
25 | use Cake\Core\Configure; |
||
26 | use Cake\Datasource\Exception\RecordNotFoundException; |
||
27 | |||
28 | use Cake\Event\EventDispatcherInterface; |
||
29 | use Cake\Event\EventDispatcherTrait; |
||
30 | use Cake\Event\EventListenerInterface; |
||
31 | use Cake\Event\EventManager; |
||
32 | use Cake\Http\Response; |
||
33 | use Cake\Http\ServerRequest; |
||
34 | use Cake\Routing\RouteBuilder; |
||
35 | use Cake\Utility\Hash; |
||
36 | use Cake\Utility\Inflector; |
||
37 | use Exception; |
||
38 | |||
39 | /** |
||
40 | * Class Service |
||
41 | */ |
||
42 | abstract class Service implements EventListenerInterface, EventDispatcherInterface |
||
43 | { |
||
44 | use EventDispatcherTrait; |
||
45 | |||
46 | /** |
||
47 | * Extensions to load and attach to listener |
||
48 | * |
||
49 | * @var array |
||
50 | */ |
||
51 | public $extensions = []; |
||
52 | |||
53 | /** |
||
54 | * Actions routes description map, indexed by action name. |
||
55 | * |
||
56 | * @var array |
||
57 | */ |
||
58 | protected $_actions = []; |
||
59 | |||
60 | /** |
||
61 | * Actions classes map, indexed by action name. |
||
62 | * |
||
63 | * @var array |
||
64 | */ |
||
65 | protected $_actionsClassMap = []; |
||
66 | |||
67 | /** |
||
68 | * Service url acceptable extensions list. |
||
69 | * |
||
70 | * @var array |
||
71 | */ |
||
72 | protected $_routeExtensions = ['json']; |
||
73 | |||
74 | /** |
||
75 | * |
||
76 | * |
||
77 | * @var string |
||
78 | */ |
||
79 | protected $_routePrefix = ''; |
||
80 | |||
81 | /** |
||
82 | * Service name |
||
83 | * |
||
84 | * @var string |
||
85 | */ |
||
86 | protected $_name = null; |
||
87 | |||
88 | /** |
||
89 | * Service version. |
||
90 | * |
||
91 | * @var int |
||
92 | */ |
||
93 | protected $_version; |
||
94 | |||
95 | /** |
||
96 | * Parser class to process the HTTP request. |
||
97 | * |
||
98 | * @var BaseParser |
||
99 | */ |
||
100 | protected $_parser; |
||
101 | |||
102 | /** |
||
103 | * Renderer class to build the HTTP response. |
||
104 | * |
||
105 | * @var BaseRenderer |
||
106 | */ |
||
107 | protected $_renderer; |
||
108 | |||
109 | /** |
||
110 | * The parser class. |
||
111 | * |
||
112 | * @var string |
||
113 | */ |
||
114 | protected $_parserClass = null; |
||
115 | |||
116 | /** |
||
117 | * The Renderer class. |
||
118 | * |
||
119 | * @var string |
||
120 | */ |
||
121 | protected $_rendererClass = null; |
||
122 | |||
123 | /** |
||
124 | * Dependent services names list |
||
125 | * |
||
126 | * @var array<string> |
||
127 | */ |
||
128 | protected $_innerServices = []; |
||
129 | |||
130 | /** |
||
131 | * Parent service instance. |
||
132 | * |
||
133 | * @var Service |
||
134 | */ |
||
135 | protected $_parentService; |
||
136 | |||
137 | /** |
||
138 | * Service Action Result object. |
||
139 | * |
||
140 | * @var Result |
||
141 | */ |
||
142 | protected $_result; |
||
143 | |||
144 | /** |
||
145 | * Base url for service. |
||
146 | * |
||
147 | * @var string |
||
148 | */ |
||
149 | protected $_baseUrl; |
||
150 | |||
151 | /** |
||
152 | * Request |
||
153 | * |
||
154 | * @var \Cake\Http\ServerRequest |
||
155 | */ |
||
156 | protected $_request; |
||
157 | |||
158 | /** |
||
159 | * Request |
||
160 | * |
||
161 | * @var \Cake\Http\Response |
||
162 | */ |
||
163 | protected $_response; |
||
164 | |||
165 | /** |
||
166 | * @var string |
||
167 | */ |
||
168 | protected $_corsSuffix = '_cors'; |
||
169 | |||
170 | /** |
||
171 | * Extension registry. |
||
172 | * |
||
173 | * @var \CakeDC\Api\Service\ExtensionRegistry |
||
174 | */ |
||
175 | protected $_extensions; |
||
176 | |||
177 | /** |
||
178 | * Service constructor. |
||
179 | * |
||
180 | * @param array $config Service configuration. |
||
181 | */ |
||
182 | 140 | public function __construct(array $config = []) |
|
183 | { |
||
184 | 140 | if (isset($config['request'])) { |
|
185 | 140 | $this->setRequest($config['request']); |
|
186 | 140 | } |
|
187 | 140 | if (isset($config['response'])) { |
|
188 | 140 | $this->setResponse($config['response']); |
|
189 | 140 | } |
|
190 | 140 | if (isset($config['baseUrl'])) { |
|
191 | 93 | $this->_baseUrl = $config['baseUrl']; |
|
192 | 93 | } |
|
193 | 140 | if (isset($config['service'])) { |
|
194 | 111 | $this->setName($config['service']); |
|
195 | 111 | } |
|
196 | 140 | if (isset($config['version'])) { |
|
197 | $this->setVersion($config['version']); |
||
198 | } |
||
199 | 140 | if (isset($config['classMap'])) { |
|
200 | 1 | $this->_actionsClassMap = Hash::merge($this->_actionsClassMap, $config['classMap']); |
|
201 | 1 | } |
|
202 | |||
203 | 140 | if (!empty($config['Extension'])) { |
|
204 | $this->extensions = (Hash::merge($this->extensions, $config['Extension'])); |
||
205 | } |
||
206 | 140 | $extensionRegistry = $eventManager = null; |
|
207 | 140 | if (!empty($config['eventManager'])) { |
|
208 | $eventManager = $config['eventManager']; |
||
209 | } |
||
210 | 140 | $this->_eventManager = $eventManager ?: new EventManager(); |
|
211 | |||
212 | 140 | $this->initialize(); |
|
213 | 140 | $this->_initializeParser($config); |
|
214 | 140 | $this->_initializeRenderer($config); |
|
215 | 140 | $this->_eventManager->on($this); |
|
216 | 140 | $this->setExtensions($extensionRegistry); |
|
0 ignored issues
–
show
|
|||
217 | 140 | $this->_loadExtensions(); |
|
218 | 140 | } |
|
219 | |||
220 | /** |
||
221 | * Initialize method |
||
222 | * |
||
223 | * @return void |
||
224 | */ |
||
225 | 140 | public function initialize() |
|
226 | { |
||
227 | 140 | if ($this->_name === null) { |
|
228 | 46 | $className = (new \ReflectionClass($this))->getShortName(); |
|
229 | 46 | $this->setName(Inflector::underscore(str_replace('Service', '', $className))); |
|
230 | 46 | } |
|
231 | 140 | } |
|
232 | |||
233 | /** |
||
234 | * Gets service name. |
||
235 | * |
||
236 | * @return string |
||
237 | */ |
||
238 | 139 | public function getName() |
|
239 | { |
||
240 | 139 | return $this->_name; |
|
241 | } |
||
242 | |||
243 | /** |
||
244 | * Sets service name. |
||
245 | * |
||
246 | * @param string $name Service name. |
||
247 | * @return $this |
||
248 | */ |
||
249 | 140 | public function setName($name) |
|
250 | { |
||
251 | 140 | $this->_name = $name; |
|
252 | |||
253 | 140 | return $this; |
|
254 | } |
||
255 | |||
256 | /** |
||
257 | * Get and set service name. |
||
258 | * |
||
259 | * @param string $name Service name. |
||
260 | * @deprecated 3.4.0 Use setName()/getName() instead. |
||
261 | * @return string |
||
262 | */ |
||
263 | public function name($name = null) |
||
264 | { |
||
265 | deprecationWarning( |
||
266 | 'Service::name() is deprecated. ' . |
||
267 | 'Use Service::setName()/getName() instead.' |
||
268 | ); |
||
269 | |||
270 | if ($name !== null) { |
||
271 | return $this->setName($name); |
||
272 | } |
||
273 | |||
274 | return $this->getName(); |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Gets service version number. |
||
279 | * |
||
280 | * @return int |
||
281 | */ |
||
282 | 81 | public function getVersion() |
|
283 | { |
||
284 | 81 | return $this->_version; |
|
285 | } |
||
286 | |||
287 | /** |
||
288 | * Sets service version. |
||
289 | * |
||
290 | * @param int $version Version number. |
||
291 | * @return void |
||
292 | */ |
||
293 | public function setVersion($version) |
||
294 | { |
||
295 | $this->_version = $version; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Get and set service version. |
||
300 | * |
||
301 | * @param int $version Version number. |
||
302 | * @deprecated 3.4.0 Use setVersion()/getVersion() instead. |
||
303 | * @return int|$this |
||
304 | */ |
||
305 | public function version($version = null) |
||
306 | { |
||
307 | deprecationWarning( |
||
308 | 'Service::version() is deprecated. ' . |
||
309 | 'Use Service::setVersion()/getVersion() instead.' |
||
310 | ); |
||
311 | |||
312 | if ($version !== null) { |
||
313 | $this->setVersion($version); |
||
314 | } |
||
315 | |||
316 | return $this->getVersion(); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Gets the service parser. |
||
321 | * |
||
322 | * @return BaseParser |
||
323 | */ |
||
324 | 66 | public function getParser() |
|
325 | { |
||
326 | 66 | return $this->_parser; |
|
327 | } |
||
328 | |||
329 | /** |
||
330 | * Sets the service parser. |
||
331 | * |
||
332 | * @param BaseParser $parser A Parser instance. |
||
333 | * @return $this |
||
334 | */ |
||
335 | public function setParser(BaseParser $parser) |
||
336 | { |
||
337 | $this->_parser = $parser; |
||
338 | |||
339 | return $this; |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * Service parser configuration method. |
||
344 | * |
||
345 | * @param BaseParser $parser A Parser instance. |
||
346 | * @deprecated 3.4.0 Use getParser()/setParser() instead. |
||
347 | * @return BaseParser|$this |
||
348 | */ |
||
349 | public function parser(BaseParser $parser = null) |
||
350 | { |
||
351 | deprecationWarning( |
||
352 | 'Service::parser() is deprecated. ' . |
||
353 | 'Use Service::setParser()/getParser() instead.' |
||
354 | ); |
||
355 | |||
356 | if ($parser !== null) { |
||
357 | return $this->setParser($parser); |
||
358 | } |
||
359 | |||
360 | return $this->getParser(); |
||
361 | } |
||
362 | |||
363 | /** |
||
364 | * Gets the Request. |
||
365 | * |
||
366 | * @return \Cake\Http\ServerRequest |
||
367 | */ |
||
368 | 123 | public function getRequest() |
|
369 | { |
||
370 | 123 | return $this->_request; |
|
371 | } |
||
372 | |||
373 | /** |
||
374 | * Sets the Request. |
||
375 | * |
||
376 | * @param \Cake\Http\ServerRequest $request A Request object. |
||
377 | * @return void |
||
378 | */ |
||
379 | 140 | public function setRequest(ServerRequest $request) |
|
380 | { |
||
381 | 140 | $this->_request = $request; |
|
382 | 140 | } |
|
383 | |||
384 | /** |
||
385 | * Get and set request. |
||
386 | * |
||
387 | * @param \Cake\Http\ServerRequest $request A Request object. |
||
388 | * @deprecated 3.4.0 Use getRequest()/setRequest() instead. |
||
389 | * @return \Cake\Http\ServerRequest|$this |
||
390 | */ |
||
391 | public function request($request = null) |
||
392 | { |
||
393 | deprecationWarning( |
||
394 | 'Service::request() is deprecated. ' . |
||
395 | 'Use Service::setRequest()/getRequest() instead.' |
||
396 | ); |
||
397 | |||
398 | if ($request !== null) { |
||
399 | $this->setRequest($request); |
||
400 | } |
||
401 | |||
402 | return $this->getRequest(); |
||
403 | } |
||
404 | |||
405 | /** |
||
406 | * Get the service route scopes and their connected routes. |
||
407 | * |
||
408 | * @return array |
||
409 | */ |
||
410 | 3 | public function routes() |
|
411 | { |
||
412 | return $this->_routesWrapper(function () { |
||
413 | 3 | return ApiRouter::routes(); |
|
414 | 3 | }); |
|
415 | } |
||
416 | |||
417 | /** |
||
418 | * @param callable $callable Wrapped router instance. |
||
419 | * @return mixed |
||
420 | */ |
||
421 | 65 | protected function _routesWrapper(callable $callable) |
|
422 | { |
||
423 | 65 | $this->resetRoutes(); |
|
424 | 65 | $this->loadRoutes(); |
|
425 | 65 | ApiRouter::$initialized = true; |
|
426 | 65 | $result = $callable(); |
|
427 | 64 | $this->resetRoutes(); |
|
428 | |||
429 | 64 | return $result; |
|
430 | } |
||
431 | |||
432 | /** |
||
433 | * Reset to default application routes. |
||
434 | * |
||
435 | * @return void |
||
436 | */ |
||
437 | 65 | public function resetRoutes() |
|
438 | { |
||
439 | 65 | ApiRouter::reload(); |
|
440 | 65 | } |
|
441 | |||
442 | /** |
||
443 | * Initialize service level routes |
||
444 | * |
||
445 | * @return void |
||
446 | */ |
||
447 | 8 | public function loadRoutes() |
|
448 | { |
||
449 | 8 | $defaultOptions = $this->routerDefaultOptions(); |
|
450 | ApiRouter::scope('/', $defaultOptions, function (RouteBuilder $routes) use ($defaultOptions) { |
||
451 | 8 | if (is_array($this->_routeExtensions)) { |
|
452 | 8 | $routes->setExtensions($this->_routeExtensions); |
|
453 | 8 | } |
|
454 | 8 | if (!empty($defaultOptions['map'])) { |
|
455 | 8 | $routes->resources($this->getName(), $defaultOptions); |
|
456 | 8 | } |
|
457 | 8 | }); |
|
458 | 8 | } |
|
459 | |||
460 | /** |
||
461 | * Build router settings. |
||
462 | * This implementation build action map for resource routes based on Service actions. |
||
463 | * |
||
464 | * @return array |
||
465 | */ |
||
466 | 64 | public function routerDefaultOptions() |
|
467 | { |
||
468 | 64 | $mapList = []; |
|
469 | 64 | foreach ($this->_actions as $alias => $map) { |
|
470 | 43 | if (is_numeric($alias)) { |
|
471 | $alias = $map; |
||
472 | $map = []; |
||
473 | } |
||
474 | 43 | $mapCors = false; |
|
475 | 43 | if (!empty($map['mapCors'])) { |
|
476 | 9 | $mapCors = $map['mapCors']; |
|
477 | 9 | unset($map['mapCors']); |
|
478 | 9 | } |
|
479 | 43 | $mapList[$alias] = $map; |
|
480 | 43 | $mapList[$alias] += ['method' => 'GET', 'path' => '', 'action' => $alias]; |
|
481 | 43 | if ($mapCors) { |
|
482 | 9 | $map['method'] = 'OPTIONS'; |
|
483 | 9 | $map += ['path' => '', 'action' => $alias . $this->_corsSuffix]; |
|
484 | 9 | $mapList[$alias . $this->_corsSuffix] = $map; |
|
485 | 9 | } |
|
486 | 64 | } |
|
487 | |||
488 | return [ |
||
489 | 'map' => $mapList |
||
490 | 64 | ]; |
|
491 | } |
||
492 | |||
493 | /** |
||
494 | * Finds URL for specified action. |
||
495 | * |
||
496 | * Returns an URL pointing to a combination of controller and action. |
||
497 | * |
||
498 | * @param string|array|null $route An array specifying any of the following: |
||
499 | * 'controller', 'action', 'plugin' additionally, you can provide routed |
||
500 | * elements or query string parameters. If string it can be name any valid url |
||
501 | * string. |
||
502 | * @return string Full translated URL with base path. |
||
503 | * @throws \Cake\Core\Exception\Exception When the route name is not found |
||
504 | */ |
||
505 | public function routeUrl($route) |
||
506 | { |
||
507 | return $this->_routesWrapper(function () use ($route) { |
||
508 | return ApiRouter::url($route); |
||
509 | }); |
||
510 | } |
||
511 | |||
512 | /** |
||
513 | * Reverses a parsed parameter array into a string. |
||
514 | * |
||
515 | * @param \Cake\Http\ServerRequest|array $params The params array or |
||
516 | * Cake\Http\ServerRequest object that needs to be reversed. |
||
517 | * @return string The string that is the reversed result of the array |
||
518 | */ |
||
519 | 13 | public function routeReverse($params) |
|
520 | { |
||
521 | return $this->_routesWrapper(function () use ($params) { |
||
522 | try { |
||
523 | 13 | return ApiRouter::reverse($params); |
|
524 | 1 | } catch (Exception $e) { |
|
525 | 1 | return null; |
|
526 | } |
||
527 | 13 | }); |
|
528 | } |
||
529 | |||
530 | /** |
||
531 | * Dispatch service call. |
||
532 | * |
||
533 | * @return \CakeDC\Api\Service\Action\Result |
||
534 | */ |
||
535 | 56 | public function dispatch() |
|
536 | { |
||
537 | try { |
||
538 | 56 | $result = $this->_dispatch(); |
|
539 | |||
540 | 52 | if ($result instanceof Result) { |
|
541 | $this->setResult($result); |
||
542 | } else { |
||
543 | 52 | $this->getResult()->setData($result); |
|
544 | 52 | $this->getResult()->setCode(200); |
|
545 | } |
||
546 | 56 | } catch (RecordNotFoundException $e) { |
|
547 | 6 | $this->getResult()->setCode(404); |
|
548 | 6 | $this->getResult()->setException($e); |
|
549 | 8 | } catch (ValidationException $e) { |
|
550 | 1 | $this->getResult()->setCode(422); |
|
551 | 1 | $this->getResult()->setException($e); |
|
552 | 2 | } catch (Exception $e) { |
|
553 | 1 | $code = $e->getCode(); |
|
554 | 1 | if (!is_int($code) || $code < 100 || $code >= 600) { |
|
555 | $this->getResult()->setCode(500); |
||
556 | } |
||
557 | 1 | $this->getResult()->setException($e); |
|
558 | } |
||
559 | 56 | $this->dispatchEvent('Service.afterDispatch', ['service' => $this]); |
|
560 | |||
561 | 56 | return $this->getResult(); |
|
562 | } |
||
563 | |||
564 | /** |
||
565 | * Dispatch service call through callbacks and action. |
||
566 | * |
||
567 | * @return Result|mixed |
||
568 | */ |
||
569 | 56 | protected function _dispatch() |
|
570 | { |
||
571 | 56 | $event = $this->dispatchEvent('Service.beforeDispatch', ['service' => $this]); |
|
572 | 56 | if ($event->result instanceof Result) { |
|
573 | return $event->result; |
||
574 | } |
||
575 | |||
576 | 56 | $action = $this->buildAction(); |
|
577 | 56 | $this->dispatchEvent('Service.beforeProcess', ['service' => $this, 'action' => $this]); |
|
578 | 56 | if ($event->result instanceof Result) { |
|
579 | return $event->result; |
||
580 | } |
||
581 | |||
582 | 56 | return $action->process(); |
|
583 | } |
||
584 | |||
585 | /** |
||
586 | * Build action instance |
||
587 | * |
||
588 | * @return \CakeDC\Api\Service\Action\Action |
||
589 | * @throws Exception |
||
590 | */ |
||
591 | 64 | public function buildAction() |
|
592 | { |
||
593 | 64 | $route = $this->parseRoute($this->getBaseUrl()); |
|
594 | 63 | if (empty($route)) { |
|
595 | throw new MissingActionException('Invalid Action Route:' . $this->getBaseUrl()); // InvalidActionException |
||
596 | } |
||
597 | 63 | $service = null; |
|
598 | 63 | $serviceName = Inflector::underscore($route['controller']); |
|
599 | 63 | if ($serviceName == $this->getName()) { |
|
600 | 54 | $service = $this; |
|
601 | 54 | } |
|
602 | 63 | if (in_array($serviceName, $this->_innerServices)) { |
|
603 | $options = [ |
||
604 | 9 | 'version' => $this->getVersion(), |
|
605 | 9 | 'request' => $this->getRequest(), |
|
606 | 9 | 'response' => $this->getResponse(), |
|
607 | 9 | 'refresh' => true, |
|
608 | 9 | ]; |
|
609 | 9 | $service = ServiceRegistry::getServiceLocator()->get($serviceName, $options); |
|
610 | 9 | $service->setParentService($this); |
|
611 | 9 | } |
|
612 | 63 | $action = $route['action']; |
|
613 | 63 | list($namespace, $serviceClass) = namespaceSplit(get_class($service)); |
|
614 | 63 | $actionPrefix = substr($serviceClass, 0, -7); |
|
615 | 63 | $actionClass = $namespace . '\\Action\\' . $actionPrefix . Inflector::camelize($action) . 'Action'; |
|
616 | 63 | if (class_exists($actionClass)) { |
|
617 | 2 | return $service->buildActionClass($actionClass, $route); |
|
618 | } |
||
619 | 61 | $actionsClassMap = $service->getActionsClassMap(); |
|
620 | 61 | if (array_key_exists($action, $actionsClassMap)) { |
|
621 | 61 | return $service->buildActionClass($actionsClassMap[$action], $route); |
|
622 | } |
||
623 | throw new MissingActionException(['class' => $actionClass]); |
||
624 | } |
||
625 | |||
626 | /** |
||
627 | * Parses given URL string. Returns 'routing' parameters for that URL. |
||
628 | * |
||
629 | * @param string $url URL to be parsed |
||
630 | * @return array Parsed elements from URL |
||
631 | * @throws \Cake\Routing\Exception\MissingRouteException When a route cannot be handled |
||
632 | */ |
||
633 | public function parseRoute($url) |
||
634 | { |
||
635 | 64 | return $this->_routesWrapper(function () use ($url) { |
|
636 | 64 | return ApiRouter::parseRequest(new ServerRequest([ |
|
637 | 64 | 'url' => $url, |
|
638 | 'environment' => [ |
||
639 | 64 | 'REQUEST_METHOD' => $this->_request->getEnv('REQUEST_METHOD') |
|
640 | 64 | ] |
|
641 | 64 | ])); |
|
642 | 64 | }); |
|
643 | } |
||
644 | |||
645 | /** |
||
646 | * Returns action class map. |
||
647 | * |
||
648 | * @return array |
||
649 | */ |
||
650 | 61 | public function getActionsClassMap() |
|
651 | { |
||
652 | 61 | return $this->_actionsClassMap; |
|
653 | } |
||
654 | |||
655 | /** |
||
656 | * Build base url |
||
657 | * |
||
658 | * @return string |
||
659 | */ |
||
660 | 65 | public function getBaseUrl() |
|
661 | { |
||
662 | 65 | if (!empty($this->_baseUrl)) { |
|
663 | 65 | return $this->_baseUrl; |
|
664 | } |
||
665 | |||
666 | $result = '/' . $this->getName(); |
||
667 | |||
668 | return $result; |
||
669 | } |
||
670 | |||
671 | /** |
||
672 | * Gets the parent service method. |
||
673 | * |
||
674 | * @return Service |
||
675 | */ |
||
676 | 55 | public function getParentService() |
|
677 | { |
||
678 | 55 | return $this->_parentService; |
|
679 | } |
||
680 | |||
681 | /** |
||
682 | * Sets the parent service method. |
||
683 | * |
||
684 | * @param Service $parentService Parent Service |
||
685 | * @return $this |
||
686 | */ |
||
687 | 9 | public function setParentService(Service $parentService) |
|
688 | { |
||
689 | 9 | $this->_parentService = $parentService; |
|
690 | |||
691 | 9 | return $this; |
|
692 | } |
||
693 | |||
694 | /** |
||
695 | * Parent service get and set methods. |
||
696 | * |
||
697 | * @param Service $service Parent Service instance. |
||
698 | * @deprecated 3.4.0 Use getParentService()/setParentService() instead. |
||
699 | * @return Service|$this |
||
700 | */ |
||
701 | public function parent(Service $service = null) |
||
702 | { |
||
703 | deprecationWarning( |
||
704 | 'Service::parent() is deprecated. ' . |
||
705 | 'Use Service::setParentService()/getParentService() instead.' |
||
706 | ); |
||
707 | |||
708 | if ($service !== null) { |
||
709 | return $this->setParentService($service); |
||
710 | } |
||
711 | |||
712 | return $this->getParentService(); |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * Build action class |
||
717 | * |
||
718 | * @param string $class Class name. |
||
719 | * @param array $route Activated route. |
||
720 | * @return mixed |
||
721 | */ |
||
722 | 64 | public function buildActionClass($class, $route) |
|
723 | { |
||
724 | 64 | $instance = new $class($this->_actionOptions($route)); |
|
725 | |||
726 | 64 | return $instance; |
|
727 | } |
||
728 | |||
729 | /** |
||
730 | * Action constructor options. |
||
731 | * |
||
732 | * @param array $route Activated route. |
||
733 | * @return array |
||
734 | */ |
||
735 | 64 | protected function _actionOptions($route) |
|
736 | { |
||
737 | 64 | $actionName = $route['action']; |
|
738 | |||
739 | $options = [ |
||
740 | 64 | 'name' => $actionName, |
|
741 | 64 | 'service' => $this, |
|
742 | 64 | 'route' => $route, |
|
743 | 64 | ]; |
|
744 | 64 | $options += (new ConfigReader())->actionOptions($this->getName(), $actionName, $this->getVersion()); |
|
745 | |||
746 | 64 | return $options; |
|
747 | } |
||
748 | |||
749 | /** |
||
750 | * Gets the result for service. |
||
751 | * |
||
752 | * @return Result |
||
753 | */ |
||
754 | 56 | public function getResult() |
|
755 | { |
||
756 | 56 | if ($this->_parentService !== null) { |
|
757 | 2 | return $this->_parentService->getResult(); |
|
758 | } |
||
759 | 56 | if ($this->_result === null) { |
|
760 | 56 | $this->_result = new Result(); |
|
761 | 56 | } |
|
762 | |||
763 | 56 | return $this->_result; |
|
764 | } |
||
765 | |||
766 | /** |
||
767 | * Sets the result for service. |
||
768 | * |
||
769 | * @param Result $result A Result object. |
||
770 | * @return $this |
||
771 | */ |
||
772 | public function setResult(Result $result) |
||
773 | { |
||
774 | if ($this->_parentService !== null) { |
||
775 | $this->_parentService->setResult($result); |
||
776 | |||
777 | return $this; |
||
778 | } |
||
779 | $this->_result = $result; |
||
780 | |||
781 | return $this; |
||
782 | } |
||
783 | |||
784 | /** |
||
785 | * @param null $value value |
||
786 | * @deprecated 3.4.0 Use getResult()/setResult() instead. |
||
787 | * @return Result |
||
788 | */ |
||
789 | public function result($value = null) |
||
790 | { |
||
791 | deprecationWarning( |
||
792 | 'Service::result() is deprecated. ' . |
||
793 | 'Use Service::setResult()/getResult() instead.' |
||
794 | ); |
||
795 | |||
796 | if ($value !== null) { |
||
797 | return $this->setResult($value); |
||
0 ignored issues
–
show
$value is of type null , but the function expects a object<CakeDC\Api\Service\Action\Result> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() The return type of
return $this->setResult($value); (CakeDC\Api\Service\Service ) is incompatible with the return type documented by CakeDC\Api\Service\Service::result of type CakeDC\Api\Service\Action\Result .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
798 | } |
||
799 | |||
800 | return $this->getResult(); |
||
801 | } |
||
802 | |||
803 | /** |
||
804 | * Fill up response and stop execution. |
||
805 | * |
||
806 | * @param Result $result A Result instance. |
||
807 | * @return Response |
||
808 | */ |
||
809 | 56 | public function respond($result = null) |
|
810 | { |
||
811 | 56 | if ($result === null) { |
|
812 | $result = $this->getResult(); |
||
813 | } |
||
814 | 56 | $this->setResponse($this->getResponse()->withStatus($result->getCode())); |
|
815 | 56 | if ($result->getException() !== null) { |
|
816 | 8 | $this->getRenderer() |
|
817 | 8 | ->error($result->getException()); |
|
818 | 8 | } else { |
|
819 | 52 | $this->getRenderer() |
|
820 | 52 | ->response($result); |
|
821 | } |
||
822 | |||
823 | 56 | return $this->getResponse(); |
|
824 | } |
||
825 | |||
826 | /** |
||
827 | * Gets the response. |
||
828 | * |
||
829 | * @return \Cake\Http\Response |
||
830 | */ |
||
831 | 131 | public function getResponse() |
|
832 | { |
||
833 | 131 | return $this->_response; |
|
834 | } |
||
835 | |||
836 | /** |
||
837 | * Sets the response. |
||
838 | * |
||
839 | * @param \Cake\Http\Response $response Response |
||
840 | * @return $this |
||
841 | */ |
||
842 | 140 | public function setResponse(Response $response) |
|
843 | { |
||
844 | 140 | $this->_response = $response; |
|
845 | |||
846 | 140 | return $this; |
|
847 | } |
||
848 | |||
849 | /** |
||
850 | * Get and set response. |
||
851 | * |
||
852 | * @param \Cake\Http\Response $response A Response object. |
||
853 | * @deprecated 3.4.0 Use getResponse()/setResponse() instead. |
||
854 | * @return \Cake\Http\Response |
||
855 | */ |
||
856 | public function response(Response $response = null) |
||
857 | { |
||
858 | deprecationWarning( |
||
859 | 'Service::response() is deprecated. ' . |
||
860 | 'Use Service::setResponse()/getResponse() instead.' |
||
861 | ); |
||
862 | |||
863 | if ($response !== null) { |
||
864 | return $this->setResponse($response); |
||
0 ignored issues
–
show
The return type of
return $this->setResponse($response); (CakeDC\Api\Service\Service ) is incompatible with the return type documented by CakeDC\Api\Service\Service::response of type Cake\Http\Response .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function ![]() |
|||
865 | } |
||
866 | |||
867 | return $this->getResponse(); |
||
868 | } |
||
869 | |||
870 | /** |
||
871 | * Gets the service renderer. |
||
872 | * |
||
873 | * @return BaseRenderer |
||
874 | */ |
||
875 | 68 | public function getRenderer() |
|
876 | { |
||
877 | 68 | return $this->_renderer; |
|
878 | } |
||
879 | |||
880 | /** |
||
881 | * Sets the service renderer. |
||
882 | * |
||
883 | * @param BaseRenderer $renderer Rendered |
||
884 | * @return $this |
||
885 | */ |
||
886 | 140 | public function setRenderer(BaseRenderer $renderer) |
|
887 | { |
||
888 | 140 | $this->_renderer = $renderer; |
|
889 | |||
890 | 140 | return $this; |
|
891 | } |
||
892 | |||
893 | /** |
||
894 | * Service renderer configuration method. |
||
895 | * |
||
896 | * @param BaseRenderer $renderer A Renderer instance. |
||
897 | * @deprecated 3.4.0 Use getRenderer()/setRenderer() instead. |
||
898 | * @return BaseRenderer|$this |
||
899 | */ |
||
900 | public function renderer(BaseRenderer $renderer = null) |
||
901 | { |
||
902 | deprecationWarning( |
||
903 | 'Service::renderer() is deprecated. ' . |
||
904 | 'Use Service::setRenderer()/getRenderer() instead.' |
||
905 | ); |
||
906 | |||
907 | if ($renderer !== null) { |
||
908 | return $this->setRenderer($renderer); |
||
909 | } |
||
910 | |||
911 | return $this->getRenderer(); |
||
912 | } |
||
913 | |||
914 | /** |
||
915 | * Define action config. |
||
916 | * |
||
917 | * @param string $actionName Action name. |
||
918 | * @param string $className Class name. |
||
919 | * @param array $route Route config. |
||
920 | * @return void |
||
921 | */ |
||
922 | 23 | public function mapAction($actionName, $className, $route) |
|
923 | { |
||
924 | 23 | $route += ['mapCors' => false]; |
|
925 | 23 | $this->_actionsClassMap[$actionName] = $className; |
|
926 | 23 | if ($route['mapCors']) { |
|
927 | 23 | $this->_actionsClassMap[$actionName . $this->_corsSuffix] = DummyAction::class; |
|
928 | 23 | } |
|
929 | 23 | if (!isset($route['path'])) { |
|
930 | 8 | $route['path'] = $actionName; |
|
931 | 8 | } |
|
932 | 23 | $this->_actions[$actionName] = $route; |
|
933 | 23 | } |
|
934 | |||
935 | /** |
||
936 | * Lists supported events. |
||
937 | * |
||
938 | * @return array |
||
939 | */ |
||
940 | 140 | public function implementedEvents() |
|
941 | { |
||
942 | $eventMap = [ |
||
943 | 140 | 'Service.beforeDispatch' => 'beforeDispatch', |
|
944 | 140 | 'Service.beforeProcess' => 'beforeProcess', |
|
945 | 140 | 'Service.afterDispatch' => 'afterDispatch', |
|
946 | 140 | ]; |
|
947 | 140 | $events = []; |
|
948 | |||
949 | 140 | foreach ($eventMap as $event => $method) { |
|
950 | 140 | if (!method_exists($this, $method)) { |
|
951 | 140 | continue; |
|
952 | } |
||
953 | $events[$event] = $method; |
||
954 | 140 | } |
|
955 | |||
956 | 140 | return $events; |
|
957 | } |
||
958 | |||
959 | /** |
||
960 | * Gets the extension registry instance. |
||
961 | * |
||
962 | * @return \CakeDC\Api\Service\ExtensionRegistry |
||
963 | */ |
||
964 | public function getExtensions() |
||
965 | { |
||
966 | if ($this->_extensions === null) { |
||
967 | $this->_extensions = new ExtensionRegistry($this); |
||
968 | } |
||
969 | |||
970 | return $this->_extensions; |
||
971 | } |
||
972 | |||
973 | /** |
||
974 | * Sets the extension registry for this service. |
||
975 | * |
||
976 | * @param \CakeDC\Api\Service\ExtensionRegistry $extensions The extension registry instance. |
||
977 | * @return $this |
||
978 | */ |
||
979 | 140 | public function setExtensions($extensions) |
|
980 | { |
||
981 | 140 | if ($extensions === null) { |
|
982 | 140 | $extensions = new ExtensionRegistry($this); |
|
983 | 140 | } |
|
984 | 140 | $this->_extensions = $extensions; |
|
985 | |||
986 | 140 | return $this; |
|
987 | } |
||
988 | |||
989 | /** |
||
990 | * Get the extension registry for this service. |
||
991 | * |
||
992 | * If called with the first parameter, it will be set as the action $this->_extensions property |
||
993 | * |
||
994 | * @param \CakeDC\Api\Service\ExtensionRegistry|null $extensions Extension registry. |
||
995 | * @deprecated 3.4.0 Use getExtensions()/setExtensions() instead. |
||
996 | * @return \CakeDC\Api\Service\ExtensionRegistry|$this |
||
997 | */ |
||
998 | public function extensions($extensions = null) |
||
999 | { |
||
1000 | deprecationWarning( |
||
1001 | 'Service::extensions() is deprecated. ' . |
||
1002 | 'Use Service::setExtensions()/getExtensions() instead.' |
||
1003 | ); |
||
1004 | |||
1005 | if ($extensions !== null) { |
||
1006 | $this->setExtensions($extensions); |
||
1007 | } |
||
1008 | |||
1009 | return $this->getExtensions(); |
||
1010 | } |
||
1011 | |||
1012 | /** |
||
1013 | * Loads the defined extensions using the Extension factory. |
||
1014 | * |
||
1015 | * @return void |
||
1016 | */ |
||
1017 | 140 | protected function _loadExtensions() |
|
1018 | { |
||
1019 | 140 | if (empty($this->extensions)) { |
|
1020 | 140 | return; |
|
1021 | } |
||
1022 | $registry = $this->getExtensions(); |
||
1023 | $extensions = $registry->normalizeArray($this->extensions); |
||
1024 | foreach ($extensions as $properties) { |
||
1025 | $instance = $registry->load($properties['class'], $properties['config']); |
||
1026 | $this->_eventManager->on($instance); |
||
1027 | } |
||
1028 | } |
||
1029 | |||
1030 | /** |
||
1031 | * Initialize parser. |
||
1032 | * |
||
1033 | * @param array $config Service options |
||
1034 | * @return void |
||
1035 | */ |
||
1036 | 140 | protected function _initializeParser(array $config) |
|
1037 | { |
||
1038 | 140 | if (empty($this->_parserClass) && isset($config['parserClass'])) { |
|
1039 | $this->_parserClass = $config['parserClass']; |
||
1040 | } |
||
1041 | 140 | $parserClass = Configure::read('Api.parser'); |
|
1042 | 140 | if (empty($this->_parserClass) && !empty($parserClass)) { |
|
1043 | 140 | $this->_parserClass = $parserClass; |
|
1044 | 140 | } |
|
1045 | |||
1046 | 140 | $class = App::className($this->_parserClass, 'Service/RequestParser', 'Parser'); |
|
1047 | 140 | if (!class_exists($class)) { |
|
1048 | throw new MissingParserException(['class' => $this->_parserClass]); |
||
1049 | } |
||
1050 | 140 | $this->_parser = new $class($this); |
|
1051 | 140 | } |
|
1052 | |||
1053 | /** |
||
1054 | * Initialize renderer. |
||
1055 | * |
||
1056 | * @param array $config Service options. |
||
1057 | * @return void |
||
1058 | */ |
||
1059 | 140 | protected function _initializeRenderer(array $config) |
|
1060 | { |
||
1061 | 140 | if (empty($this->_rendererClass) && isset($config['rendererClass'])) { |
|
1062 | 13 | $this->_rendererClass = $config['rendererClass']; |
|
1063 | 13 | } |
|
1064 | 140 | $rendererClass = Configure::read('Api.renderer'); |
|
1065 | 140 | if (empty($this->_rendererClass) && !empty($rendererClass)) { |
|
1066 | 127 | $this->_rendererClass = $rendererClass; |
|
1067 | 127 | } |
|
1068 | |||
1069 | 140 | $class = App::className($this->_rendererClass, 'Service/Renderer', 'Renderer'); |
|
1070 | 140 | if (!class_exists($class)) { |
|
1071 | throw new MissingRendererException(['class' => $this->_rendererClass]); |
||
1072 | } |
||
1073 | 140 | $this->setRenderer(new $class($this)); |
|
1074 | 140 | } |
|
1075 | } |
||
1076 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: