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 contains the skeleton for all of the controllers |
||
5 | * |
||
6 | * @package BZiON\Controllers |
||
7 | * @license https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3 |
||
8 | */ |
||
9 | |||
10 | use BZIon\Debug\Debug; |
||
11 | use Symfony\Component\DependencyInjection\ContainerAwareTrait; |
||
12 | use Symfony\Component\EventDispatcher\Event; |
||
13 | use Symfony\Component\HttpFoundation\ParameterBag; |
||
14 | use Symfony\Component\HttpFoundation\Response; |
||
15 | |||
16 | /** |
||
17 | * The Controller class represents a bunch of pages relating to the same |
||
18 | * subject (Model in most cases) - for example, there is a PlayerController, |
||
19 | * a TeamController and a HomeController. |
||
20 | * |
||
21 | * Controllers contain special methods called 'actions', which are essentially |
||
22 | * different pages performing different actions - for example, the |
||
23 | * TeamController might contain a 'show' action, which renders the team's page, |
||
24 | * and a 'new' action, which renders the page that is shown to the user when |
||
25 | * they want to create a new team. |
||
26 | * |
||
27 | * Actions have some unique characteristics. Take a look at this sample action: |
||
28 | * |
||
29 | * <pre><code>public function showAction(Request $request, Team $team) { |
||
30 | * return array('team' => $team); |
||
31 | * } |
||
32 | * </code></pre> |
||
33 | * |
||
34 | * The following route will make sure that `showAction()` handles the request: |
||
35 | * |
||
36 | * <pre><code>team_show: |
||
37 | * pattern: /teams/{team} |
||
38 | * defaults: { _controller: 'Team', _action: 'show' } |
||
39 | * </code></pre> |
||
40 | * |
||
41 | * First of all, the method's name should end with `Action`. The parameters |
||
42 | * are passed dynamically, and the order is insignificant. |
||
43 | * |
||
44 | * You can request Symfony's Request or Session class, or even a model, which |
||
45 | * will be generated based on the route parameters. For example, the route |
||
46 | * pattern `/posts/{post}/comments/{commentId}` (note how you can use both |
||
47 | * `comment` and `commentId` as parameters - just make sure to use the correct |
||
48 | * variable name on the method later) and can be used with actions like these: |
||
49 | * |
||
50 | * <code> |
||
51 | * public function sampleAction |
||
52 | * (Request $request, NewsArticle $post, Comment $comment) |
||
53 | * </code> |
||
54 | * |
||
55 | * <code> |
||
56 | * public function sampleAction |
||
57 | * (NewsArticle $post, Session $session, Request $request, Comment $comment) |
||
58 | * </code> |
||
59 | * |
||
60 | * A method's return value can be: |
||
61 | * - Symfony's Response Class |
||
62 | * - A string representing the text you want the user to see |
||
63 | * - An array representing the variables you want to pass to the controller's |
||
64 | * view, so that it can be rendered |
||
65 | * |
||
66 | * @package BZiON\Controllers |
||
67 | */ |
||
68 | abstract class Controller |
||
69 | { |
||
70 | use ContainerAwareTrait; |
||
71 | |||
72 | /** |
||
73 | * Parameters specified by the route |
||
74 | * @var ParameterBag |
||
75 | */ |
||
76 | protected $parameters; |
||
77 | |||
78 | /** |
||
79 | * The first controller that was invoked |
||
80 | * @var Controller |
||
81 | */ |
||
82 | protected $parent; |
||
83 | |||
84 | /* |
||
85 | * An array of data to pass between different parts of the application |
||
86 | * |
||
87 | * @var ParameterBag |
||
88 | */ |
||
89 | public $data; |
||
90 | |||
91 | /** |
||
92 | * @param ParameterBag $parameters The array returned by $request->attributes |
||
93 | * @param Controller|null $parent The controller who invoked this controller |
||
94 | */ |
||
95 | 23 | public function __construct($parameters, Controller $parent = null) |
|
96 | { |
||
97 | 23 | $this->parameters = $parameters; |
|
98 | 23 | $this->parent = $parent ?: $this; |
|
99 | 23 | $this->data = new ParameterBag(); |
|
100 | |||
101 | 23 | $this->setContainer(Service::getContainer()); |
|
102 | 23 | } |
|
103 | |||
104 | /** |
||
105 | * Returns the controller that is assigned to a route |
||
106 | * |
||
107 | * @param ParameterBag $parameters The array returned by $request->attributes |
||
108 | * @return Controller The controller |
||
109 | */ |
||
110 | 23 | public static function getController($parameters) |
|
111 | { |
||
112 | 23 | $ref = new ReflectionClass($parameters->get('_controller') . 'Controller'); |
|
113 | 23 | $controller = $ref->newInstance($parameters); |
|
114 | |||
115 | 23 | return $controller; |
|
116 | } |
||
117 | |||
118 | /** |
||
119 | * Call the controller's action specified by the $parameters array |
||
120 | * |
||
121 | * @param string|null $action The action name to call (e.g. `show`), null to invoke the default one |
||
122 | * @return Response The action's response |
||
123 | */ |
||
124 | 23 | public function callAction($action = null) |
|
125 | { |
||
126 | 23 | $this->setup(); |
|
127 | 23 | $response = $this->forward($action); |
|
128 | 22 | $this->cleanup(); |
|
129 | |||
130 | 22 | return $response->prepare($this->getRequest()); |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * Get the controller's default action name |
||
135 | * |
||
136 | * @return string The action's name without the `Action` suffix |
||
137 | */ |
||
138 | 23 | protected function getDefaultActionName() |
|
139 | { |
||
140 | 23 | return $this->parameters->get('_action') ?: 'default'; |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * Get a controller's action |
||
145 | * |
||
146 | * @param string|null $action The action name to call (e.g. `show`), null to invoke the default one |
||
147 | * @return \ReflectionMethod The action method |
||
148 | */ |
||
149 | 23 | public function getAction($action = null) |
|
150 | { |
||
151 | 23 | if (!$action) { |
|
0 ignored issues
–
show
|
|||
152 | $action = $this->getDefaultActionName(); |
||
153 | } |
||
154 | |||
155 | 23 | return new ReflectionMethod($this, $action . 'Action'); |
|
156 | } |
||
157 | |||
158 | /** |
||
159 | * Forward the request to another action |
||
160 | * |
||
161 | * Please note that this doesn't generate an HTTP redirect, but an |
||
162 | * internal one - the user sees the original URL, but a different page |
||
163 | * |
||
164 | * @param string $action The action to forward the request to |
||
165 | * @param array $params An additional associative array of parameters to |
||
166 | * provide to the action |
||
167 | * @param string|null $controllerName The name of the controller of the |
||
168 | * action, without the 'Controller' |
||
169 | * suffix (defaults to the current |
||
170 | * controller) |
||
171 | * @return Response |
||
172 | */ |
||
173 | 23 | protected function forward($action, $params = array(), $controllerName = null) |
|
174 | { |
||
175 | 23 | if (!$action) { |
|
176 | 23 | $action = $this->getDefaultActionName(); |
|
177 | } |
||
178 | |||
179 | 23 | $args = clone $this->parameters; |
|
180 | 23 | $args->add($params); |
|
181 | |||
182 | 23 | if ($controllerName === null) { |
|
183 | 23 | $controller = $this; |
|
184 | } else { |
||
185 | $ref = new ReflectionClass($controllerName . 'Controller'); |
||
186 | $controller = $ref->newInstance($args, $this->parent); |
||
187 | } |
||
188 | |||
189 | 23 | $ret = $controller->callMethod($controller->getAction($action), $args); |
|
190 | |||
191 | 22 | return $controller->handleReturnValue($ret, $action); |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * Method that will be called before any action |
||
196 | * |
||
197 | * @return void |
||
198 | */ |
||
199 | 1 | public function setup() |
|
200 | { |
||
201 | 1 | } |
|
202 | |||
203 | /** |
||
204 | * Method that will be called after all actions |
||
205 | * |
||
206 | * @return void |
||
207 | */ |
||
208 | 22 | public function cleanup() |
|
209 | { |
||
210 | 22 | } |
|
211 | |||
212 | /** |
||
213 | * Call one of the controller's methods |
||
214 | * |
||
215 | * The arguments are passed dynamically to the method, based on its |
||
216 | * definition - check the description of the Controller class for more |
||
217 | * information |
||
218 | * |
||
219 | * @param \ReflectionMethod $method The method |
||
220 | * @param ParameterBag $parameters The parameter bag representing the route's parameters |
||
221 | * @return mixed The return value of the called method |
||
222 | */ |
||
223 | 23 | protected function callMethod($method, $parameters) |
|
224 | { |
||
225 | 23 | $params = array(); |
|
226 | |||
227 | 23 | foreach ($method->getParameters() as $p) { |
|
228 | 23 | if ($model = $this->getObjectFromParameters($p, $parameters)) { |
|
229 | 23 | $params[] = $model; |
|
230 | 1 | } elseif ($parameters->has($p->name)) { |
|
231 | $params[] = $parameters->get($p->name); |
||
232 | 1 | } elseif ($p->isOptional()) { |
|
233 | 1 | $params[] = $p->getDefaultValue(); |
|
234 | } else { |
||
235 | throw new MissingArgumentException( |
||
236 | "Missing parameter '$p->name' for " . $this->getName() . "::" |
||
237 | 23 | . $method->getName() . "()" |
|
238 | ); |
||
239 | } |
||
240 | } |
||
241 | |||
242 | 23 | return $method->invokeArgs($this, $params); |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * Find what to pass as an argument on an action |
||
247 | * |
||
248 | * @param ReflectionParameter $modelParameter The model's parameter we want to investigate |
||
249 | * @param ParameterBag $routeParameters The route's parameters |
||
250 | * |
||
251 | * @return object|null |
||
252 | */ |
||
253 | 23 | protected function getObjectFromParameters($modelParameter, $routeParameters) |
|
254 | { |
||
255 | 23 | $refClass = $modelParameter->getClass(); |
|
256 | 23 | $paramName = $modelParameter->getName(); |
|
257 | |||
258 | 23 | if ($refClass !== null && $refClass->isSubclassOf("Model")) { |
|
259 | // Look for the object's ID/slugs in the routeParameters array |
||
260 | 1 | $model = $this->findModelInParameters($modelParameter, $routeParameters); |
|
261 | |||
262 | 1 | if ($model !== null) { |
|
263 | 1 | return $model; |
|
264 | } |
||
265 | } |
||
266 | |||
267 | // $me -> currently logged in user |
||
268 | 23 | if ($paramName == "me") { |
|
269 | 1 | return self::getMe(); |
|
270 | } |
||
271 | |||
272 | 23 | if ($refClass === null) { |
|
273 | // No class provived by the method's definition, we don't know |
||
274 | // what we should pass |
||
275 | return null; |
||
276 | } |
||
277 | |||
278 | 23 | switch ($refClass->getName()) { |
|
279 | 23 | case 'Symfony\Component\HttpFoundation\Request': |
|
280 | 23 | return $this->getRequest(); |
|
281 | 23 | case 'Symfony\Component\HttpFoundation\Session\Session': |
|
282 | 1 | return $this->getRequest()->getSession(); |
|
283 | 23 | case 'Symfony\Component\HttpFoundation\Session\Flash\FlashBag': |
|
284 | return $this->getRequest()->getSession()->getFlashBag(); |
||
285 | 23 | case 'Monolog\Logger': |
|
286 | 22 | return $this->getLogger(); |
|
287 | 1 | case 'Symfony\Component\Form\FormFactory': |
|
288 | return Service::getFormFactory(); |
||
289 | } |
||
290 | |||
291 | 1 | return null; |
|
292 | } |
||
293 | |||
294 | /** |
||
295 | * Try locating a method's parameter in an array |
||
296 | * |
||
297 | * @param ReflectionParameter $modelParameter The model's parameter we want to investigate |
||
298 | * @param ParameterBag $routeParameters The route's parameters |
||
299 | * @return Model|null A Model or null if it couldn't be found |
||
300 | */ |
||
301 | 1 | protected function findModelInParameters($modelParameter, $routeParameters) |
|
302 | { |
||
303 | 1 | $refClass = $modelParameter->getClass(); |
|
304 | 1 | $paramName = $modelParameter->getName(); |
|
305 | |||
306 | 1 | if ($routeParameters->has($paramName)) { |
|
307 | 1 | $parameter = $routeParameters->get($paramName); |
|
308 | 1 | if (is_object($parameter) && $refClass->getName() === get_class($parameter)) { |
|
309 | // The model has already been instantiated - we don't need to do anything |
||
310 | return $parameter; |
||
311 | } |
||
312 | |||
313 | 1 | return $refClass->getMethod("fetchFromSlug")->invoke(null, $parameter); |
|
314 | } |
||
315 | |||
316 | 1 | if ($routeParameters->has($paramName . 'Id')) { |
|
317 | return $refClass->getMethod('get') |
||
318 | ->invoke(null, $routeParameters->get($paramName . 'Id')); |
||
319 | } |
||
320 | |||
321 | 1 | return null; |
|
322 | } |
||
323 | |||
324 | /** |
||
325 | * Render the action's template |
||
326 | * @param array $params The variables to pass to the template |
||
327 | * @param string $action The controller's action |
||
328 | * @return string The content |
||
329 | */ |
||
330 | 1 | protected function renderDefault($params, $action) |
|
331 | { |
||
332 | 1 | $templatePath = $this->getName() . "/$action.html.twig"; |
|
333 | |||
334 | 1 | return $this->render($templatePath, $params); |
|
335 | } |
||
336 | |||
337 | /** |
||
338 | * Get a Response from the return value of an action |
||
339 | * @param mixed $return Whatever the method returned |
||
340 | * @param string $action The name of the action |
||
341 | * @return Response The response that the controller wants us to send to the client |
||
342 | */ |
||
343 | 22 | protected function handleReturnValue($return, $action) |
|
344 | { |
||
345 | 22 | if ($return instanceof Response) { |
|
346 | 22 | return $return; |
|
347 | } |
||
348 | |||
349 | 22 | $content = null; |
|
350 | 22 | if (is_array($return)) { |
|
351 | // The controller is probably expecting us to show a view to the |
||
352 | // user, using the array provided to set variables for the template |
||
353 | 1 | $content = $this->renderDefault($return, $action); |
|
354 | 22 | } elseif (is_string($return)) { |
|
355 | 22 | $content = $return; |
|
356 | } |
||
357 | |||
358 | 22 | return new Response($content); |
|
359 | } |
||
360 | |||
361 | /** |
||
362 | * Returns the name of the controller without the "Controller" part |
||
363 | * @return string |
||
364 | */ |
||
365 | 1 | public static function getName() |
|
366 | { |
||
367 | 1 | return preg_replace('/Controller$/', '', get_called_class()); |
|
368 | } |
||
369 | |||
370 | /** |
||
371 | * Returns a configured QueryBuilder for the corresponding model |
||
372 | * |
||
373 | * The returned QueryBuilder will only show models visible to the currently |
||
374 | * logged in user |
||
375 | * |
||
376 | * @param string $type The model whose query builder we should get (null |
||
377 | * to get the builder of the controller's model) |
||
378 | * @return QueryBuilder |
||
379 | */ |
||
380 | public static function getQueryBuilder($type = null) |
||
381 | 1 | { |
|
382 | $type = ($type) ?: static::getName(); |
||
383 | 1 | ||
384 | return $type::getQueryBuilder() |
||
385 | 1 | ->visibleTo(static::getMe(), static::getRequest()->get('showDeleted')); |
|
386 | 1 | } |
|
387 | |||
388 | /** |
||
389 | * Generates a URL from the given parameters. |
||
390 | * @param string $name The name of the route |
||
391 | * @param mixed $parameters An array of parameters |
||
392 | * @param bool $absolute Whether to generate an absolute URL |
||
393 | * @return string The generated URL |
||
394 | */ |
||
395 | public static function generate($name, $parameters = array(), $absolute = false) |
||
396 | { |
||
397 | return Service::getGenerator()->generate($name, $parameters, $absolute); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Gets the browser's request |
||
402 | * @return Symfony\Component\HttpFoundation\Request |
||
403 | */ |
||
404 | public static function getRequest() |
||
405 | 23 | { |
|
406 | return Service::getRequest(); |
||
407 | 23 | } |
|
408 | |||
409 | /** |
||
410 | * Gets the currently logged in player |
||
411 | * |
||
412 | * If the user is not logged in, a Player object that is invalid will be |
||
413 | * returned |
||
414 | * |
||
415 | * @return Player |
||
416 | */ |
||
417 | public static function getMe() |
||
418 | 1 | { |
|
419 | return Player::get(self::getRequest()->getSession()->get('playerId')); |
||
420 | 1 | } |
|
421 | |||
422 | /** |
||
423 | * Find out whether debugging is enabled |
||
424 | * |
||
425 | * @return bool |
||
426 | */ |
||
427 | public function isDebug() |
||
428 | 23 | { |
|
429 | return $this->container->getParameter('kernel.debug'); |
||
430 | 23 | } |
|
431 | |||
432 | /** |
||
433 | * Find out whether the site is in demo mode |
||
434 | * |
||
435 | * @return bool |
||
436 | */ |
||
437 | public function isDemoMode() |
||
438 | { |
||
439 | 22 | return $this->container->getParameter('bzion.miscellaneous.demo_mode'); |
|
440 | } |
||
441 | 22 | ||
442 | 22 | /** |
|
443 | * Gets the monolog logger |
||
444 | * |
||
445 | 22 | * @param string $channel The log channel, defaults to the Controller's default |
|
446 | * @return Monolog\Logger |
||
447 | */ |
||
448 | protected static function getLogger($channel = null) |
||
449 | { |
||
450 | if (!$channel) { |
||
0 ignored issues
–
show
The expression
$channel of type string|null is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
451 | $channel = static::getLogChannel(); |
||
452 | } |
||
453 | |||
454 | return Service::getContainer()->get("monolog.logger.$channel"); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Gets the logging channel for monolog |
||
459 | * @return string |
||
460 | */ |
||
461 | protected static function getLogChannel() |
||
462 | { |
||
463 | 1 | return 'app'; |
|
464 | } |
||
465 | 1 | ||
466 | /** |
||
467 | * Uses symfony's dispatcher to announce an event |
||
468 | * @param string $eventName The name of the event to dispatch. |
||
469 | * @param Event $event The event to pass to the event handlers/listeners. |
||
470 | * @return Event |
||
471 | */ |
||
472 | protected function dispatch($eventName, Event $event = null) |
||
473 | { |
||
474 | 1 | return $this->container->get('event_dispatcher')->dispatch($eventName, $event); |
|
475 | } |
||
476 | 1 | ||
477 | /** |
||
478 | 1 | * Renders a view |
|
479 | * @param string $view The view name |
||
480 | 1 | * @param array $parameters An array of parameters to pass to the view |
|
481 | * @return string The rendered view |
||
482 | 1 | */ |
|
483 | protected function render($view, $parameters = array()) |
||
484 | { |
||
485 | Debug::startStopwatch('view.render'); |
||
486 | |||
487 | $ret = $this->container->get('twig')->render($view, $parameters); |
||
488 | |||
489 | Debug::finishStopwatch('view.render'); |
||
490 | |||
491 | return $ret; |
||
492 | } |
||
493 | } |
||
494 | |||
495 | class MissingArgumentException extends Exception |
||
496 | { |
||
497 | } |
||
498 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: