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 | // +---------------------------------------------------------------------------+ |
||
4 | // | This file is part of the Agavi package. | |
||
5 | // | Copyright (c) 2005-2011 the Agavi Project. | |
||
6 | // | | |
||
7 | // | For the full copyright and license information, please view the LICENSE | |
||
8 | // | file that was distributed with this source code. You can also view the | |
||
9 | // | LICENSE file online at http://www.agavi.org/LICENSE.txt | |
||
10 | // | vi: set noexpandtab: | |
||
11 | // | Local Variables: | |
||
12 | // | indent-tabs-mode: t | |
||
13 | // | End: | |
||
14 | // +---------------------------------------------------------------------------+ |
||
15 | |||
16 | namespace Agavi\Dispatcher; |
||
17 | |||
18 | use Agavi\Controller\Controller; |
||
19 | use Agavi\Config\ConfigCache; |
||
20 | use Agavi\Exception\AgaviException; |
||
21 | use Agavi\Exception\ViewException; |
||
22 | use Agavi\Filter\FilterChain; |
||
23 | use Agavi\Request\RequestDataHolder; |
||
24 | use Agavi\Response\Response; |
||
25 | use Agavi\Util\AttributeHolder; |
||
26 | use Agavi\Core\Context; |
||
27 | use Agavi\Config\Config; |
||
28 | use Agavi\Exception\DisabledModuleException; |
||
29 | use Agavi\Exception\FileNotFoundException; |
||
30 | use Agavi\Exception\ConfigurationException; |
||
31 | use Agavi\Util\Toolkit; |
||
32 | use Agavi\Validator\ValidationManager; |
||
33 | use Agavi\View\View; |
||
34 | |||
35 | /** |
||
36 | * A container used for each controller execution that holds necessary information, |
||
37 | * such as the output type, the response etc. |
||
38 | * |
||
39 | * @package agavi |
||
40 | * @subpackage Dispatcher |
||
41 | * |
||
42 | * @author David Zülke <[email protected]> |
||
43 | * @copyright Authors |
||
44 | * @copyright The Agavi Project |
||
45 | * |
||
46 | * @since 0.11.0 |
||
47 | * |
||
48 | * @version $Id$ |
||
49 | */ |
||
50 | |||
51 | class ExecutionContainer extends AttributeHolder |
||
52 | { |
||
53 | /** |
||
54 | * @var Context The context instance. |
||
55 | */ |
||
56 | protected $context = null; |
||
57 | |||
58 | /** |
||
59 | * @var string The context name. |
||
60 | */ |
||
61 | protected $contextName = null; |
||
62 | |||
63 | /** |
||
64 | * @var string The output type name. |
||
65 | */ |
||
66 | protected $outputTypeName = null; |
||
67 | |||
68 | /** |
||
69 | * @var FilterChain The container's filter chain. |
||
70 | */ |
||
71 | protected $filterChain = null; |
||
72 | |||
73 | /** |
||
74 | * @var ValidationManager The validation manager instance. |
||
75 | */ |
||
76 | protected $validationManager = null; |
||
77 | |||
78 | /** |
||
79 | * @var string The request method for this container. |
||
80 | */ |
||
81 | protected $requestMethod = null; |
||
82 | |||
83 | /** |
||
84 | * @var RequestDataHolder A request data holder with request info. |
||
85 | */ |
||
86 | protected $requestData = null; // TODO: check if this can actually be protected |
||
87 | // or whether it should be private (would break controller tests though) |
||
88 | |||
89 | /** |
||
90 | * @var RequestDataHolder A pointer to the global request data. |
||
91 | */ |
||
92 | private $globalRequestData = null; |
||
93 | |||
94 | /** |
||
95 | * @var RequestDataHolder A request data holder with arguments. |
||
96 | */ |
||
97 | protected $arguments = null; |
||
98 | |||
99 | /** |
||
100 | * @var Response A response instance holding the Controller's output. |
||
101 | */ |
||
102 | protected $response = null; |
||
103 | |||
104 | /** |
||
105 | * @var OutputType The output type for this container. |
||
106 | */ |
||
107 | protected $outputType = null; |
||
108 | |||
109 | /** |
||
110 | * @var float The microtime at which this container was initialized. |
||
111 | */ |
||
112 | protected $microtime = null; |
||
113 | |||
114 | /** |
||
115 | * @var Controller The Controller instance that belongs to this container. |
||
116 | */ |
||
117 | protected $controllerInstance = null; |
||
118 | |||
119 | /** |
||
120 | * @var ViewException The View instance that belongs to this container. |
||
121 | */ |
||
122 | protected $viewInstance = null; |
||
123 | |||
124 | /** |
||
125 | * @var string The name of the Controller's Module. |
||
126 | */ |
||
127 | protected $moduleName = null; |
||
128 | |||
129 | /** |
||
130 | * @var string The name of the Controller. |
||
131 | */ |
||
132 | protected $controllerName = null; |
||
133 | |||
134 | /** |
||
135 | * @var string Name of the module of the View returned by the Controller. |
||
136 | */ |
||
137 | protected $viewModuleName = null; |
||
138 | |||
139 | /** |
||
140 | * @var string The name of the View returned by the Controller. |
||
141 | */ |
||
142 | protected $viewName = null; |
||
143 | |||
144 | /** |
||
145 | * @var ExecutionContainer The next container to execute. |
||
146 | */ |
||
147 | protected $next = null; |
||
148 | |||
149 | /** |
||
150 | * Controller names may contain any valid PHP token, as well as dots and slashes |
||
151 | * (for sub-controllers). |
||
152 | */ |
||
153 | const SANE_CONTROLLER_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\/.]*/'; |
||
154 | |||
155 | /** |
||
156 | * View names may contain any valid PHP token, as well as dots and slashes |
||
157 | * (for sub-controllers). |
||
158 | */ |
||
159 | const SANE_VIEW_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\/.]*/'; |
||
160 | |||
161 | /** |
||
162 | * Only valid PHP tokens are allowed in module names. |
||
163 | */ |
||
164 | const SANE_MODULE_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/'; |
||
165 | |||
166 | /** |
||
167 | * Pre-serialization callback. |
||
168 | * |
||
169 | * Will set the name of the context instead of the instance, and the name of |
||
170 | * the output type instead of the instance. Both will be restored by __wakeup |
||
171 | * |
||
172 | * @author David Zülke <[email protected]> |
||
173 | * @since 0.11.0 |
||
174 | */ |
||
175 | public function __sleep() |
||
176 | { |
||
177 | $this->contextName = $this->context->getName(); |
||
178 | if (!empty($this->outputType)) { |
||
179 | $this->outputTypeName = $this->outputType->getName(); |
||
180 | } |
||
181 | $arr = get_object_vars($this); |
||
182 | unset($arr['context'], $arr['outputType'], $arr['requestData'], $arr['globalRequestData']); |
||
183 | return array_keys($arr); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Post-unserialization callback. |
||
188 | * |
||
189 | * Will restore the context and output type instances based on their names set |
||
190 | * by __sleep. |
||
191 | * |
||
192 | * @author David Zülke <[email protected]> |
||
193 | * @since 0.11.0 |
||
194 | */ |
||
195 | public function __wakeup() |
||
196 | { |
||
197 | $this->context = Context::getInstance($this->contextName); |
||
198 | |||
199 | if (!empty($this->outputTypeName)) { |
||
200 | $this->outputType = $this->context->getDispatcher()->getOutputType($this->outputTypeName); |
||
201 | } |
||
202 | |||
203 | try { |
||
204 | $this->globalRequestData = $this->context->getRequest()->getRequestData(); |
||
205 | } catch (AgaviException $e) { |
||
206 | $this->globalRequestData = new RequestDataHolder(); |
||
207 | } |
||
208 | unset($this->contextName, $this->outputTypeName); |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Initialize the container. This will create a response instance. |
||
213 | * |
||
214 | * @param Context $context The current Context instance. |
||
215 | * @param array $parameters An array of initialization parameters. |
||
216 | * |
||
217 | * @author David Zülke <[email protected]> |
||
218 | * @since 0.11.0 |
||
219 | */ |
||
220 | public function initialize(Context $context, array $parameters = array()) |
||
221 | { |
||
222 | $this->microtime = microtime(true); |
||
223 | |||
224 | $this->context = $context; |
||
225 | |||
226 | $this->parameters = $parameters; |
||
227 | |||
228 | $this->response = $this->context->createInstanceFor('response'); |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Creates a new container instance with the same output type and request |
||
233 | * method as this one. |
||
234 | * |
||
235 | * @param string $moduleName The name of the module. |
||
236 | * @param string $controllerName The name of the controller. |
||
237 | * @param RequestDataHolder $arguments A RequestDataHolder with additional |
||
238 | * request arguments. |
||
239 | * @param string $outputType Optional name of an initial output type |
||
240 | * to set. |
||
241 | * @param string $requestMethod Optional name of the request method to |
||
242 | * be used in this container. |
||
243 | * |
||
244 | * @return ExecutionContainer A new execution container instance, |
||
245 | * fully initialized. |
||
246 | * |
||
247 | * @author David Zülke <[email protected]> |
||
248 | * @since 0.11.0 |
||
249 | */ |
||
250 | public function createExecutionContainer($moduleName = null, $controllerName = null, RequestDataHolder $arguments = null, $outputType = null, $requestMethod = null) |
||
251 | { |
||
252 | if ($outputType === null) { |
||
253 | $outputType = $this->getOutputType()->getName(); |
||
254 | } |
||
255 | if ($requestMethod === null) { |
||
256 | $requestMethod = $this->getRequestMethod(); |
||
257 | } |
||
258 | |||
259 | $container = $this->context->getDispatcher()->createExecutionContainer($moduleName, $controllerName, $arguments, $outputType, $requestMethod); |
||
260 | |||
261 | // copy over parameters (could be is_slot, is_forward etc) |
||
262 | $container->setParameters($this->getParameters()); |
||
263 | |||
264 | return $container; |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Start execution. |
||
269 | * |
||
270 | * This will create an instance of the controller and merge in request parameters. |
||
271 | * |
||
272 | * This method returns a response. It is not necessarily the same response as |
||
273 | * the one of this container, but instead the one that contains the actual |
||
274 | * content that should be used for output etc, since the container's own |
||
275 | * response might be empty or invalid due to a "next" container that has been |
||
276 | * set and executed. |
||
277 | * |
||
278 | * @return Response The "real" response. |
||
279 | * |
||
280 | * @author David Zülke <[email protected]> |
||
281 | * @since 0.11.0 |
||
282 | */ |
||
283 | public function execute() |
||
284 | { |
||
285 | $dispatcher = $this->context->getDispatcher(); |
||
286 | |||
287 | $dispatcher->countExecution(); |
||
288 | |||
289 | $moduleName = $this->getModuleName(); |
||
290 | |||
291 | try { |
||
292 | $controllerInstance = $this->getControllerInstance(); |
||
293 | } catch (DisabledModuleException $e) { |
||
294 | $this->setNext($this->createSystemControllerForwardContainer('module_disabled')); |
||
295 | return $this->proceed(); |
||
296 | } catch (FileNotFoundException $e) { |
||
297 | $this->setNext($this->createSystemControllerForwardContainer('error_404')); |
||
298 | return $this->proceed(); |
||
299 | } // do not catch AgaviClassNotFoundException, we want that to bubble up since it means the class in the controller file is named incorrectly |
||
300 | |||
301 | // copy and merge request data as required |
||
302 | $this->initRequestData(); |
||
303 | |||
304 | /** @var FilterChain $filterChain */ |
||
305 | $filterChain = $this->getFilterChain(); |
||
306 | |||
307 | if (!$controllerInstance->isSimple()) { |
||
308 | // simple controllers have no filters |
||
309 | |||
310 | if (Config::get('core.available', false)) { |
||
0 ignored issues
–
show
|
|||
311 | // the application is available so we'll register |
||
312 | // globally defined and module-specific controller filters, otherwise skip them |
||
313 | |||
314 | // does this controller require security? |
||
315 | if (Config::get('core.use_security', false)) { |
||
0 ignored issues
–
show
false is of type boolean , but the function expects a string|null .
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);
![]() |
|||
316 | // register security filter |
||
317 | $filterChain->register($dispatcher->getFilter('security'), 'agavi_security_filter'); |
||
318 | } |
||
319 | |||
320 | // load filters |
||
321 | $dispatcher->loadFilters($filterChain, 'controller'); |
||
322 | $dispatcher->loadFilters($filterChain, 'controller', $moduleName); |
||
323 | } |
||
324 | } |
||
325 | |||
326 | // register the execution filter |
||
327 | $filterChain->register($dispatcher->getFilter('execution'), 'agavi_execution_filter'); |
||
328 | |||
329 | // process the filter chain |
||
330 | $filterChain->execute($this); |
||
331 | |||
332 | return $this->proceed(); |
||
333 | } |
||
334 | |||
335 | /** |
||
336 | * Copies and merges the global request data. |
||
337 | * |
||
338 | * @author Felix Gilcher <[email protected]> |
||
339 | * @since 1.1.0 |
||
340 | */ |
||
341 | protected function initRequestData() |
||
342 | { |
||
343 | if ($this->getControllerInstance()->isSimple()) { |
||
344 | if ($this->arguments !== null) { |
||
345 | // clone it so mutating it has no effect on the "outside world" |
||
346 | $this->requestData = clone $this->arguments; |
||
347 | } else { |
||
348 | $rdhc = $this->getContext()->getRequest()->getParameter('request_data_holder_class'); |
||
349 | $this->requestData = new $rdhc(); |
||
350 | } |
||
351 | } else { |
||
352 | // mmmh I smell awesomeness... clone the RD JIT, yay, that's the spirit |
||
353 | $this->requestData = clone $this->globalRequestData; |
||
354 | |||
355 | if ($this->arguments !== null) { |
||
356 | $this->requestData->merge($this->arguments); |
||
357 | } |
||
358 | } |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Create a system forward container |
||
363 | * |
||
364 | * Calling this method will set the attributes: |
||
365 | * - requested_module |
||
366 | * - requested_controller |
||
367 | * - (optional) exception |
||
368 | * in the appropriate namespace on the created container as well as the global |
||
369 | * request (for legacy reasons) |
||
370 | * |
||
371 | * |
||
372 | * @param string $type The type of forward to create (error_404, |
||
373 | * module_disabled, secure, login, unavailable). |
||
374 | * @param AgaviException $e Optional exception thrown by the Dispatcher |
||
375 | * while resolving the module/controller. |
||
376 | * |
||
377 | * @return ExecutionContainer The forward container. |
||
378 | * |
||
379 | * @author Felix Gilcher <[email protected]> |
||
380 | * @since 1.0.0 |
||
381 | */ |
||
382 | public function createSystemControllerForwardContainer($type, AgaviException $e = null) |
||
383 | { |
||
384 | if (!in_array($type, array('error_404', 'module_disabled', 'secure', 'login', 'unavailable'))) { |
||
385 | throw new AgaviException(sprintf('Unknown system forward type "%1$s"', $type)); |
||
386 | } |
||
387 | |||
388 | // track the requested module so we have access to the data in the error 404 page |
||
389 | $forwardInfoData = array( |
||
390 | 'requested_module' => $this->getModuleName(), |
||
391 | 'requested_controller' => $this->getControllerName(), |
||
392 | 'exception' => $e, |
||
393 | ); |
||
394 | $forwardInfoNamespace = 'org.agavi.dispatcher.forwards.' . $type; |
||
395 | |||
396 | $moduleName = Config::get('controllers.' . $type . '_module'); |
||
397 | $controllerName = Config::get('controllers.' . $type . '_controller'); |
||
398 | |||
399 | if (false === $this->context->getDispatcher()->checkControllerFile($moduleName, $controllerName)) { |
||
400 | // cannot find unavailable module/controller |
||
401 | $error = 'Invalid configuration settings: controllers.%3$s_module "%1$s", controllers.%3$s_controller "%2$s"'; |
||
402 | $error = sprintf($error, $moduleName, $controllerName, $type); |
||
403 | |||
404 | throw new ConfigurationException($error); |
||
405 | } |
||
406 | |||
407 | $forwardContainer = $this->createExecutionContainer($moduleName, $controllerName); |
||
408 | |||
409 | $forwardContainer->setAttributes($forwardInfoData, $forwardInfoNamespace); |
||
410 | // legacy |
||
411 | $this->context->getRequest()->setAttributes($forwardInfoData, $forwardInfoNamespace); |
||
412 | |||
413 | return $forwardContainer; |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Proceed to the "next" container by running it and returning its response, |
||
418 | * or return our response if there is no "next" container. |
||
419 | * |
||
420 | * @return Response The "real" response. |
||
421 | * |
||
422 | * @author David Zülke <[email protected]> |
||
423 | * @since 1.0.0 |
||
424 | */ |
||
425 | protected function proceed() |
||
426 | { |
||
427 | if ($this->next !== null) { |
||
428 | return $this->next->execute(); |
||
429 | } else { |
||
430 | return $this->getResponse(); |
||
431 | } |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Get the Context. |
||
436 | * |
||
437 | * @return Context The Context. |
||
438 | * |
||
439 | * @author David Zülke <[email protected]> |
||
440 | * @since 0.11.0 |
||
441 | */ |
||
442 | final public function getContext() |
||
443 | { |
||
444 | return $this->context; |
||
445 | } |
||
446 | |||
447 | /** |
||
448 | * Retrieve the ValidationManager |
||
449 | * |
||
450 | * @return ValidationManager The container's ValidationManager |
||
451 | * implementation instance. |
||
452 | * |
||
453 | * @author David Zülke <[email protected]> |
||
454 | * @since 0.11.0 |
||
455 | */ |
||
456 | public function getValidationManager() |
||
457 | { |
||
458 | if ($this->validationManager === null) { |
||
459 | $this->validationManager = $this->context->createInstanceFor('validation_manager'); |
||
460 | } |
||
461 | return $this->validationManager; |
||
462 | } |
||
463 | |||
464 | /** |
||
465 | * Get the container's filter chain. |
||
466 | * |
||
467 | * @return FilterChain The container's filter chain. |
||
468 | * |
||
469 | * @author David Zülke <[email protected]> |
||
470 | * @since 1.1.0 |
||
471 | */ |
||
472 | View Code Duplication | public function getFilterChain() |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
473 | { |
||
474 | if ($this->filterChain === null) { |
||
475 | $this->filterChain = $this->context->createInstanceFor('filter_chain'); |
||
476 | $this->filterChain->setType(FilterChain::TYPE_CONTROLLER); |
||
477 | } |
||
478 | |||
479 | return $this->filterChain; |
||
480 | } |
||
481 | |||
482 | /** |
||
483 | * Execute the Controller. |
||
484 | * |
||
485 | * @return mixed The processed View information returned by the Controller. |
||
486 | * |
||
487 | * @author David Zülke <[email protected]> |
||
488 | * @author Felix Gilcher <[email protected]> |
||
489 | * @since 1.0.0 |
||
490 | */ |
||
491 | public function runController() |
||
492 | { |
||
493 | $viewName = null; |
||
494 | |||
495 | $request = $this->context->getRequest(); |
||
496 | $validationManager = $this->getValidationManager(); |
||
497 | |||
498 | // get the current controller instance |
||
499 | $controllerInstance = $this->getControllerInstance(); |
||
500 | |||
501 | // get the current controller information |
||
502 | $moduleName = $this->getModuleName(); |
||
503 | $controllerName = $this->getControllerName(); |
||
504 | |||
505 | // get the (already formatted) request method |
||
506 | $method = $this->getRequestMethod(); |
||
507 | |||
508 | $requestData = $this->getRequestData(); |
||
509 | |||
510 | $useGenericMethods = false; |
||
511 | $executeMethod = 'execute' . $method; |
||
512 | if (!is_callable(array($controllerInstance, $executeMethod))) { |
||
513 | $executeMethod = 'execute'; |
||
514 | $useGenericMethods = true; |
||
515 | } |
||
516 | |||
517 | if ($controllerInstance->isSimple() || ($useGenericMethods && !is_callable(array($controllerInstance, $executeMethod)))) { |
||
518 | // this controller will skip validation/execution for this method |
||
519 | // get the default view |
||
520 | $key = $request->toggleLock(); |
||
521 | try { |
||
522 | $viewName = $controllerInstance->getDefaultViewName(); |
||
523 | } catch (\Exception $e) { |
||
524 | // we caught an exception... unlock the request and rethrow! |
||
525 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 520 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
526 | throw $e; |
||
527 | } |
||
528 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 520 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
529 | |||
530 | // run the validation manager - it's going to take care of cleaning up the request data, and retain "conditional" mode behavior etc. |
||
531 | // but only if the controller is not simple; otherwise, the (safe) arguments in the request data holder will all be removed |
||
532 | if (!$controllerInstance->isSimple()) { |
||
533 | $validationManager->execute($requestData); |
||
534 | } |
||
535 | } else { |
||
536 | if ($this->performValidation()) { |
||
537 | // execute the controller |
||
538 | // prevent access to Request::getParameters() |
||
539 | $key = $request->toggleLock(); |
||
540 | try { |
||
541 | $viewName = $controllerInstance->$executeMethod($requestData); |
||
542 | } catch (\Exception $e) { |
||
543 | // we caught an exception... unlock the request and rethrow! |
||
544 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 539 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
545 | throw $e; |
||
546 | } |
||
547 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 539 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
548 | } else { |
||
549 | // validation failed |
||
550 | $handleErrorMethod = 'handle' . $method . 'Error'; |
||
551 | if (!is_callable(array($controllerInstance, $handleErrorMethod))) { |
||
552 | $handleErrorMethod = 'handleError'; |
||
553 | } |
||
554 | $key = $request->toggleLock(); |
||
555 | try { |
||
556 | $viewName = $controllerInstance->$handleErrorMethod($requestData); |
||
557 | } catch (\Exception $e) { |
||
558 | // we caught an exception... unlock the request and rethrow! |
||
559 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 554 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
560 | throw $e; |
||
561 | } |
||
562 | $request->toggleLock($key); |
||
0 ignored issues
–
show
It seems like
$key defined by $request->toggleLock() on line 554 can also be of type boolean ; however, Agavi\Request\Request::toggleLock() does only seem to accept string|null , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
563 | } |
||
564 | } |
||
565 | |||
566 | if (is_array($viewName)) { |
||
567 | // we're going to use an entirely different controller for this view |
||
568 | $viewModule = $viewName[0]; |
||
569 | $viewName = $viewName[1]; |
||
570 | } elseif ($viewName !== View::NONE) { |
||
571 | // use a view related to this controller |
||
572 | $viewName = Toolkit::evaluateModuleDirective( |
||
573 | $moduleName, |
||
574 | 'agavi.view.name', |
||
575 | array( |
||
576 | 'controllerName' => $controllerName, |
||
577 | 'viewName' => $viewName, |
||
578 | ) |
||
579 | ); |
||
580 | $viewModule = $moduleName; |
||
581 | } else { |
||
582 | $viewName = View::NONE; |
||
583 | $viewModule = View::NONE; |
||
584 | } |
||
585 | |||
586 | return array($viewModule, $viewName === View::NONE ? View::NONE : Toolkit::canonicalName($viewName)); |
||
587 | } |
||
588 | |||
589 | /** |
||
590 | * Performs validation for this execution container. |
||
591 | * |
||
592 | * @return bool true if the data validated successfully, false otherwise. |
||
593 | * |
||
594 | * @author David Zülke <[email protected]> |
||
595 | * @author Felix Gilcher <[email protected]> |
||
596 | * @since 1.0.0 |
||
597 | */ |
||
598 | public function performValidation() |
||
599 | { |
||
600 | $validationManager = $this->getValidationManager(); |
||
601 | |||
602 | // get the current controller instance |
||
603 | $controllerInstance = $this->getControllerInstance(); |
||
604 | // get the (already formatted) request method |
||
605 | $method = $this->getRequestMethod(); |
||
606 | |||
607 | $requestData = $this->getRequestData(); |
||
608 | |||
609 | // set default validated status |
||
610 | $validated = true; |
||
0 ignored issues
–
show
$validated is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
611 | |||
612 | $this->registerValidators(); |
||
613 | |||
614 | // process validators |
||
615 | $validated = $validationManager->execute($requestData); |
||
616 | |||
617 | $validateMethod = 'validate' . $method; |
||
618 | if (!is_callable(array($controllerInstance, $validateMethod))) { |
||
619 | $validateMethod = 'validate'; |
||
620 | } |
||
621 | |||
622 | // process manual validation |
||
623 | return $controllerInstance->$validateMethod($requestData) && $validated; |
||
624 | } |
||
625 | |||
626 | /** |
||
627 | * Register validators for this execution container. |
||
628 | * |
||
629 | * @author David Zülke <[email protected]> |
||
630 | * @author Felix Gilcher <[email protected]> |
||
631 | * @since 1.0.0 |
||
632 | */ |
||
633 | public function registerValidators() |
||
634 | { |
||
635 | |||
636 | // get the current controller instance |
||
637 | $controllerInstance = $this->getControllerInstance(); |
||
638 | |||
639 | // get the current controller information |
||
640 | $moduleName = $this->getModuleName(); |
||
641 | $controllerName = $this->getControllerName(); |
||
642 | |||
643 | // get the (already formatted) request method |
||
644 | $method = $this->getRequestMethod(); |
||
645 | |||
646 | // get the current controller validation configuration |
||
647 | $validationConfig = Toolkit::evaluateModuleDirective( |
||
648 | $moduleName, |
||
649 | 'agavi.validate.path', |
||
650 | array( |
||
651 | 'moduleName' => $moduleName, |
||
652 | 'controllerName' => $controllerName, |
||
653 | ) |
||
654 | ); |
||
655 | $validationManager = $this->getValidationManager(); |
||
656 | |||
657 | if (is_readable($validationConfig)) { |
||
658 | // load validation configuration |
||
659 | // do NOT use require_once |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
660 | require(ConfigCache::checkConfig($validationConfig, $this->context->getName())); |
||
661 | } |
||
662 | |||
663 | // manually load validators |
||
664 | $registerValidatorsMethod = 'register' . $method . 'Validators'; |
||
665 | if (!is_callable(array($controllerInstance, $registerValidatorsMethod))) { |
||
666 | $registerValidatorsMethod = 'registerValidators'; |
||
667 | } |
||
668 | $controllerInstance->$registerValidatorsMethod(); |
||
669 | } |
||
670 | |||
671 | /** |
||
672 | * Retrieve this container's request method name. |
||
673 | * |
||
674 | * @return string The request method name. |
||
675 | * |
||
676 | * @author David Zülke <[email protected]> |
||
677 | * @since 1.0.0 |
||
678 | */ |
||
679 | public function getRequestMethod() |
||
680 | { |
||
681 | return $this->requestMethod; |
||
682 | } |
||
683 | |||
684 | /** |
||
685 | * Set this container's request method name. |
||
686 | * |
||
687 | * @param string $requestMethod The request method name. |
||
688 | * |
||
689 | * @author David Zülke <[email protected]> |
||
690 | * @since 1.0.0 |
||
691 | */ |
||
692 | public function setRequestMethod($requestMethod) |
||
693 | { |
||
694 | $this->requestMethod = $requestMethod; |
||
695 | } |
||
696 | |||
697 | /** |
||
698 | * Retrieve this container's request data holder instance. |
||
699 | * |
||
700 | * @return RequestDataHolder The request data holder. |
||
701 | * |
||
702 | * @author David Zülke <[email protected]> |
||
703 | * @since 0.11.0 |
||
704 | */ |
||
705 | final public function getRequestData() |
||
706 | { |
||
707 | return $this->requestData; |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * Set this container's global request data holder reference. |
||
712 | * |
||
713 | * @param RequestDataHolder $rd The request data holder. |
||
714 | * |
||
715 | * @author David Zülke <[email protected]> |
||
716 | * @since 0.11.0 |
||
717 | */ |
||
718 | final public function setRequestData(RequestDataHolder $rd) |
||
719 | { |
||
720 | $this->globalRequestData = $rd; |
||
721 | } |
||
722 | |||
723 | /** |
||
724 | * Get this container's request data holder instance for additional arguments. |
||
725 | * |
||
726 | * @return RequestDataHolder The additional arguments. |
||
727 | * |
||
728 | * @author David Zülke <[email protected]> |
||
729 | * @since 0.11.0 |
||
730 | */ |
||
731 | public function getArguments() |
||
732 | { |
||
733 | return $this->arguments; |
||
734 | } |
||
735 | |||
736 | /** |
||
737 | * Set this container's request data holder instance for additional arguments. |
||
738 | * |
||
739 | * @return RequestDataHolder The request data holder. |
||
740 | * |
||
741 | * @author David Zülke <[email protected]> |
||
742 | * @since 0.11.0 |
||
743 | */ |
||
744 | public function setArguments(RequestDataHolder $arguments) |
||
745 | { |
||
746 | $this->arguments = $arguments; |
||
747 | } |
||
748 | |||
749 | /** |
||
750 | * Retrieve this container's response instance. |
||
751 | * |
||
752 | * @return Response The Response instance for this controller. |
||
753 | * |
||
754 | * @author David Zülke <[email protected]> |
||
755 | * @since 0.11.0 |
||
756 | */ |
||
757 | public function getResponse() |
||
758 | { |
||
759 | return $this->response; |
||
760 | } |
||
761 | |||
762 | /** |
||
763 | * Set a new response. |
||
764 | * |
||
765 | * @param Response $response A new Response instance. |
||
766 | * |
||
767 | * @author David Zülke <[email protected]> |
||
768 | * @since 0.11.0 |
||
769 | */ |
||
770 | public function setResponse(Response $response) |
||
771 | { |
||
772 | $this->response = $response; |
||
773 | // do not set the output type on the response here! |
||
774 | } |
||
775 | |||
776 | /** |
||
777 | * Retrieve the output type of this container. |
||
778 | * |
||
779 | * @return OutputType The output type object. |
||
780 | * |
||
781 | * @author David Zülke <[email protected]> |
||
782 | * @since 0.11.0 |
||
783 | */ |
||
784 | public function getOutputType() |
||
785 | { |
||
786 | return $this->outputType; |
||
787 | } |
||
788 | |||
789 | /** |
||
790 | * Set a different output type for this container. |
||
791 | * |
||
792 | * @param OutputType $outputType An output type object. |
||
793 | * |
||
794 | * @author David Zülke <[email protected]> |
||
795 | * @since 0.11.0 |
||
796 | */ |
||
797 | public function setOutputType(OutputType $outputType) |
||
798 | { |
||
799 | $this->outputType = $outputType; |
||
800 | if ($this->response) { |
||
801 | $this->response->setOutputType($outputType); |
||
802 | } |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * Retrieve this container's microtime. |
||
807 | * |
||
808 | * @return string A string representing the microtime this container was |
||
809 | * initialized. |
||
810 | * |
||
811 | * @author David Zülke <[email protected]> |
||
812 | * @since 0.11.0 |
||
813 | */ |
||
814 | public function getMicrotime() |
||
815 | { |
||
816 | return $this->microtime; |
||
817 | } |
||
818 | |||
819 | /** |
||
820 | * Retrieve this container's controller instance. |
||
821 | * |
||
822 | * @return Controller An controller implementation instance. |
||
823 | * |
||
824 | * @author David Zülke <[email protected]> |
||
825 | * @since 0.11.0 |
||
826 | */ |
||
827 | public function getControllerInstance() |
||
828 | { |
||
829 | if ($this->controllerInstance === null) { |
||
830 | $dispatcher = $this->context->getDispatcher(); |
||
831 | |||
832 | $moduleName = $this->getModuleName(); |
||
833 | $controllerName = $this->getControllerName(); |
||
834 | |||
835 | $this->controllerInstance = $dispatcher->createControllerInstance($moduleName, $controllerName); |
||
836 | |||
837 | // initialize the controller |
||
838 | $this->controllerInstance->initialize($this); |
||
839 | } |
||
840 | |||
841 | return $this->controllerInstance; |
||
842 | } |
||
843 | |||
844 | /** |
||
845 | * Retrieve this container's view instance. |
||
846 | * |
||
847 | * @return View A view implementation instance. |
||
848 | * |
||
849 | * @author Ross Lawley <[email protected]> |
||
850 | * @since 0.11.0 |
||
851 | */ |
||
852 | public function getViewInstance() |
||
853 | { |
||
854 | if ($this->viewInstance === null) { |
||
855 | // get the view instance |
||
856 | $this->viewInstance = $this->getContext()->getDispatcher()->createViewInstance($this->getViewModuleName(), $this->getViewName()); |
||
0 ignored issues
–
show
It seems like
$this->getContext()->get..., $this->getViewName()) of type object<Agavi\View\View> is incompatible with the declared type object<Agavi\Exception\ViewException> of property $viewInstance .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
857 | // initialize the view |
||
858 | $this->viewInstance->initialize($this); |
||
859 | } |
||
860 | |||
861 | return $this->viewInstance; |
||
0 ignored issues
–
show
The expression
$this->viewInstance; of type Agavi\View\View|Agavi\Exception\ViewException adds the type Agavi\Exception\ViewException to the return on line 861 which is incompatible with the return type documented by Agavi\Dispatcher\Executi...tainer::getViewInstance of type Agavi\View\View .
![]() |
|||
862 | } |
||
863 | |||
864 | /** |
||
865 | * Set this container's view instance. |
||
866 | * |
||
867 | * @param View $viewInstance A view implementation instance. |
||
868 | * |
||
869 | * @author Ross Lawley <[email protected]> |
||
870 | * @since 0.11.0 |
||
871 | */ |
||
872 | public function setViewInstance($viewInstance) |
||
873 | { |
||
874 | return $this->viewInstance = $viewInstance; |
||
0 ignored issues
–
show
It seems like
$viewInstance of type object<Agavi\View\View> is incompatible with the declared type object<Agavi\Exception\ViewException> of property $viewInstance .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
875 | } |
||
876 | |||
877 | /** |
||
878 | * Retrieve this container's module name. |
||
879 | * |
||
880 | * @return string A module name. |
||
881 | * |
||
882 | * @author David Zülke <[email protected]> |
||
883 | * @since 0.11.0 |
||
884 | */ |
||
885 | public function getModuleName() |
||
886 | { |
||
887 | return $this->moduleName; |
||
888 | } |
||
889 | |||
890 | /** |
||
891 | * Retrieve this container's controller name. |
||
892 | * |
||
893 | * @return string An controller name. |
||
894 | * |
||
895 | * @author David Zülke <[email protected]> |
||
896 | * @since 0.11.0 |
||
897 | */ |
||
898 | public function getControllerName() |
||
899 | { |
||
900 | return $this->controllerName; |
||
901 | } |
||
902 | |||
903 | /** |
||
904 | * Retrieve this container's view module name. This is the name of the module of |
||
905 | * the View returned by the Controller. |
||
906 | * |
||
907 | * @return string A view module name. |
||
908 | * |
||
909 | * @author David Zülke <[email protected]> |
||
910 | * @since 0.11.0 |
||
911 | */ |
||
912 | public function getViewModuleName() |
||
913 | { |
||
914 | return $this->viewModuleName; |
||
915 | } |
||
916 | |||
917 | /** |
||
918 | * Retrieve this container's view name. |
||
919 | * |
||
920 | * @return string A view name. |
||
921 | * |
||
922 | * @author David Zülke <[email protected]> |
||
923 | * @since 0.11.0 |
||
924 | */ |
||
925 | public function getViewName() |
||
926 | { |
||
927 | return $this->viewName; |
||
928 | } |
||
929 | |||
930 | /** |
||
931 | * Set the module name for this container. |
||
932 | * |
||
933 | * @param string $moduleName A module name. |
||
934 | * |
||
935 | * @author David Zülke <[email protected]> |
||
936 | * @since 0.11.0 |
||
937 | */ |
||
938 | public function setModuleName($moduleName) |
||
939 | { |
||
940 | if (null === $moduleName) { |
||
941 | $this->moduleName = null; |
||
942 | } elseif (preg_match(self::SANE_MODULE_NAME, $moduleName)) { |
||
943 | $this->moduleName = $moduleName; |
||
944 | } else { |
||
945 | throw new AgaviException(sprintf('Invalid module name "%1$s"', $moduleName)); |
||
946 | } |
||
947 | } |
||
948 | |||
949 | /** |
||
950 | * Set the controller name for this container. |
||
951 | * |
||
952 | * @param string $controllerName An controller name. |
||
953 | * |
||
954 | * @author David Zülke <[email protected]> |
||
955 | * @since 0.11.0 |
||
956 | */ |
||
957 | public function setControllerName($controllerName) |
||
958 | { |
||
959 | View Code Duplication | if (null === $controllerName) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
960 | $this->controllerName = null; |
||
961 | } elseif (preg_match(self::SANE_CONTROLLER_NAME, $controllerName)) { |
||
962 | $controllerName = Toolkit::canonicalName($controllerName); |
||
963 | $this->controllerName = $controllerName; |
||
964 | } else { |
||
965 | throw new AgaviException(sprintf('Invalid controller name "%1$s"', $controllerName)); |
||
966 | } |
||
967 | } |
||
968 | |||
969 | /** |
||
970 | * Set the view module name for this container. |
||
971 | * |
||
972 | * @param string $viewModuleName A view module name. |
||
973 | * |
||
974 | * @author David Zülke <[email protected]> |
||
975 | * @since 0.11.0 |
||
976 | */ |
||
977 | public function setViewModuleName($viewModuleName) |
||
978 | { |
||
979 | if (null === $viewModuleName) { |
||
980 | $this->viewModuleName = null; |
||
981 | } elseif (preg_match(self::SANE_MODULE_NAME, $viewModuleName)) { |
||
982 | $this->viewModuleName = $viewModuleName; |
||
983 | } else { |
||
984 | throw new AgaviException(sprintf('Invalid view module name "%1$s"', $viewModuleName)); |
||
985 | } |
||
986 | } |
||
987 | |||
988 | /** |
||
989 | * Set the module name for this container. |
||
990 | * |
||
991 | * @param string $viewName A view name. |
||
992 | * |
||
993 | * @author David Zülke <[email protected]> |
||
994 | * @since 0.11.0 |
||
995 | */ |
||
996 | public function setViewName($viewName) |
||
997 | { |
||
998 | View Code Duplication | if (null === $viewName) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
999 | $this->viewName = null; |
||
1000 | } elseif (preg_match(self::SANE_VIEW_NAME, $viewName)) { |
||
1001 | $viewName = Toolkit::canonicalName($viewName); |
||
1002 | $this->viewName = $viewName; |
||
1003 | } else { |
||
1004 | throw new AgaviException(sprintf('Invalid view name "%1$s"', $viewName)); |
||
1005 | } |
||
1006 | } |
||
1007 | |||
1008 | /** |
||
1009 | * Check if a "next" container has been set. |
||
1010 | * |
||
1011 | * @return bool True, if a container for eventual execution has been set. |
||
1012 | * |
||
1013 | * @author David Zülke <[email protected]> |
||
1014 | * @since 0.11.0 |
||
1015 | */ |
||
1016 | public function hasNext() |
||
1017 | { |
||
1018 | return $this->next !== null; |
||
1019 | } |
||
1020 | |||
1021 | /** |
||
1022 | * Get the "next" container. |
||
1023 | * |
||
1024 | * @return ExecutionContainer The "next" container, of null if unset. |
||
1025 | * |
||
1026 | * @author David Zülke <[email protected]> |
||
1027 | * @since 0.11.0 |
||
1028 | */ |
||
1029 | public function getNext() |
||
1030 | { |
||
1031 | return $this->next; |
||
1032 | } |
||
1033 | |||
1034 | /** |
||
1035 | * Set the container that should be executed once this one finished running. |
||
1036 | * |
||
1037 | * @param ExecutionContainer $container An execution container instance. |
||
1038 | * |
||
1039 | * @author David Zülke <[email protected]> |
||
1040 | * @since 0.11.0 |
||
1041 | */ |
||
1042 | public function setNext(ExecutionContainer $container) |
||
1043 | { |
||
1044 | $this->next = $container; |
||
1045 | } |
||
1046 | |||
1047 | /** |
||
1048 | * Remove a possibly set "next" container. |
||
1049 | * |
||
1050 | * @return ExecutionContainer The removed "next" container, or null |
||
1051 | * if none had been set. |
||
1052 | * |
||
1053 | * @author David Zülke <[email protected]> |
||
1054 | * @since 0.11.0 |
||
1055 | */ |
||
1056 | public function clearNext() |
||
1057 | { |
||
1058 | $retval = $this->next; |
||
1059 | $this->next = null; |
||
1060 | return $retval; |
||
1061 | } |
||
1062 | } |
||
1063 |
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: