horros /
agavi2
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\Routing; |
||
| 17 | |||
| 18 | use Agavi\Config\Config; |
||
| 19 | use Agavi\Config\ConfigCache; |
||
| 20 | use Agavi\Exception\AgaviException; |
||
| 21 | use Agavi\Response\Response; |
||
| 22 | use Agavi\Util\ArrayPathDefinition; |
||
| 23 | use Agavi\Util\ParameterHolder; |
||
| 24 | use Agavi\Core\Context; |
||
| 25 | use Agavi\Util\Toolkit; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Routing allows you to centralize your entry point urls in your web |
||
| 29 | * application. |
||
| 30 | * |
||
| 31 | * @package agavi |
||
| 32 | * @subpackage routing |
||
| 33 | * |
||
| 34 | * @author Dominik del Bondio <[email protected]> |
||
| 35 | * @author David Zülke <[email protected]> |
||
| 36 | * @copyright Authors |
||
| 37 | * @copyright The Agavi Project |
||
| 38 | * |
||
| 39 | * @since 0.11.0 |
||
| 40 | * |
||
| 41 | * @version $Id$ |
||
| 42 | */ |
||
| 43 | abstract class Routing extends ParameterHolder |
||
| 44 | { |
||
| 45 | const ANCHOR_NONE = 0; |
||
| 46 | const ANCHOR_START = 1; |
||
| 47 | const ANCHOR_END = 2; |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @var array An array of route information |
||
| 51 | */ |
||
| 52 | protected $routes = array(); |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @var Context A Context instance. |
||
| 56 | */ |
||
| 57 | protected $context = null; |
||
| 58 | |||
| 59 | /** |
||
| 60 | * @var string Route input. |
||
| 61 | */ |
||
| 62 | protected $input = null; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * @var RoutingArraySource[] An array of RoutingArraySource. |
||
| 66 | */ |
||
| 67 | protected $sources = array(); |
||
| 68 | |||
| 69 | /** |
||
| 70 | * @var string Route prefix to use with gen() |
||
| 71 | */ |
||
| 72 | protected $prefix = ''; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * @var array An array of default options for gen() |
||
| 76 | */ |
||
| 77 | protected $defaultGenOptions = array(); |
||
| 78 | |||
| 79 | /** |
||
| 80 | * @var array An array of default options presets for gen() |
||
| 81 | */ |
||
| 82 | protected $genOptionsPresets = array(); |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Constructor. |
||
| 86 | * |
||
| 87 | * @author David Zülke <[email protected]> |
||
| 88 | * @since 0.11.0 |
||
| 89 | */ |
||
| 90 | public function __construct() |
||
| 91 | { |
||
| 92 | // for now, we still use this setting as default. |
||
| 93 | // will be removed in 1.1 |
||
| 94 | $this->setParameter('enabled', Config::get('core.use_routing', true)); |
||
|
0 ignored issues
–
show
|
|||
| 95 | |||
| 96 | $this->defaultGenOptions = array_merge($this->defaultGenOptions, array( |
||
| 97 | 'relative' => true, |
||
| 98 | 'refill_all_parameters' => false, |
||
| 99 | 'omit_defaults' => false, |
||
| 100 | )); |
||
| 101 | } |
||
| 102 | |||
| 103 | /** |
||
| 104 | * Initialize the routing instance. |
||
| 105 | * |
||
| 106 | * @param Context $context The Context. |
||
| 107 | * @param array $parameters An array of initialization parameters. |
||
| 108 | * |
||
| 109 | * @author Dominik del Bondio <[email protected]> |
||
| 110 | * @author David Zülke <[email protected]> |
||
| 111 | * @since 0.11.0 |
||
| 112 | */ |
||
| 113 | public function initialize(Context $context, array $parameters = array()) |
||
| 114 | { |
||
| 115 | $this->context = $context; |
||
| 116 | |||
| 117 | $this->setParameters($parameters); |
||
| 118 | |||
| 119 | $this->defaultGenOptions = array_merge( |
||
| 120 | $this->defaultGenOptions, |
||
| 121 | $this->getParameter('default_gen_options', array()) |
||
| 122 | ); |
||
| 123 | |||
| 124 | $this->genOptionsPresets = array_merge( |
||
| 125 | $this->genOptionsPresets, |
||
| 126 | $this->getParameter('gen_options_presets', array()) |
||
| 127 | ); |
||
| 128 | |||
| 129 | // and load the config. |
||
| 130 | $this->loadConfig(); |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * Load the routing.xml configuration file. |
||
| 135 | * |
||
| 136 | * @author David Zülke <[email protected]> |
||
| 137 | * @since 0.11.0 |
||
| 138 | */ |
||
| 139 | protected function loadConfig() |
||
| 140 | { |
||
| 141 | $cfg = Config::get('core.config_dir') . '/routing.xml'; |
||
| 142 | // allow missing routing.xml when routing is not enabled |
||
| 143 | if ($this->isEnabled() || is_readable($cfg)) { |
||
| 144 | $this->importRoutes(unserialize(file_get_contents(ConfigCache::checkConfig($cfg, $this->context->getName())))); |
||
| 145 | } |
||
| 146 | } |
||
| 147 | |||
| 148 | /** |
||
| 149 | * Do any necessary startup work after initialization. |
||
| 150 | * |
||
| 151 | * This method is not called directly after initialize(). |
||
| 152 | * |
||
| 153 | * @author David Zülke <[email protected]> |
||
| 154 | * @since 0.11.0 |
||
| 155 | */ |
||
| 156 | public function startup() |
||
|
0 ignored issues
–
show
startup uses the super-global variable $_ENV which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
Loading history...
startup uses the super-global variable $_SERVER which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
Loading history...
|
|||
| 157 | { |
||
| 158 | $this->sources['_ENV'] = new RoutingArraySource($_ENV); |
||
| 159 | |||
| 160 | $this->sources['_SERVER'] = new RoutingArraySource($_SERVER); |
||
| 161 | |||
| 162 | if (Config::get('core.use_security')) { |
||
| 163 | $this->sources['user'] = new RoutingUserSource($this->context->getUser()); |
||
| 164 | } |
||
| 165 | } |
||
| 166 | |||
| 167 | /** |
||
| 168 | * Execute the shutdown procedure. |
||
| 169 | * |
||
| 170 | * @author David Zülke <[email protected]> |
||
| 171 | * @since 0.11.0 |
||
| 172 | */ |
||
| 173 | public function shutdown() |
||
| 174 | { |
||
| 175 | } |
||
| 176 | |||
| 177 | /** |
||
| 178 | * Check if this routing instance is enabled. |
||
| 179 | * |
||
| 180 | * @return bool Whether or not routing is enabled. |
||
| 181 | * |
||
| 182 | * @author David Zülke <[email protected]> |
||
| 183 | * @since 1.0.0 |
||
| 184 | */ |
||
| 185 | public function isEnabled() |
||
| 186 | { |
||
| 187 | return $this->getParameter('enabled') === true; |
||
| 188 | } |
||
| 189 | |||
| 190 | /** |
||
| 191 | * Retrieve the current application context. |
||
| 192 | * |
||
| 193 | * @return Context A Context instance. |
||
| 194 | * |
||
| 195 | * @author Dominik del Bondio <[email protected]> |
||
| 196 | * @since 0.11.0 |
||
| 197 | */ |
||
| 198 | final public function getContext() |
||
| 199 | { |
||
| 200 | return $this->context; |
||
| 201 | } |
||
| 202 | |||
| 203 | /** |
||
| 204 | * Retrieve the info about a named route for this routing instance. |
||
| 205 | * |
||
| 206 | * @return mixed The route info or null if the route doesn't exist. |
||
| 207 | * |
||
| 208 | * @author Dominik del Bondio <[email protected]> |
||
| 209 | * @since 0.11.0 |
||
| 210 | */ |
||
| 211 | final public function getRoute($name) |
||
| 212 | { |
||
| 213 | if (!isset($this->routes[$name])) { |
||
| 214 | return null; |
||
| 215 | } |
||
| 216 | return $this->routes[$name]; |
||
| 217 | } |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Retrieve the input for this routing instance. |
||
| 221 | * |
||
| 222 | * @return string The input. |
||
| 223 | * |
||
| 224 | * @author Dominik del Bondio <[email protected]> |
||
| 225 | * @since 0.11.0 |
||
| 226 | */ |
||
| 227 | final public function getInput() |
||
| 228 | { |
||
| 229 | return $this->input; |
||
| 230 | } |
||
| 231 | |||
| 232 | /** |
||
| 233 | * Retrieve the prefix for this routing instance. |
||
| 234 | * |
||
| 235 | * @return string The prefix. |
||
| 236 | * |
||
| 237 | * @author Dominik del Bondio <[email protected]> |
||
| 238 | * @since 0.11.0 |
||
| 239 | */ |
||
| 240 | final public function getPrefix() |
||
| 241 | { |
||
| 242 | return $this->prefix; |
||
| 243 | } |
||
| 244 | |||
| 245 | /** |
||
| 246 | * Adds a route to this routing instance. |
||
| 247 | * |
||
| 248 | * @param string $route A string with embedded regexp. |
||
| 249 | * @param array $options An array with options. The array can contain following |
||
| 250 | * items: |
||
| 251 | * <ul> |
||
| 252 | * <li>name</li> |
||
| 253 | * <li>stop</li> |
||
| 254 | * <li>output_type</li> |
||
| 255 | * <li>module</li> |
||
| 256 | * <li>controller</li> |
||
| 257 | * <li>parameters</li> |
||
| 258 | * <li>ignores</li> |
||
| 259 | * <li>defaults</li> |
||
| 260 | * <li>childs</li> |
||
| 261 | * <li>callbacks</li> |
||
| 262 | * <li>imply</li> |
||
| 263 | * <li>cut</li> |
||
| 264 | * <li>source</li> |
||
| 265 | * </ul> |
||
| 266 | * @param string $parent The name of the parent route (if any). |
||
| 267 | * |
||
| 268 | * @return string The name of the route. |
||
| 269 | * |
||
| 270 | * @author Dominik del Bondio <[email protected]> |
||
| 271 | * @since 0.11.0 |
||
| 272 | */ |
||
| 273 | public function addRoute($route, array $options = array(), $parent = null) |
||
| 274 | { |
||
| 275 | // catch the old options from the route which has to be overwritten |
||
| 276 | if (isset($options['name']) && isset($this->routes[$options['name']])) { |
||
| 277 | $defaultOpts = $this->routes[$options['name']]['opt']; |
||
| 278 | |||
| 279 | // when the parent is set and differs from the parent of the route to be overwritten bail out |
||
| 280 | if ($parent !== null && $defaultOpts['parent'] != $parent) { |
||
| 281 | throw new AgaviException('You are trying to overwrite a route but are not staying in the same hierarchy'); |
||
| 282 | } |
||
| 283 | |||
| 284 | if ($parent === null) { |
||
| 285 | $parent = $defaultOpts['parent']; |
||
| 286 | } else { |
||
| 287 | $defaultOpts['parent'] = $parent; |
||
| 288 | } |
||
| 289 | } else { |
||
| 290 | $defaultOpts = array('name' => Toolkit::uniqid(), 'stop' => true, 'output_type' => null, 'module' => null, 'controller' => null, 'parameters' => array(), 'ignores' => array(), 'defaults' => array(), 'childs' => array(), 'callbacks' => array(), 'imply' => false, 'cut' => null, 'source' => null, 'method' => null, 'constraint' => array(), 'locale' => null, 'pattern_parameters' => array(), 'optional_parameters' => array(), 'parent' => $parent, 'reverseStr' => '', 'nostops' => array(), 'anchor' => self::ANCHOR_NONE); |
||
| 291 | } |
||
| 292 | // retain backwards compatibility to 0.11 |
||
| 293 | if (isset($options['callback'])) { |
||
| 294 | $options['callbacks'] = array(array('class' => $options['callback'], 'parameters' => array())); |
||
| 295 | unset($options['callback']); |
||
| 296 | } |
||
| 297 | |||
| 298 | if (isset($options['defaults'])) { |
||
| 299 | foreach ($options['defaults'] as $name => &$value) { |
||
| 300 | $val = $pre = $post = null; |
||
|
0 ignored issues
–
show
$val 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 Loading history...
|
|||
| 301 | if (preg_match('#(.*)\{(.*)\}(.*)#', $value, $match)) { |
||
| 302 | $pre = $match[1]; |
||
| 303 | $val = $match[2]; |
||
| 304 | $post = $match[3]; |
||
| 305 | } else { |
||
| 306 | $val = $value; |
||
| 307 | } |
||
| 308 | |||
| 309 | $value = $this->createValue($val)->setPrefix($pre)->setPostfix($post); |
||
| 310 | } |
||
| 311 | } |
||
| 312 | |||
| 313 | // set the default options + user opts |
||
| 314 | $options = array_merge($defaultOpts, $options); |
||
| 315 | list($regexp, $options['reverseStr'], $routeParams, $options['anchor']) = $this->parseRouteString($route); |
||
| 316 | |||
| 317 | $params = array(); |
||
| 318 | |||
| 319 | // transfer the parameters and fill available automatic defaults |
||
| 320 | foreach ($routeParams as $name => $param) { |
||
| 321 | $params[] = $name; |
||
| 322 | |||
| 323 | if ($param['is_optional']) { |
||
| 324 | $options['optional_parameters'][$name] = true; |
||
| 325 | } |
||
| 326 | |||
| 327 | if (!isset($options['defaults'][$name]) && ($param['pre'] || $param['val'] || $param['post'])) { |
||
| 328 | unset($param['is_optional']); |
||
| 329 | $options['defaults'][$name] = $this->createValue($param['val'])->setPrefix($param['pre'])->setPostfix($param['post']); |
||
| 330 | } |
||
| 331 | } |
||
| 332 | |||
| 333 | $options['pattern_parameters'] = $params; |
||
| 334 | |||
| 335 | // remove all ignore from the parameters in the route |
||
| 336 | foreach ($options['ignores'] as $ignore) { |
||
| 337 | if (($key = array_search($ignore, $params)) !== false) { |
||
| 338 | unset($params[$key]); |
||
| 339 | } |
||
| 340 | } |
||
| 341 | |||
| 342 | $routeName = $options['name']; |
||
| 343 | |||
| 344 | // parse all the setting values for dynamic variables |
||
| 345 | // check if 2 nodes with the same name in the same execution tree exist |
||
| 346 | foreach ($this->routes as $name => $route) { |
||
| 347 | // if a route with this route as parent exist check if its really a child of our route |
||
| 348 | if ($route['opt']['parent'] == $routeName && !in_array($name, $options['childs'])) { |
||
| 349 | throw new AgaviException('The route ' . $routeName . ' specifies a child route with the same name'); |
||
| 350 | } |
||
| 351 | } |
||
| 352 | |||
| 353 | // direct childs/parents with the same name aren't caught by the above check |
||
| 354 | if ($routeName == $parent) { |
||
| 355 | throw new AgaviException('The route ' . $routeName . ' specifies a child route with the same name'); |
||
| 356 | } |
||
| 357 | |||
| 358 | // if we are a child route, we need add this route as a child to the parent |
||
| 359 | if ($parent !== null) { |
||
| 360 | foreach ($this->routes[$parent]['opt']['childs'] as $name) { |
||
| 361 | if ($name == $routeName) { |
||
| 362 | // we're overwriting a route, so unlike when first adding the route, there are more routes after this that might also be non-stopping, but we obviously don't want those, so we need to bail out at this point |
||
| 363 | break; |
||
| 364 | } |
||
| 365 | $route = $this->routes[$name]; |
||
| 366 | if (!$route['opt']['stop']) { |
||
| 367 | $options['nostops'][] = $name; |
||
| 368 | } |
||
| 369 | } |
||
| 370 | $this->routes[$parent]['opt']['childs'][] = $routeName; |
||
| 371 | } else { |
||
| 372 | foreach ($this->routes as $name => $route) { |
||
| 373 | if ($name == $routeName) { |
||
| 374 | // we're overwriting a route, so unlike when first adding the route, there are more routes after this that might also be non-stopping, but we obviously don't want those, so we need to bail out at this point |
||
| 375 | break; |
||
| 376 | } |
||
| 377 | if (!$route['opt']['stop'] && !$route['opt']['parent']) { |
||
| 378 | $options['nostops'][] = $name; |
||
| 379 | } |
||
| 380 | } |
||
| 381 | } |
||
| 382 | |||
| 383 | // make sure we have no duplicates in the nostops (can happen when a route is overwritten) |
||
| 384 | $options['nostops'] = array_unique($options['nostops']); |
||
| 385 | |||
| 386 | $route = array('rxp' => $regexp, 'par' => $params, 'opt' => $options, 'matches' => array()); |
||
| 387 | $this->routes[$routeName] = $route; |
||
| 388 | |||
| 389 | return $routeName; |
||
| 390 | } |
||
| 391 | |||
| 392 | /** |
||
| 393 | * Retrieve the internal representation of the route info. |
||
| 394 | * |
||
| 395 | * @return array The info about all routes. |
||
| 396 | * |
||
| 397 | * @author Dominik del Bondio <[email protected]> |
||
| 398 | * @since 0.11.0 |
||
| 399 | */ |
||
| 400 | public function exportRoutes() |
||
| 401 | { |
||
| 402 | return $this->routes; |
||
| 403 | } |
||
| 404 | |||
| 405 | /** |
||
| 406 | * Sets the internal representation of the route info. |
||
| 407 | * |
||
| 408 | * @param array $route The info about all routes. |
||
|
0 ignored issues
–
show
There is no parameter named
$route. Did you maybe mean $routes?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not. Loading history...
|
|||
| 409 | * |
||
| 410 | * @author Dominik del Bondio <[email protected]> |
||
| 411 | * @since 0.11.0 |
||
| 412 | */ |
||
| 413 | public function importRoutes(array $routes) |
||
| 414 | { |
||
| 415 | $this->routes = $routes; |
||
| 416 | } |
||
| 417 | |||
| 418 | /** |
||
| 419 | * Retrieves the routes which need to be taken into account when generating |
||
| 420 | * the reverse string of a routing to be generated. |
||
| 421 | * |
||
| 422 | * @param string $route The route name(s, delimited by +) to calculate. |
||
| 423 | * @param bool $isNullRoute Set to true if the requested route was 'null' or |
||
| 424 | * 'null' + 'xxx' |
||
| 425 | * |
||
| 426 | * @return array A list of names of affected routes. |
||
| 427 | * |
||
| 428 | * @author Dominik del Bondio <[email protected]> |
||
| 429 | * @since 0.11.0 |
||
| 430 | */ |
||
| 431 | public function getAffectedRoutes($route, &$isNullRoute = false) |
||
| 432 | { |
||
| 433 | $includedRoutes = array(); |
||
| 434 | $excludedRoutes = array(); |
||
| 435 | |||
| 436 | if ($route === null) { |
||
| 437 | $includedRoutes = array_reverse($this->getContext()->getRequest()->getAttribute('matched_routes', 'org.agavi.routing', array())); |
||
| 438 | $isNullRoute = true; |
||
| 439 | } elseif (strlen($route) > 0) { |
||
| 440 | if ($route[0] == '-' || $route[0] == '+') { |
||
| 441 | $includedRoutes = array_reverse($this->getContext()->getRequest()->getAttribute('matched_routes', 'org.agavi.routing', array())); |
||
| 442 | $isNullRoute = true; |
||
| 443 | } |
||
| 444 | |||
| 445 | $routeParts = preg_split('#(-|\+)#', $route, -1, PREG_SPLIT_DELIM_CAPTURE); |
||
| 446 | $prevDelimiter = '+'; |
||
| 447 | foreach ($routeParts as $part) { |
||
| 448 | if ($part == '+' || $part == '-') { |
||
| 449 | $prevDelimiter = $part; |
||
| 450 | } |
||
| 451 | |||
| 452 | if ($prevDelimiter == '+') { |
||
| 453 | $includedRoutes[] = $part; |
||
| 454 | } else { // $prevDelimiter == '-' |
||
| 455 | $excludedRoutes[] = $part; |
||
| 456 | } |
||
| 457 | } |
||
| 458 | } |
||
| 459 | |||
| 460 | $excludedRoutes = array_flip($excludedRoutes); |
||
| 461 | |||
| 462 | if ($includedRoutes) { |
||
|
0 ignored issues
–
show
The expression
$includedRoutes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||
| 463 | $route = $includedRoutes[0]; |
||
| 464 | // TODO: useful comment here |
||
| 465 | unset($includedRoutes[0]); |
||
| 466 | } |
||
| 467 | |||
| 468 | $myRoutes = array(); |
||
| 469 | foreach ($includedRoutes as $r) { |
||
| 470 | $myRoutes[$r] = true; |
||
| 471 | } |
||
| 472 | |||
| 473 | $affectedRoutes = array(); |
||
| 474 | |||
| 475 | if (isset($this->routes[$route])) { |
||
| 476 | $parent = $route; |
||
| 477 | do { |
||
| 478 | if (!isset($excludedRoutes[$parent])) { |
||
| 479 | $affectedRoutes[] = $parent; |
||
| 480 | } |
||
| 481 | $r = $this->routes[$parent]; |
||
| 482 | |||
| 483 | foreach (array_reverse($r['opt']['nostops']) as $noStop) { |
||
| 484 | $myR = $this->routes[$noStop]; |
||
| 485 | if (isset($myRoutes[$noStop])) { |
||
| 486 | unset($myRoutes[$noStop]); |
||
| 487 | } elseif (!$myR['opt']['imply']) { |
||
| 488 | continue; |
||
| 489 | } |
||
| 490 | |||
| 491 | if (!isset($excludedRoutes[$noStop])) { |
||
| 492 | $affectedRoutes[] = $noStop; |
||
| 493 | } |
||
| 494 | } |
||
| 495 | |||
| 496 | $parent = $r['opt']['parent']; |
||
| 497 | } while ($parent); |
||
| 498 | } else { |
||
|
0 ignored issues
–
show
This
else statement is empty and can be removed.
This check looks for the These if (rand(1, 6) > 3) {
print "Check failed";
} else {
//print "Check succeeded";
}
could be turned into if (rand(1, 6) > 3) {
print "Check failed";
}
This is much more concise to read. Loading history...
|
|||
| 499 | // TODO: error handling - route with the given name does not exist |
||
| 500 | } |
||
| 501 | |||
| 502 | if (count($myRoutes)) { |
||
|
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. Loading history...
|
|||
| 503 | // TODO: error handling - we couldn't find some of the nonstopping rules |
||
| 504 | } |
||
| 505 | |||
| 506 | return $affectedRoutes; |
||
| 507 | } |
||
| 508 | |||
| 509 | /** |
||
| 510 | * Get a list of all parameter matches which where matched in execute() |
||
| 511 | * in the given routes. |
||
| 512 | * |
||
| 513 | * @param array $routeNames An array of route names. |
||
| 514 | * |
||
| 515 | * @return array The matched parameters as name => value. |
||
| 516 | * |
||
| 517 | * @author Dominik del Bondio <[email protected]> |
||
| 518 | * @since 1.0.0 |
||
| 519 | */ |
||
| 520 | public function getMatchedParameters(array $routeNames) |
||
| 521 | { |
||
| 522 | $params = array(); |
||
| 523 | foreach ($routeNames as $name) { |
||
| 524 | if (isset($this->routes[$name])) { |
||
| 525 | $route = $this->routes[$name]; |
||
| 526 | $params = array_merge($params, $route['matches']); |
||
| 527 | } |
||
| 528 | } |
||
| 529 | return $params; |
||
| 530 | } |
||
| 531 | |||
| 532 | /** |
||
| 533 | * Get a complete list of gen() options based on the given, probably |
||
| 534 | * incomplete, options array, and/or options preset name(s). |
||
| 535 | * |
||
| 536 | * @param mixed $input An array of gen options and names of options presets |
||
| 537 | * or just the name of a single option preset. |
||
| 538 | * |
||
| 539 | * @return array A complete array of options. |
||
| 540 | * |
||
| 541 | * @throws \Exception If the given preset name doesn't exist. |
||
| 542 | * |
||
| 543 | * @author David Zülke <[email protected]> |
||
| 544 | * @since 0.11.0 |
||
| 545 | */ |
||
| 546 | protected function resolveGenOptions($input = array()) |
||
| 547 | { |
||
| 548 | if (is_string($input)) { |
||
| 549 | // A single option preset was given |
||
| 550 | if (isset($this->genOptionsPresets[$input])) { |
||
| 551 | return array_merge($this->defaultGenOptions, $this->genOptionsPresets[$input]); |
||
| 552 | } |
||
| 553 | } elseif (is_array($input)) { |
||
| 554 | $genOptions = $this->defaultGenOptions; |
||
| 555 | foreach ($input as $key => $value) { |
||
| 556 | if (is_numeric($key)) { |
||
| 557 | // Numeric key – it's an option preset |
||
| 558 | if (isset($this->genOptionsPresets[$value])) { |
||
| 559 | $genOptions = array_merge($genOptions, $this->genOptionsPresets[$value]); |
||
| 560 | } else { |
||
| 561 | throw new AgaviException('Undefined Routing gen() options preset "' . $value . '"'); |
||
| 562 | } |
||
| 563 | } else { |
||
| 564 | // String key – it's an option |
||
| 565 | $genOptions[$key] = $value; |
||
| 566 | } |
||
| 567 | } |
||
| 568 | return $genOptions; |
||
| 569 | } |
||
| 570 | throw new AgaviException('Unexpected type "' . gettype($input) . '" used as Routing gen() option preset identifier'); |
||
| 571 | } |
||
| 572 | |||
| 573 | /** |
||
| 574 | * Adds the matched parameters from the 'null' routes to the given parameters |
||
| 575 | * (without overwriting existing ones) |
||
| 576 | * |
||
| 577 | * @param array $routeNames The route names |
||
| 578 | * @param array $params The parameters |
||
| 579 | * |
||
| 580 | * @return array The new parameters |
||
| 581 | * |
||
| 582 | * @author Dominik del Bondio <[email protected]> |
||
| 583 | * @since 1.0.0 |
||
| 584 | */ |
||
| 585 | public function fillGenNullParameters(array $routeNames, array $params) |
||
| 586 | { |
||
| 587 | return array_merge($this->getMatchedParameters($routeNames), $params); |
||
| 588 | } |
||
| 589 | |||
| 590 | /** |
||
| 591 | * Builds the routing information (result string, all kinds of parameters) |
||
| 592 | * for the given routes. |
||
| 593 | * |
||
| 594 | * @param array $options The options |
||
| 595 | * @param array $routeNames The names of the routes to generate |
||
| 596 | * @param array $params The parameters supplied by the user |
||
| 597 | * |
||
| 598 | * @return array |
||
| 599 | * |
||
| 600 | * @author Dominik del Bondio <[email protected]> |
||
| 601 | * @since 1.0.0 |
||
| 602 | */ |
||
| 603 | protected function assembleRoutes(array $options, array $routeNames, array $params) |
||
| 604 | { |
||
| 605 | $uri = ''; |
||
| 606 | $defaultParams = array(); |
||
| 607 | $availableParams = array(); |
||
| 608 | $matchedParams = array(); // the merged incoming matched params of implied routes |
||
| 609 | $optionalParams = array(); |
||
| 610 | $firstRoute = true; |
||
| 611 | |||
| 612 | foreach ($routeNames as $routeName) { |
||
| 613 | $r = $this->routes[$routeName]; |
||
| 614 | |||
| 615 | $myDefaults = $r['opt']['defaults']; |
||
| 616 | |||
| 617 | if (count($r['opt']['callbacks']) > 0) { |
||
| 618 | View Code Duplication | if (!isset($r['callback_instances'])) { |
|
|
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. Loading history...
|
|||
| 619 | foreach ($r['opt']['callbacks'] as $key => $callback) { |
||
| 620 | /** @var RoutingCallback $instance */ |
||
| 621 | $instance = new $callback['class'](); |
||
| 622 | $instance->setParameters($callback['parameters']); |
||
| 623 | $instance->initialize($this->context, $r); |
||
| 624 | $r['callback_instances'][$key] = $instance; |
||
| 625 | } |
||
| 626 | } |
||
| 627 | foreach ($r['callback_instances'] as $callbackInstance) { |
||
| 628 | $paramsCopy = $params; |
||
| 629 | $isLegacyCallback = false; |
||
| 630 | if ($callbackInstance instanceof LegacyRoutingCallbackInterface) { |
||
| 631 | $isLegacyCallback = true; |
||
| 632 | // convert all routing values to strings so legacy callbacks don't break |
||
| 633 | $defaultsCopy = $myDefaults; |
||
| 634 | foreach ($paramsCopy as &$param) { |
||
| 635 | if ($param instanceof RoutingValueInterface) { |
||
| 636 | $param = $param->getValue(); |
||
| 637 | } |
||
| 638 | } |
||
| 639 | foreach ($defaultsCopy as &$default) { |
||
| 640 | if ($default instanceof RoutingValueInterface) { |
||
| 641 | $default = array( |
||
| 642 | 'pre' => $default->getPrefix(), |
||
| 643 | 'val' => $default->getValue(), |
||
| 644 | 'post' => $default->getPostfix(), |
||
| 645 | ); |
||
| 646 | } |
||
| 647 | } |
||
| 648 | $changedParamsCopy = $paramsCopy; |
||
| 649 | if (!$callbackInstance->onGenerate($defaultsCopy, $paramsCopy, $options)) { |
||
|
0 ignored issues
–
show
The method
onGenerate() does not seem to exist on object<Agavi\Routing\Leg...utingCallbackInterface>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 650 | continue 2; |
||
| 651 | } |
||
| 652 | // find all params changed in the callback, but ignore unset() parameters since they will be filled in at a later stage (and doing something the them would prevent default values being inserted after unset()tting of a parameter) |
||
| 653 | $diff = array(); |
||
| 654 | foreach ($paramsCopy as $key => $value) { |
||
| 655 | if (!array_key_exists($key, $changedParamsCopy) || $changedParamsCopy[$key] !== $value) { |
||
| 656 | $diff[$key] = $value; |
||
| 657 | } |
||
| 658 | } |
||
| 659 | // do *not* use this instead, it will segfault in PHP < 5.2.6: |
||
| 660 | // $diff = array_udiff_assoc($paramsCopy, $changedParamsCopy, array($this, 'onGenerateParamDiffCallback')); |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% 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. Loading history...
|
|||
| 661 | // likely caused by http://bugs.php.net/bug.php?id=42838 / http://cvs.php.net/viewvc.cgi/php-src/ext/standard/array.c?r1=1.308.2.21.2.51&r2=1.308.2.21.2.52 |
||
| 662 | } else { |
||
| 663 | if (!$callbackInstance->onGenerate($myDefaults, $params, $options)) { |
||
| 664 | continue 2; |
||
| 665 | } |
||
| 666 | // find all params changed in the callback, but ignore unset() parameters since they will be filled in at a later stage (and doing something the them would prevent default values being inserted after unset()tting of a parameter) |
||
| 667 | $diff = array(); |
||
| 668 | View Code Duplication | foreach ($params as $key => $value) { |
|
|
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. Loading history...
|
|||
| 669 | if (!array_key_exists($key, $paramsCopy) || $paramsCopy[$key] !== $value) { |
||
| 670 | $diff[$key] = $value; |
||
| 671 | } |
||
| 672 | } |
||
| 673 | // do *not* use this instead, it will segfault in PHP < 5.2.6: |
||
| 674 | // $diff = array_udiff_assoc($params, $paramsCopy, array($this, 'onGenerateParamDiffCallback')); |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% 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. Loading history...
|
|||
| 675 | // likely caused by http://bugs.php.net/bug.php?id=42838 / http://cvs.php.net/viewvc.cgi/php-src/ext/standard/array.c?r1=1.308.2.21.2.51&r2=1.308.2.21.2.52 |
||
| 676 | } |
||
| 677 | |||
| 678 | if (count($diff)) { |
||
| 679 | $diffKeys = array_keys($diff); |
||
| 680 | foreach ($diffKeys as $key) { |
||
| 681 | // NEVER assign this value as a reference, as PHP will go completely bonkers if we use a reference here (it marks the entry in the array as a reference, so modifying the value in $params in a callback means it gets modified in $paramsCopy as well) |
||
| 682 | // if the callback was a legacy callback, the array to read the values from is different (since everything was cast to strings before running the callback) |
||
| 683 | $value = $isLegacyCallback ? $paramsCopy[$key] : $params[$key]; |
||
| 684 | if ($value !== null && !($value instanceof RoutingValueInterface)) { |
||
| 685 | $routingValue = $this->createValue($value, false); |
||
| 686 | if (isset($myDefaults[$key])) { |
||
| 687 | if ($myDefaults[$key] instanceof RoutingValueInterface) { |
||
| 688 | // clone the default value so pre and postfix are preserved |
||
| 689 | /** @var RoutingValue $routingValue */ |
||
| 690 | $routingValue = clone $myDefaults[$key]; |
||
| 691 | // BC: When setting a value in a callback it was supposed to be already encoded |
||
| 692 | $routingValue->setValue($value)->setValueNeedsEncoding(false); |
||
| 693 | } else { |
||
| 694 | // $myDefaults[$key] can only be an array at this stage |
||
| 695 | $routingValue->setPrefix($myDefaults[$key]['pre'])->setPrefixNeedsEncoding(false); |
||
| 696 | $routingValue->setPostfix($myDefaults[$key]['post'])->setPostfixNeedsEncoding(false); |
||
| 697 | } |
||
| 698 | } |
||
| 699 | $value = $routingValue; |
||
| 700 | } |
||
| 701 | // for writing no legacy check mustn't be done, since that would mean the changed value would get lost |
||
| 702 | $params[$key] = $value; |
||
| 703 | } |
||
| 704 | } |
||
| 705 | } |
||
| 706 | } |
||
| 707 | |||
| 708 | // if the route has a source we shouldn't put its stuff in the generated string |
||
| 709 | if ($r['opt']['source']) { |
||
| 710 | continue; |
||
| 711 | } |
||
| 712 | |||
| 713 | $matchedParams = array_merge($matchedParams, $r['matches']); |
||
| 714 | $optionalParams = array_merge($optionalParams, $r['opt']['optional_parameters']); |
||
| 715 | |||
| 716 | $availableParams = array_merge($availableParams, array_reverse($r['opt']['pattern_parameters'])); |
||
| 717 | |||
| 718 | if ($firstRoute || $r['opt']['cut'] || (count($r['opt']['childs']) && $r['opt']['cut'] === null)) { |
||
| 719 | if ($r['opt']['anchor'] & self::ANCHOR_START || $r['opt']['anchor'] == self::ANCHOR_NONE) { |
||
| 720 | $uri = $r['opt']['reverseStr'] . $uri; |
||
| 721 | } else { |
||
| 722 | $uri = $uri . $r['opt']['reverseStr']; |
||
| 723 | } |
||
| 724 | } |
||
| 725 | |||
| 726 | $defaultParams = array_merge($defaultParams, $myDefaults); |
||
| 727 | $firstRoute = false; |
||
| 728 | } |
||
| 729 | |||
| 730 | $availableParams = array_reverse($availableParams); |
||
| 731 | |||
| 732 | return array( |
||
| 733 | 'uri' => $uri, |
||
| 734 | 'options' => $options, |
||
| 735 | 'user_parameters' => $params, |
||
| 736 | 'available_parameters' => $availableParams, |
||
| 737 | 'matched_parameters' => $matchedParams, |
||
| 738 | 'optional_parameters' => $optionalParams, |
||
| 739 | 'default_parameters' => $defaultParams, |
||
| 740 | ); |
||
| 741 | } |
||
| 742 | |||
| 743 | /** |
||
| 744 | * Adds all matched parameters to the supplied parameters. Will not overwrite |
||
| 745 | * already existing parameters. |
||
| 746 | * |
||
| 747 | * @param array $options The options |
||
| 748 | * @param array $params The parameters supplied by the user |
||
| 749 | * @param array $matchedParams The parameters which matched in execute() |
||
| 750 | * |
||
| 751 | * @return array The $params with the added matched parameters |
||
| 752 | * |
||
| 753 | * @author Dominik del Bondio <[email protected]> |
||
| 754 | * @since 1.0.0 |
||
| 755 | */ |
||
| 756 | protected function refillAllMatchedParameters(array $options, array $params, array $matchedParams) |
||
| 757 | { |
||
| 758 | if (!empty($options['refill_all_parameters'])) { |
||
| 759 | View Code Duplication | foreach ($matchedParams as $name => $value) { |
|
|
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. Loading history...
|
|||
| 760 | if (!(isset($params[$name]) || array_key_exists($name, $params))) { |
||
| 761 | $params[$name] = $this->createValue($value, true); |
||
| 762 | } |
||
| 763 | } |
||
| 764 | } |
||
| 765 | |||
| 766 | return $params; |
||
| 767 | } |
||
| 768 | |||
| 769 | /** |
||
| 770 | * Adds all parameters which were matched in the incoming routes to the |
||
| 771 | * generated route up the first user supplied parameter (from left to right) |
||
| 772 | * Also adds the default value for all non optional parameters the user |
||
| 773 | * didn't supply. |
||
| 774 | * |
||
| 775 | * @param array $options The options |
||
| 776 | * @param array $originalUserParams The parameters originally passed to gen() |
||
| 777 | * @param array $params The parameters |
||
| 778 | * @param array $availableParams A list of parameter names available for the route |
||
| 779 | * @param array $matchedParams The matched parameters from execute() for the route |
||
| 780 | * @param array $optionalParams the optional parameters for the route |
||
| 781 | * @param array $defaultParams the default parameters for the route |
||
| 782 | * |
||
| 783 | * @return array The 'final' parameters |
||
| 784 | * |
||
| 785 | * @author Dominik del Bondio <[email protected]> |
||
| 786 | * @since 1.0.0 |
||
| 787 | */ |
||
| 788 | protected function refillMatchedAndDefaultParameters(array $options, array $originalUserParams, array $params, array $availableParams, array $matchedParams, array $optionalParams, array $defaultParams) |
||
|
0 ignored issues
–
show
|
|||
| 789 | { |
||
| 790 | $refillValue = true; |
||
| 791 | $finalParams = array(); |
||
| 792 | foreach ($availableParams as $name) { |
||
| 793 | // loop all params and fill all with the matched parameters |
||
| 794 | // until a user (not callback) supplied parameter is encountered. |
||
| 795 | // After that only check defaults. Parameters supplied from the user |
||
| 796 | // or via callback always have precedence |
||
| 797 | |||
| 798 | // keep track if a user supplied parameter has already been encountered |
||
| 799 | if ($refillValue && (isset($originalUserParams[$name]) || array_key_exists($name, $originalUserParams))) { |
||
| 800 | $refillValue = false; |
||
| 801 | } |
||
| 802 | |||
| 803 | // these 'aliases' are just for readability of the lower block |
||
| 804 | $isOptional = isset($optionalParams[$name]); |
||
| 805 | $hasMatched = isset($matchedParams[$name]); |
||
| 806 | $hasDefault = isset($defaultParams[$name]); |
||
| 807 | $hasUserCallbackParam = (isset($params[$name]) || array_key_exists($name, $params)); |
||
| 808 | |||
| 809 | if ($hasUserCallbackParam) { |
||
|
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. Loading history...
|
|||
| 810 | // anything a user or callback supplied has precedence |
||
| 811 | // and since the user params are handled afterwards, skip them here |
||
| 812 | } elseif ($refillValue && $hasMatched) { |
||
| 813 | // Use the matched input |
||
| 814 | $finalParams[$name] = $this->createValue($matchedParams[$name], true); |
||
| 815 | } elseif ($hasDefault) { |
||
| 816 | // now we just need to check if there are defaults for this available param and fill them in if applicable |
||
| 817 | $default = $defaultParams[$name]; |
||
| 818 | if (!$isOptional || strlen($default->getValue()) > 0) { |
||
| 819 | $finalParams[$name] = clone $default; |
||
| 820 | } elseif ($isOptional) { |
||
| 821 | // there is no default or incoming match for this optional param, so remove it |
||
| 822 | $finalParams[$name] = null; |
||
| 823 | } |
||
| 824 | } |
||
| 825 | } |
||
| 826 | |||
| 827 | return $finalParams; |
||
| 828 | } |
||
| 829 | |||
| 830 | /** |
||
| 831 | * Adds the user supplied parameters to the 'final' parameters for the route. |
||
| 832 | * |
||
| 833 | * @param array $options The options |
||
| 834 | * @param array $params The user parameters |
||
| 835 | * @param array $finalParams The 'final' parameters |
||
| 836 | * @param array $availableParams A list of parameter names available for the route |
||
| 837 | * @param array $optionalParams the optional parameters for the route |
||
| 838 | * @param array $defaultParams the default parameters for the route |
||
| 839 | * |
||
| 840 | * @return array The 'final' parameters |
||
| 841 | * |
||
| 842 | * @author Dominik del Bondio <[email protected]> |
||
| 843 | * @since 1.0.0 |
||
| 844 | */ |
||
| 845 | protected function fillUserParameters(array $options, array $params, array $finalParams, array $availableParams, array $optionalParams, array $defaultParams) |
||
|
0 ignored issues
–
show
|
|||
| 846 | { |
||
| 847 | $availableParamsAsKeys = array_flip($availableParams); |
||
| 848 | |||
| 849 | foreach ($params as $name => $param) { |
||
| 850 | if (!(isset($finalParams[$name]) || array_key_exists($name, $finalParams))) { |
||
| 851 | if ($param === null && isset($optionalParams[$name])) { |
||
| 852 | // null was set for an optional parameter |
||
| 853 | $finalParams[$name] = $param; |
||
| 854 | } else { |
||
| 855 | if (isset($defaultParams[$name])) { |
||
| 856 | if ($param === null || ($param instanceof RoutingValue && $param->getValue() === null)) { |
||
| 857 | // the user set the parameter to null, to signal that the default value should be used |
||
| 858 | $param = clone $defaultParams[$name]; |
||
| 859 | } |
||
| 860 | $finalParams[$name] = $param; |
||
| 861 | } elseif (isset($availableParamsAsKeys[$name])) { |
||
| 862 | // when the parameter was available in one of the routes |
||
| 863 | $finalParams[$name] = $param; |
||
| 864 | } |
||
| 865 | } |
||
| 866 | } |
||
| 867 | } |
||
| 868 | |||
| 869 | return $finalParams; |
||
| 870 | } |
||
| 871 | |||
| 872 | /** |
||
| 873 | * Adds the user supplied parameters to the 'final' parameters for the route. |
||
| 874 | * |
||
| 875 | * @param array $options The options |
||
| 876 | * @param array $finalParams The 'final' parameters |
||
| 877 | * @param array $availableParams A list of parameter names available for the route |
||
| 878 | * @param array $optionalParams the optional parameters for the route |
||
| 879 | * @param array $defaultParams the default parameters for the route |
||
| 880 | * |
||
| 881 | * @return array The 'final' parameters |
||
| 882 | * |
||
| 883 | * @author Dominik del Bondio <[email protected]> |
||
| 884 | * @since 1.0.0 |
||
| 885 | */ |
||
| 886 | protected function removeMatchingDefaults(array $options, array $finalParams, array $availableParams, array $optionalParams, array $defaultParams) |
||
| 887 | { |
||
| 888 | // if omit_defaults is set, we should not put optional values into the result string in case they are equal to their default value - even if they were given as a param |
||
| 889 | if (!empty($options['omit_defaults'])) { |
||
| 890 | // remove the optional parameters from the pattern beginning from right to the left, in case they are equal to their default |
||
| 891 | foreach (array_reverse($availableParams) as $name) { |
||
| 892 | if (isset($optionalParams[$name])) { |
||
| 893 | // the isset() could be replaced by |
||
| 894 | // "!array_key_exists($name, $finalParams) || $finalParams[$name] === null" |
||
| 895 | // to clarify that null is explicitly allowed here |
||
| 896 | if (!isset($finalParams[$name]) || |
||
| 897 | ( |
||
| 898 | isset($defaultParams[$name]) && |
||
| 899 | $finalParams[$name]->getValue() == $defaultParams[$name]->getValue() && |
||
| 900 | (!$finalParams[$name]->hasPrefix() || $finalParams[$name]->getPrefix() == $defaultParams[$name]->getPrefix()) && |
||
| 901 | (!$finalParams[$name]->hasPostfix() || $finalParams[$name]->getPostfix() == $defaultParams[$name]->getPostfix()) |
||
| 902 | ) |
||
| 903 | ) { |
||
| 904 | $finalParams[$name] = null; |
||
| 905 | } else { |
||
| 906 | break; |
||
| 907 | } |
||
| 908 | } else { |
||
| 909 | break; |
||
| 910 | } |
||
| 911 | } |
||
| 912 | } |
||
| 913 | |||
| 914 | return $finalParams; |
||
| 915 | } |
||
| 916 | |||
| 917 | /** |
||
| 918 | * Updates the pre and postfixes in the final params from the default |
||
| 919 | * pre and postfix if available and if it hasn't been set yet by the user. |
||
| 920 | * |
||
| 921 | * @param array $finalParams The 'final' parameters |
||
| 922 | * @param array $defaultParams the default parameters for the route |
||
| 923 | * |
||
| 924 | * @return array The 'final' parameters |
||
| 925 | * |
||
| 926 | * @author Dominik del Bondio <[email protected]> |
||
| 927 | * @since 1.0.0 |
||
| 928 | */ |
||
| 929 | protected function updatePrefixAndPostfix(array $finalParams, array $defaultParams) |
||
| 930 | { |
||
| 931 | foreach ($finalParams as $name => $param) { |
||
| 932 | if ($param === null) { |
||
| 933 | continue; |
||
| 934 | } |
||
| 935 | |||
| 936 | if (isset($defaultParams[$name])) { |
||
| 937 | // update the pre- and postfix from the default if they are not set in the routing value |
||
| 938 | $default = $defaultParams[$name]; |
||
| 939 | if (!$param->hasPrefix() && $default->hasPrefix()) { |
||
| 940 | $param->setPrefix($default->getPrefix()); |
||
| 941 | } |
||
| 942 | if (!$param->hasPostfix() && $default->hasPostfix()) { |
||
| 943 | $param->setPostfix($default->getPostfix()); |
||
| 944 | } |
||
| 945 | } |
||
| 946 | } |
||
| 947 | return $finalParams; |
||
| 948 | } |
||
| 949 | |||
| 950 | /** |
||
| 951 | * Encodes all 'final' parameters. |
||
| 952 | * |
||
| 953 | * @param array $options The 'final' parameters |
||
| 954 | * @param array $params The default parameters for the route |
||
| 955 | * |
||
| 956 | * @return array The 'final' parameters |
||
| 957 | * |
||
| 958 | * @author Dominik del Bondio <[email protected]> |
||
| 959 | * @since 1.0.0 |
||
| 960 | */ |
||
| 961 | protected function encodeParameters(array $options, array $params) |
||
|
0 ignored issues
–
show
|
|||
| 962 | { |
||
| 963 | foreach ($params as &$param) { |
||
| 964 | $param = $this->encodeParameter($param); |
||
| 965 | } |
||
| 966 | return $params; |
||
| 967 | } |
||
| 968 | |||
| 969 | /** |
||
| 970 | * Encodes a single parameter. |
||
| 971 | * |
||
| 972 | * @param mixed $parameter A RoutingValue object or a string |
||
| 973 | * |
||
| 974 | * @return string The encoded parameter |
||
| 975 | * |
||
| 976 | * @author Dominik del Bondio <[email protected]> |
||
| 977 | * @since 1.0.0 |
||
| 978 | */ |
||
| 979 | protected function encodeParameter($parameter) |
||
| 980 | { |
||
| 981 | if ($parameter instanceof RoutingValue) { |
||
| 982 | return sprintf('%s%s%s', |
||
| 983 | $parameter->getPrefixNeedsEncoding() ? $this->escapeOutputParameter($parameter->getPrefix()) : $parameter->getPrefix(), |
||
| 984 | $parameter->getValueNeedsEncoding() ? $this->escapeOutputParameter($parameter->getValue()) : $parameter->getValue(), |
||
| 985 | $parameter->getPostfixNeedsEncoding() ? $this->escapeOutputParameter($parameter->getPostfix()) : $parameter->getPostfix() |
||
| 986 | ); |
||
| 987 | } else { |
||
| 988 | return $this->escapeOutputParameter($parameter); |
||
| 989 | } |
||
| 990 | } |
||
| 991 | |||
| 992 | /** |
||
| 993 | * Converts all members of an array to AgaviIRoutingValues. |
||
| 994 | * |
||
| 995 | * @param array $parameters The parameters |
||
| 996 | * |
||
| 997 | * @return array An array containing all parameters as RoutingValues |
||
| 998 | * |
||
| 999 | * @author Dominik del Bondio <[email protected]> |
||
| 1000 | * @since 1.0.0 |
||
| 1001 | */ |
||
| 1002 | protected function convertParametersToRoutingValues(array $parameters) |
||
| 1003 | { |
||
| 1004 | if (count($parameters)) { |
||
| 1005 | // make sure everything in $parameters is a routing value |
||
| 1006 | foreach ($parameters as &$param) { |
||
| 1007 | if (!$param instanceof RoutingValue) { |
||
| 1008 | if ($param !== null) { |
||
| 1009 | $param = $this->createValue($param); |
||
| 1010 | } |
||
| 1011 | } else { |
||
| 1012 | // make sure the routing value the user passed to gen() is not modified |
||
| 1013 | $param = clone $param; |
||
| 1014 | } |
||
| 1015 | } |
||
| 1016 | return $parameters; |
||
| 1017 | } else { |
||
| 1018 | return array(); |
||
| 1019 | } |
||
| 1020 | } |
||
| 1021 | |||
| 1022 | /** |
||
| 1023 | * Generate a formatted Agavi URL. |
||
| 1024 | * |
||
| 1025 | * @param string $route A route name. |
||
| 1026 | * @param array $params An associative array of parameters. |
||
| 1027 | * @param mixed $options An array of options, or the name of an options preset. |
||
| 1028 | * |
||
| 1029 | * @return array An array containing the generated route path, the |
||
| 1030 | * (possibly modified) parameters, and the (possibly |
||
| 1031 | * modified) options. |
||
| 1032 | * |
||
| 1033 | * @author Dominik del Bondio <[email protected]> |
||
| 1034 | * @author David Zülke <[email protected]> |
||
| 1035 | * @since 0.11.0 |
||
| 1036 | */ |
||
| 1037 | public function gen($route, array $params = array(), $options = array()) |
||
| 1038 | { |
||
| 1039 | if (array_key_exists('prefix', $options)) { |
||
| 1040 | $prefix = (string) $options['prefix']; |
||
| 1041 | } else { |
||
| 1042 | $prefix = $this->getPrefix(); |
||
| 1043 | } |
||
| 1044 | |||
| 1045 | $isNullRoute = false; |
||
| 1046 | $routes = $this->getAffectedRoutes($route, $isNullRoute); |
||
| 1047 | |||
| 1048 | if (count($routes) == 0) { |
||
| 1049 | return array($route, array(), $options, $params, $isNullRoute); |
||
| 1050 | } |
||
| 1051 | |||
| 1052 | if ($isNullRoute) { |
||
| 1053 | // for gen(null) and friends all matched parameters are inserted before the |
||
| 1054 | // supplied params are backuped |
||
| 1055 | $params = $this->fillGenNullParameters($routes, $params); |
||
| 1056 | } |
||
| 1057 | |||
| 1058 | $params = $this->convertParametersToRoutingValues($params); |
||
| 1059 | // we need to store the original params since we will be trying to fill the |
||
| 1060 | // parameters up to the first user supplied parameter |
||
| 1061 | $originalParams = $params; |
||
| 1062 | |||
| 1063 | $assembledInformation = $this->assembleRoutes($options, $routes, $params); |
||
| 1064 | |||
| 1065 | $options = $assembledInformation['options']; |
||
| 1066 | |||
| 1067 | $params = $assembledInformation['user_parameters']; |
||
| 1068 | |||
| 1069 | $params = $this->refillAllMatchedParameters($options, $params, $assembledInformation['matched_parameters']); |
||
| 1070 | $finalParams = $this->refillMatchedAndDefaultParameters($options, $originalParams, $params, $assembledInformation['available_parameters'], $assembledInformation['matched_parameters'], $assembledInformation['optional_parameters'], $assembledInformation['default_parameters']); |
||
| 1071 | $finalParams = $this->fillUserParameters($options, $params, $finalParams, $assembledInformation['available_parameters'], $assembledInformation['optional_parameters'], $assembledInformation['default_parameters']); |
||
| 1072 | $finalParams = $this->removeMatchingDefaults($options, $finalParams, $assembledInformation['available_parameters'], $assembledInformation['optional_parameters'], $assembledInformation['default_parameters']); |
||
| 1073 | $finalParams = $this->updatePrefixAndPostfix($finalParams, $assembledInformation['default_parameters']); |
||
| 1074 | |||
| 1075 | // remember the params that are not in any pattern (could be extra query params, for example, set by a callback), use the parameter state after the callbacks have been run and defaults have been inserted. We also need to take originalParams into account for the case that a value was unset in a callback (which requires us to restore the old value). The array_merge is safe for this task since everything changed, etc appears in $params and overwrites the values from $originalParams |
||
| 1076 | $extras = array_diff_key(array_merge($originalParams, $params), $finalParams); |
||
| 1077 | // but since the values are expected as plain values and not routing values, convert the routing values back to |
||
| 1078 | // 'plain' values |
||
| 1079 | foreach ($extras as &$extra) { |
||
| 1080 | $extra = ($extra instanceof RoutingValue) ? $extra->getValue() : $extra; |
||
| 1081 | } |
||
| 1082 | |||
| 1083 | $params = $finalParams; |
||
| 1084 | |||
| 1085 | $params = $this->encodeParameters($options, $params); |
||
| 1086 | |||
| 1087 | $from = array(); |
||
| 1088 | $to = array(); |
||
| 1089 | |||
| 1090 | |||
| 1091 | // remove not specified available parameters |
||
| 1092 | foreach (array_unique($assembledInformation['available_parameters']) as $name) { |
||
| 1093 | if (!isset($params[$name])) { |
||
| 1094 | $from[] = '(:' . $name . ':)'; |
||
| 1095 | $to[] = ''; |
||
| 1096 | } |
||
| 1097 | } |
||
| 1098 | |||
| 1099 | foreach ($params as $n => $p) { |
||
| 1100 | $from[] = '(:' . $n . ':)'; |
||
| 1101 | $to[] = $p; |
||
| 1102 | } |
||
| 1103 | |||
| 1104 | $uri = str_replace($from, $to, $assembledInformation['uri']); |
||
| 1105 | return array($prefix . $uri, $params, $options, $extras, $isNullRoute); |
||
| 1106 | } |
||
| 1107 | |||
| 1108 | |||
| 1109 | /** |
||
| 1110 | * Escapes an argument to be used in an generated route. |
||
| 1111 | * |
||
| 1112 | * @param string $string The argument to be escaped. |
||
| 1113 | * |
||
| 1114 | * @return string The escaped argument. |
||
| 1115 | * |
||
| 1116 | * @author Dominik del Bondio <[email protected]> |
||
| 1117 | * @since 0.11.0 |
||
| 1118 | */ |
||
| 1119 | public function escapeOutputParameter($string) |
||
| 1120 | { |
||
| 1121 | return (string)$string; |
||
| 1122 | } |
||
| 1123 | |||
| 1124 | /** |
||
| 1125 | * Matches the input against the routing info and sets the info as request |
||
| 1126 | * parameter. |
||
| 1127 | * |
||
| 1128 | * @return mixed An ExecutionContainer as a result of this execution, |
||
| 1129 | * or an AgaviResponse if a callback returned one. |
||
| 1130 | * |
||
| 1131 | * @author Dominik del Bondio <[email protected]> |
||
| 1132 | * @since 0.11.0 |
||
| 1133 | */ |
||
| 1134 | public function execute() |
||
| 1135 | { |
||
| 1136 | $rq = $this->context->getRequest(); |
||
| 1137 | |||
| 1138 | $rd = $rq->getRequestData(); |
||
| 1139 | |||
| 1140 | $tm = $this->context->getTranslationManager(); |
||
| 1141 | |||
| 1142 | $container = $this->context->getDispatcher()->createExecutionContainer(); |
||
| 1143 | |||
| 1144 | if (!$this->isEnabled()) { |
||
| 1145 | // routing disabled, just bail out here |
||
| 1146 | return $container; |
||
| 1147 | } |
||
| 1148 | |||
| 1149 | $matchedRoutes = array(); |
||
| 1150 | |||
| 1151 | $input = $this->input; |
||
| 1152 | |||
| 1153 | $vars = array(); |
||
| 1154 | $ot = null; |
||
|
0 ignored issues
–
show
$ot 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 Loading history...
|
|||
| 1155 | $locale = null; |
||
|
0 ignored issues
–
show
$locale 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 Loading history...
|
|||
| 1156 | $method = null; |
||
|
0 ignored issues
–
show
$method 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 Loading history...
|
|||
| 1157 | |||
| 1158 | $umap = $rq->getParameter('use_module_controller_parameters'); |
||
| 1159 | $ma = $rq->getParameter('module_accessor'); |
||
| 1160 | $aa = $rq->getParameter('controller_accessor'); |
||
| 1161 | |||
| 1162 | $requestMethod = $rq->getMethod(); |
||
| 1163 | |||
| 1164 | $routes = array(); |
||
| 1165 | // get all top level routes |
||
| 1166 | foreach ($this->routes as $name => $route) { |
||
| 1167 | if (!$route['opt']['parent']) { |
||
| 1168 | $routes[] = $name; |
||
| 1169 | } |
||
| 1170 | } |
||
| 1171 | |||
| 1172 | // prepare the working stack with the root routes |
||
| 1173 | $routeStack = array($routes); |
||
| 1174 | |||
| 1175 | do { |
||
| 1176 | $routes = array_pop($routeStack); |
||
| 1177 | foreach ($routes as $key) { |
||
| 1178 | $route =& $this->routes[$key]; |
||
| 1179 | $opts =& $route['opt']; |
||
| 1180 | if (count($opts['constraint']) == 0 || in_array($requestMethod, $opts['constraint'])) { |
||
| 1181 | View Code Duplication | if (count($opts['callbacks']) > 0 && !isset($route['callback_instances'])) { |
|
|
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. Loading history...
|
|||
| 1182 | foreach ($opts['callbacks'] as $key => $callback) { |
||
| 1183 | /** @var RoutingCallback $instance */ |
||
| 1184 | $instance = new $callback['class'](); |
||
| 1185 | $instance->initialize($this->context, $route); |
||
| 1186 | $instance->setParameters($callback['parameters']); |
||
| 1187 | $route['callback_instances'][$key] = $instance; |
||
| 1188 | } |
||
| 1189 | } |
||
| 1190 | |||
| 1191 | $match = array(); |
||
| 1192 | if ($this->parseInput($route, $input, $match)) { |
||
| 1193 | $varsBackup = $vars; |
||
| 1194 | |||
| 1195 | // backup the container, must be done here already |
||
| 1196 | if (count($opts['callbacks']) > 0) { |
||
| 1197 | $containerBackup = $container; |
||
| 1198 | $container = clone $container; |
||
| 1199 | } |
||
| 1200 | |||
| 1201 | $ign = array(); |
||
| 1202 | if (count($opts['ignores']) > 0) { |
||
| 1203 | $ign = array_flip($opts['ignores']); |
||
| 1204 | } |
||
| 1205 | |||
| 1206 | /** |
||
| 1207 | * @var $value RoutingValue; |
||
| 1208 | */ |
||
| 1209 | foreach ($opts['defaults'] as $key => $value) { |
||
| 1210 | if (!isset($ign[$key]) && $value->getValue() !== null) { |
||
| 1211 | $vars[$key] = $value->getValue(); |
||
| 1212 | } |
||
| 1213 | } |
||
| 1214 | |||
| 1215 | foreach ($route['par'] as $param) { |
||
| 1216 | View Code Duplication | if (isset($match[$param]) && $match[$param][1] != -1) { |
|
|
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. Loading history...
|
|||
| 1217 | $vars[$param] = $match[$param][0]; |
||
| 1218 | } |
||
| 1219 | } |
||
| 1220 | |||
| 1221 | foreach ($match as $name => $m) { |
||
| 1222 | if (is_string($name) && $m[1] != -1) { |
||
| 1223 | $route['matches'][$name] = $m[0]; |
||
| 1224 | } |
||
| 1225 | } |
||
| 1226 | |||
| 1227 | // /* ! Only use the parameters from this route for expandVariables ! |
||
| 1228 | // matches are arrays with value and offset due to PREG_OFFSET_CAPTURE, and we want index 0, the value, which reset() will give us. Long story short, this removes the offset from the individual match |
||
| 1229 | $matchvals = array_map('reset', $match); |
||
| 1230 | // */ |
||
| 1231 | /* ! Use the parameters from ALL routes for expandVariables ! |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
47% 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. Loading history...
|
|||
| 1232 | $matchvals = $vars; |
||
| 1233 | // ignores need of the current route need to be added |
||
| 1234 | $foreach($opts['ignores'] as $ignore) { |
||
| 1235 | if(isset($match[$ignore]) && $match[$ignore][1] != -1) { |
||
| 1236 | $matchvals[$ignore] = $match[$ignore][0]; |
||
| 1237 | } |
||
| 1238 | } |
||
| 1239 | // */ |
||
| 1240 | |||
| 1241 | if ($opts['module']) { |
||
| 1242 | $module = Toolkit::expandVariables($opts['module'], $matchvals); |
||
| 1243 | $container->setModuleName($module); |
||
| 1244 | if ($umap) { |
||
| 1245 | $vars[$ma] = $module; |
||
| 1246 | } |
||
| 1247 | } |
||
| 1248 | |||
| 1249 | if ($opts['controller']) { |
||
| 1250 | $controller = Toolkit::expandVariables($opts['controller'], $matchvals); |
||
| 1251 | $container->setControllerName($controller); |
||
| 1252 | if ($umap) { |
||
| 1253 | $vars[$aa] = $controller; |
||
| 1254 | } |
||
| 1255 | } |
||
| 1256 | |||
| 1257 | if ($opts['output_type']) { |
||
| 1258 | // set the output type if necessary |
||
| 1259 | // here no explicit check is done, since in 0.11 this is compared against null |
||
| 1260 | // which can never be the result of expandVariables |
||
| 1261 | $ot = Toolkit::expandVariables($opts['output_type'], $matchvals); |
||
| 1262 | |||
| 1263 | // we need to wrap in try/catch here (but not further down after the callbacks have run) for BC |
||
| 1264 | // and because it makes sense - maybe a callback checks or changes the output type name |
||
| 1265 | try { |
||
| 1266 | $container->setOutputType($this->context->getDispatcher()->getOutputType($ot)); |
||
| 1267 | } catch (AgaviException $e) { |
||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
| 1268 | } |
||
| 1269 | } |
||
| 1270 | |||
| 1271 | if ($opts['locale']) { |
||
| 1272 | $localeBackup = $tm->getCurrentLocaleIdentifier(); |
||
| 1273 | |||
| 1274 | // set the locale if necessary |
||
| 1275 | if ($locale = Toolkit::expandVariables($opts['locale'], $matchvals)) { |
||
| 1276 | // the if is here for bc reasons, since if $opts['locale'] only contains variable parts |
||
| 1277 | // expandVariables could possibly return an empty string in which case the pre 1.0 routing |
||
| 1278 | // didn't set the variable |
||
| 1279 | |||
| 1280 | // we need to wrap in try/catch here (but not further down after the callbacks have run) for BC |
||
| 1281 | // and because it makes sense - maybe a callback checks or changes the locale name |
||
| 1282 | try { |
||
| 1283 | $tm->setLocale($locale); |
||
| 1284 | } catch (AgaviException $e) { |
||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||
| 1285 | } |
||
| 1286 | } |
||
| 1287 | } else { |
||
| 1288 | // unset it explicitly, so that further down, the isset() check doesn't set back a value from a previous iteration! |
||
| 1289 | $localeBackup = null; |
||
| 1290 | } |
||
| 1291 | |||
| 1292 | if ($opts['method']) { |
||
| 1293 | // set the request method if necessary |
||
| 1294 | if ($method = Toolkit::expandVariables($opts['method'], $matchvals)) { |
||
| 1295 | // the if is here for bc reasons, since if $opts['method'] only contains variable parts |
||
| 1296 | // expandVariables could possibly return an empty string in which case the pre 1.0 routing |
||
| 1297 | // didn't set the variable |
||
| 1298 | $rq->setMethod($method); |
||
| 1299 | // and on the already created container, too! |
||
| 1300 | $container->setRequestMethod($method); |
||
| 1301 | } |
||
| 1302 | } |
||
| 1303 | |||
| 1304 | if (count($opts['callbacks']) > 0) { |
||
| 1305 | if (count($opts['ignores']) > 0) { |
||
| 1306 | // add ignored variables to the callback vars |
||
| 1307 | foreach ($vars as $name => &$var) { |
||
| 1308 | $vars[$name] =& $var; |
||
| 1309 | } |
||
| 1310 | foreach ($opts['ignores'] as $ignore) { |
||
| 1311 | View Code Duplication | if (isset($match[$ignore]) && $match[$ignore][1] != -1) { |
|
|
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. Loading history...
|
|||
| 1312 | $vars[$ignore] = $match[$ignore][0]; |
||
| 1313 | } |
||
| 1314 | } |
||
| 1315 | } |
||
| 1316 | $callbackSuccess = true; |
||
| 1317 | /** @var RoutingCallback $callbackInstance */ |
||
| 1318 | foreach ($route['callback_instances'] as $callbackInstance) { |
||
| 1319 | // call onMatched on all callbacks until one of them returns false |
||
| 1320 | // then restore state and call onNotMatched on that same callback |
||
| 1321 | // after that, call onNotMatched for all remaining callbacks of that route |
||
| 1322 | if ($callbackSuccess) { |
||
| 1323 | // backup stuff which could be changed in the callback so we are |
||
| 1324 | // able to determine which values were changed in the callback |
||
| 1325 | $oldModule = $container->getModuleName(); |
||
| 1326 | $oldController = $container->getControllerName(); |
||
| 1327 | $oldOutputTypeName = $container->getOutputType() ? $container->getOutputType()->getName() : null; |
||
| 1328 | if (null === $tm) { |
||
| 1329 | $oldLocale = null; |
||
| 1330 | } else { |
||
| 1331 | $oldLocale = $tm->getCurrentLocaleIdentifier(); |
||
| 1332 | } |
||
| 1333 | $oldRequestMethod = $rq->getMethod(); |
||
| 1334 | $oldContainerMethod = $container->getRequestMethod(); |
||
| 1335 | |||
| 1336 | $onMatched = $callbackInstance->onMatched($vars, $container); |
||
| 1337 | if ($onMatched instanceof Response) { |
||
| 1338 | return $onMatched; |
||
| 1339 | } |
||
| 1340 | if (!$onMatched) { |
||
| 1341 | $callbackSuccess = false; |
||
| 1342 | |||
| 1343 | // reset the matches array. it must be populated by the time onMatched() is called so matches can be modified in a callback |
||
| 1344 | $route['matches'] = array(); |
||
| 1345 | // restore the variables from the variables which were set before this route matched |
||
| 1346 | $vars = $varsBackup; |
||
| 1347 | // reset all relevant container data we already set in the container for this (now non matching) route |
||
| 1348 | $container = $containerBackup; |
||
|
0 ignored issues
–
show
The variable
$containerBackup does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1349 | // restore locale |
||
| 1350 | if (isset($localeBackup)) { |
||
| 1351 | $tm->setLocale($localeBackup); |
||
| 1352 | } |
||
| 1353 | // restore request method |
||
| 1354 | $rq->setMethod($container->getRequestMethod()); |
||
| 1355 | } |
||
| 1356 | } |
||
| 1357 | |||
| 1358 | // always call onNotMatched if $callbackSuccess == false, even if we just called onMatched() on the same instance. this is expected behavior |
||
| 1359 | if (!$callbackSuccess) { |
||
| 1360 | $onNotMatched = $callbackInstance->onNotMatched($container); |
||
| 1361 | if ($onNotMatched instanceof Response) { |
||
| 1362 | return $onNotMatched; |
||
| 1363 | } |
||
| 1364 | |||
| 1365 | // continue with the next callback |
||
| 1366 | continue; |
||
| 1367 | } |
||
| 1368 | |||
| 1369 | // /* ! Only use the parameters from this route for expandVariables ! |
||
| 1370 | $expandVars = $vars; |
||
| 1371 | $routeParamsAsKey = array_flip($route['par']); |
||
| 1372 | // only use parameters which are defined in this route or are new |
||
| 1373 | foreach ($expandVars as $name => $value) { |
||
| 1374 | if (!isset($routeParamsAsKey[$name]) && array_key_exists($name, $varsBackup)) { |
||
| 1375 | unset($expandVars[$name]); |
||
| 1376 | } |
||
| 1377 | } |
||
| 1378 | // */ |
||
| 1379 | /* ! Use the parameters from ALL routes for expandVariables ! |
||
| 1380 | $expandVars = $vars; |
||
| 1381 | // */ |
||
| 1382 | |||
| 1383 | |||
| 1384 | // if the callback didn't change the value, execute expandVariables again since |
||
| 1385 | // the callback could have changed one of the values which expandVariables uses |
||
| 1386 | // to evaluate the contents of the attribute in question (e.g. module="${zomg}") |
||
| 1387 | View Code Duplication | if ($opts['module'] && $oldModule == $container->getModuleName() && (!$umap || !array_key_exists($ma, $vars) || $oldModule == $vars[$ma])) { |
|
|
0 ignored issues
–
show
The variable
$oldModule does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
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. Loading history...
|
|||
| 1388 | $module = Toolkit::expandVariables($opts['module'], $expandVars); |
||
| 1389 | $container->setModuleName($module); |
||
| 1390 | if ($umap) { |
||
| 1391 | $vars[$ma] = $module; |
||
| 1392 | } |
||
| 1393 | } |
||
| 1394 | View Code Duplication | if ($opts['controller'] && $oldController == $container->getControllerName() && (!$umap || !array_key_exists($aa, $vars) || $oldController == $vars[$aa])) { |
|
|
0 ignored issues
–
show
The variable
$oldController does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
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. Loading history...
|
|||
| 1395 | $controller = Toolkit::expandVariables($opts['controller'], $expandVars); |
||
| 1396 | $container->setControllerName($controller); |
||
| 1397 | if ($umap) { |
||
| 1398 | $vars[$aa] = $controller; |
||
| 1399 | } |
||
| 1400 | } |
||
| 1401 | if ($opts['output_type'] && $oldOutputTypeName == ($container->getOutputType() ? $container->getOutputType()->getName() : null)) { |
||
|
0 ignored issues
–
show
The variable
$oldOutputTypeName does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1402 | $ot = Toolkit::expandVariables($opts['output_type'], $expandVars); |
||
| 1403 | $container->setOutputType($this->context->getDispatcher()->getOutputType($ot)); |
||
| 1404 | } |
||
| 1405 | if ($opts['locale'] && $oldLocale == $tm->getCurrentLocaleIdentifier()) { |
||
|
0 ignored issues
–
show
The variable
$oldLocale does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1406 | if ($locale = Toolkit::expandVariables($opts['locale'], $expandVars)) { |
||
| 1407 | // see above for the reason of the if |
||
| 1408 | $tm->setLocale($locale); |
||
| 1409 | } |
||
| 1410 | } |
||
| 1411 | if ($opts['method']) { |
||
| 1412 | if ($oldRequestMethod == $rq->getMethod() && $oldContainerMethod == $container->getRequestMethod()) { |
||
| 1413 | if ($method = Toolkit::expandVariables($opts['method'], $expandVars)) { |
||
| 1414 | // see above for the reason of the if |
||
| 1415 | $rq->setMethod($method); |
||
| 1416 | $container->setRequestMethod($method); |
||
| 1417 | } |
||
| 1418 | } elseif ($oldContainerMethod != $container->getRequestMethod()) { |
||
|
0 ignored issues
–
show
The variable
$oldContainerMethod does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1419 | // copy the request method to the request (a method set on the container |
||
| 1420 | // in a callback always has precedence over request methods set on the request) |
||
| 1421 | $rq->setMethod($container->getRequestMethod()); |
||
| 1422 | } elseif ($oldRequestMethod != $rq->getMethod()) { |
||
|
0 ignored issues
–
show
The variable
$oldRequestMethod does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 1423 | // copy the request method to the container |
||
| 1424 | $container->setRequestMethod($rq->getMethod()); |
||
| 1425 | } |
||
| 1426 | } |
||
| 1427 | |||
| 1428 | // one last thing we need to do: see if one of the callbacks modified the 'controller' or 'module' vars inside $vars if $umap is on |
||
| 1429 | // we then need to write those back to the container, unless they changed THERE, too, in which case the container values take precedence |
||
| 1430 | if ($umap && $oldModule == $container->getModuleName() && array_key_exists($ma, $vars) && $vars[$ma] != $oldModule) { |
||
| 1431 | $container->setModuleName($vars[$ma]); |
||
| 1432 | } |
||
| 1433 | if ($umap && $oldController == $container->getControllerName() && array_key_exists($aa, $vars) && $vars[$aa] != $oldController) { |
||
| 1434 | $container->setControllerName($vars[$aa]); |
||
| 1435 | } |
||
| 1436 | } |
||
| 1437 | if (!$callbackSuccess) { |
||
| 1438 | // jump straight to the next route |
||
| 1439 | continue; |
||
| 1440 | } else { |
||
| 1441 | // We added the ignores to the route variables so the callback receives them, so restore them from vars backup. |
||
| 1442 | // Restoring them from the backup is necessary since otherwise a value which has been set before this route |
||
| 1443 | // and which was ignored in this route would take the ignored value instead of keeping the old one. |
||
| 1444 | // And variables which have not been set in an earlier routes need to be removed again |
||
| 1445 | foreach ($opts['ignores'] as $ignore) { |
||
| 1446 | if (array_key_exists($ignore, $varsBackup)) { |
||
| 1447 | $vars[$ignore] = $varsBackup[$ignore]; |
||
| 1448 | } else { |
||
| 1449 | unset($vars[$ignore]); |
||
| 1450 | } |
||
| 1451 | } |
||
| 1452 | } |
||
| 1453 | } |
||
| 1454 | |||
| 1455 | $matchedRoutes[] = $opts['name']; |
||
| 1456 | |||
| 1457 | if ($opts['cut'] || (count($opts['childs']) && $opts['cut'] === null)) { |
||
| 1458 | if ($route['opt']['source'] !== null) { |
||
| 1459 | $s =& $this->sources[$route['opt']['source']]; |
||
| 1460 | } else { |
||
| 1461 | $s =& $input; |
||
| 1462 | } |
||
| 1463 | |||
| 1464 | $ni = ''; |
||
| 1465 | // if the route didn't match from the start of the input preserve the 'prefix' |
||
| 1466 | if ($match[0][1] > 0) { |
||
| 1467 | $ni = substr($s, 0, $match[0][1]); |
||
| 1468 | } |
||
| 1469 | $ni .= substr($s, $match[0][1] + strlen($match[0][0])); |
||
| 1470 | $s = $ni; |
||
| 1471 | } |
||
| 1472 | |||
| 1473 | if (count($opts['childs'])) { |
||
| 1474 | // our childs need to be processed next and stop processing 'afterwards' |
||
| 1475 | $routeStack[] = $opts['childs']; |
||
| 1476 | break; |
||
| 1477 | } |
||
| 1478 | |||
| 1479 | if ($opts['stop']) { |
||
| 1480 | break; |
||
| 1481 | } |
||
| 1482 | } else { |
||
| 1483 | if (count($opts['callbacks']) > 0) { |
||
| 1484 | /** @var RoutingCallback $callbackInstance */ |
||
| 1485 | foreach ($route['callback_instances'] as $callbackInstance) { |
||
| 1486 | $onNotMatched = $callbackInstance->onNotMatched($container); |
||
| 1487 | if ($onNotMatched instanceof Response) { |
||
| 1488 | return $onNotMatched; |
||
| 1489 | } |
||
| 1490 | } |
||
| 1491 | } |
||
| 1492 | } |
||
| 1493 | } |
||
| 1494 | } |
||
| 1495 | } while (count($routeStack) > 0); |
||
| 1496 | |||
| 1497 | // put the vars into the request |
||
| 1498 | $rd->setParameters($vars); |
||
| 1499 | |||
| 1500 | if ($container->getModuleName() === null || $container->getControllerName() === null) { |
||
| 1501 | // no route which supplied the required parameters matched, use 404 controller |
||
| 1502 | $container->setModuleName(Config::get('controllers.error_404_module')); |
||
| 1503 | $container->setControllerName(Config::get('controllers.error_404_controller')); |
||
| 1504 | |||
| 1505 | if ($umap) { |
||
| 1506 | $rd->setParameters(array( |
||
| 1507 | $ma => $container->getModuleName(), |
||
| 1508 | $aa => $container->getControllerName(), |
||
| 1509 | )); |
||
| 1510 | } |
||
| 1511 | } |
||
| 1512 | |||
| 1513 | // set the list of matched route names as a request attribute |
||
| 1514 | $rq->setAttribute('matched_routes', $matchedRoutes, 'org.agavi.routing'); |
||
| 1515 | |||
| 1516 | // return a list of matched route names |
||
| 1517 | return $container; |
||
| 1518 | } |
||
| 1519 | |||
| 1520 | /** |
||
| 1521 | * Performs as match of the route against the input |
||
| 1522 | * |
||
| 1523 | * @param array $route The route info array. |
||
| 1524 | * @param string $input The input. |
||
| 1525 | * @param array $matches The array where the matches will be stored to. |
||
| 1526 | * |
||
| 1527 | * @return bool Whether the regexp matched. |
||
| 1528 | * |
||
| 1529 | * @author Dominik del Bondio <[email protected]> |
||
| 1530 | * @since 0.11.0 |
||
| 1531 | */ |
||
| 1532 | protected function parseInput(array $route, $input, &$matches) |
||
| 1533 | { |
||
| 1534 | if ($route['opt']['source'] !== null) { |
||
| 1535 | $parts = ArrayPathDefinition::getPartsFromPath($route['opt']['source']); |
||
| 1536 | $partArray = $parts['parts']; |
||
| 1537 | $count = count($partArray); |
||
| 1538 | if ($count > 0 && isset($this->sources[$partArray[0]])) { |
||
| 1539 | $input = $this->sources[$partArray[0]]; |
||
| 1540 | if ($count > 1) { |
||
| 1541 | array_shift($partArray); |
||
| 1542 | if (is_array($input)) { |
||
| 1543 | $input = ArrayPathDefinition::getValue($partArray, $input); |
||
| 1544 | } elseif ($input instanceof RoutingSourceInterface) { |
||
| 1545 | $input = $input->getSource($partArray); |
||
| 1546 | } |
||
| 1547 | } |
||
| 1548 | } |
||
| 1549 | } |
||
| 1550 | return preg_match($route['rxp'], $input, $matches, PREG_OFFSET_CAPTURE); |
||
| 1551 | } |
||
| 1552 | |||
| 1553 | /** |
||
| 1554 | * Parses a route pattern string. |
||
| 1555 | * |
||
| 1556 | * @param string $str The route pattern. |
||
| 1557 | * |
||
| 1558 | * @return array The info for this route pattern. |
||
| 1559 | * |
||
| 1560 | * @author Dominik del Bondio <[email protected]> |
||
| 1561 | * @since 0.11.0 |
||
| 1562 | */ |
||
| 1563 | protected function parseRouteString($str) |
||
| 1564 | { |
||
| 1565 | $vars = array(); |
||
| 1566 | $rxStr = ''; |
||
| 1567 | $reverseStr = ''; |
||
| 1568 | |||
| 1569 | $anchor = 0; |
||
| 1570 | $anchor |= (substr($str, 0, 1) == '^') ? self::ANCHOR_START : 0; |
||
| 1571 | $anchor |= (substr($str, -1) == '$') ? self::ANCHOR_END : 0; |
||
| 1572 | |||
| 1573 | $str = substr($str, (int)$anchor & self::ANCHOR_START, $anchor & self::ANCHOR_END ? -1 : strlen($str)); |
||
| 1574 | |||
| 1575 | $rxChars = implode('', array('.', '\\', '+', '*', '?', '[', '^', ']', '$', '(', ')', '{', '}', '=', '!', '<', '>', '|', ':')); |
||
| 1576 | |||
| 1577 | $len = strlen($str); |
||
| 1578 | $state = 'start'; |
||
| 1579 | $tmpStr = ''; |
||
| 1580 | $inEscape = false; |
||
| 1581 | |||
| 1582 | $rxName = null; |
||
| 1583 | $rxInner = null; |
||
| 1584 | $rxPrefix = null; |
||
| 1585 | $rxPostfix = null; |
||
| 1586 | $parenthesisCount = 0; |
||
| 1587 | $bracketCount = 0; |
||
| 1588 | $hasBrackets = false; |
||
| 1589 | |||
| 1590 | for ($i = 0; $i < $len; ++$i) { |
||
| 1591 | $atEnd = $i + 1 == $len; |
||
| 1592 | |||
| 1593 | $c = $str[$i]; |
||
| 1594 | |||
| 1595 | if (!$atEnd && !$inEscape && $c == '\\') { |
||
| 1596 | $cNext = $str[$i + 1]; |
||
| 1597 | |||
| 1598 | if (($cNext == '\\') || |
||
| 1599 | ($state == 'start' && $cNext == '(') || |
||
| 1600 | ($state == 'rxStart' && in_array($cNext, array('(',')','{','}'))) |
||
| 1601 | ) { |
||
| 1602 | $inEscape = true; |
||
| 1603 | continue; |
||
| 1604 | } |
||
| 1605 | if ($state == 'afterRx' && $cNext == '?') { |
||
| 1606 | $inEscape = false; |
||
| 1607 | $state = 'start'; |
||
| 1608 | continue; |
||
| 1609 | } |
||
| 1610 | } elseif ($inEscape) { |
||
| 1611 | $tmpStr .= $c; |
||
| 1612 | $inEscape = false; |
||
| 1613 | continue; |
||
| 1614 | } |
||
| 1615 | |||
| 1616 | if ($state == 'start') { |
||
| 1617 | // start of regular expression block |
||
| 1618 | if ($c == '(') { |
||
| 1619 | $rxStr .= preg_quote($tmpStr, '#'); |
||
| 1620 | $reverseStr .= $tmpStr; |
||
| 1621 | |||
| 1622 | $tmpStr = ''; |
||
| 1623 | $state = 'rxStart'; |
||
| 1624 | $rxName = $rxInner = $rxPrefix = $rxPostfix = null; |
||
| 1625 | $parenthesisCount = 1; |
||
| 1626 | $bracketCount = 0; |
||
| 1627 | $hasBrackets = false; |
||
| 1628 | } else { |
||
| 1629 | $tmpStr .= $c; |
||
| 1630 | } |
||
| 1631 | |||
| 1632 | if ($atEnd) { |
||
| 1633 | $rxStr .= preg_quote($tmpStr, '#'); |
||
| 1634 | $reverseStr .= $tmpStr; |
||
| 1635 | } |
||
| 1636 | } elseif ($state == 'rxStart') { |
||
| 1637 | if ($c == '{') { |
||
| 1638 | ++$bracketCount; |
||
| 1639 | if ($bracketCount == 1) { |
||
| 1640 | $hasBrackets = true; |
||
| 1641 | $rxPrefix = $tmpStr; |
||
| 1642 | $tmpStr = ''; |
||
| 1643 | } else { |
||
| 1644 | $tmpStr .= $c; |
||
| 1645 | } |
||
| 1646 | } elseif ($c == '}') { |
||
| 1647 | --$bracketCount; |
||
| 1648 | if ($bracketCount == 0) { |
||
| 1649 | list($rxName, $rxInner) = $this->parseParameterDefinition($tmpStr); |
||
| 1650 | $tmpStr = ''; |
||
| 1651 | } else { |
||
| 1652 | $tmpStr .= $c; |
||
| 1653 | } |
||
| 1654 | } elseif ($c == '(') { |
||
| 1655 | ++$parenthesisCount; |
||
| 1656 | $tmpStr .= $c; |
||
| 1657 | } elseif ($c == ')') { |
||
| 1658 | --$parenthesisCount; |
||
| 1659 | if ($parenthesisCount > 0) { |
||
| 1660 | $tmpStr .= $c; |
||
| 1661 | } else { |
||
| 1662 | if ($parenthesisCount < 0) { |
||
| 1663 | throw new AgaviException('The pattern ' . $str . ' contains an unbalanced set of parentheses!'); |
||
| 1664 | } |
||
| 1665 | |||
| 1666 | if (!$hasBrackets) { |
||
| 1667 | list($rxName, $rxInner) = $this->parseParameterDefinition($tmpStr); |
||
| 1668 | } else { |
||
| 1669 | if ($bracketCount != 0) { |
||
| 1670 | throw new AgaviException('The pattern ' . $str . ' contains an unbalanced set of brackets!'); |
||
| 1671 | } |
||
| 1672 | $rxPostfix = $tmpStr; |
||
| 1673 | } |
||
| 1674 | |||
| 1675 | if (!$rxName) { |
||
| 1676 | $myRx = $rxPrefix . $rxInner . $rxPostfix; |
||
| 1677 | // if the entire regular expression doesn't contain any regular expression character we can safely append it to the reverseStr |
||
| 1678 | //if(strlen($myRx) == strcspn($myRx, $rxChars)) { |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% 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. Loading history...
|
|||
| 1679 | if (strpbrk($myRx, $rxChars) === false) { |
||
| 1680 | $reverseStr .= $myRx; |
||
| 1681 | } |
||
| 1682 | $rxStr .= str_replace('#', '\#', sprintf('(%s)', $myRx)); |
||
| 1683 | } else { |
||
| 1684 | $rxStr .= str_replace('#', '\#', sprintf('(%s(?P<%s>%s)%s)', $rxPrefix, $rxName, $rxInner, $rxPostfix)); |
||
| 1685 | $reverseStr .= sprintf('(:%s:)', $rxName); |
||
| 1686 | |||
| 1687 | if (!isset($vars[$rxName])) { |
||
| 1688 | if (strpbrk($rxPrefix, $rxChars) !== false) { |
||
| 1689 | $rxPrefix = null; |
||
| 1690 | } |
||
| 1691 | if (strpbrk($rxInner, $rxChars) !== false) { |
||
| 1692 | $rxInner = null; |
||
| 1693 | } |
||
| 1694 | if (strpbrk($rxPostfix, $rxChars) !== false) { |
||
| 1695 | $rxPostfix = null; |
||
| 1696 | } |
||
| 1697 | |||
| 1698 | $vars[$rxName] = array('pre' => $rxPrefix, 'val' => $rxInner, 'post' => $rxPostfix, 'is_optional' => false); |
||
| 1699 | } |
||
| 1700 | } |
||
| 1701 | |||
| 1702 | $tmpStr = ''; |
||
| 1703 | $state = 'afterRx'; |
||
| 1704 | } |
||
| 1705 | } else { |
||
| 1706 | $tmpStr .= $c; |
||
| 1707 | } |
||
| 1708 | |||
| 1709 | if ($atEnd && $parenthesisCount != 0) { |
||
| 1710 | throw new AgaviException('The pattern ' . $str . ' contains an unbalanced set of parentheses!'); |
||
| 1711 | } |
||
| 1712 | } elseif ($state == 'afterRx') { |
||
| 1713 | if ($c == '?') { |
||
| 1714 | // only record the optional state when the pattern had a name |
||
| 1715 | if (isset($vars[$rxName])) { |
||
| 1716 | $vars[$rxName]['is_optional'] = true; |
||
| 1717 | } |
||
| 1718 | $rxStr .= $c; |
||
| 1719 | } else { |
||
| 1720 | // let the start state parse the char |
||
| 1721 | --$i; |
||
| 1722 | } |
||
| 1723 | |||
| 1724 | $state = 'start'; |
||
| 1725 | } |
||
| 1726 | } |
||
| 1727 | |||
| 1728 | $rxStr = sprintf('#%s%s%s#', $anchor & self::ANCHOR_START ? '^' : '', $rxStr, $anchor & self::ANCHOR_END ? '$' : ''); |
||
| 1729 | return array($rxStr, $reverseStr, $vars, $anchor); |
||
| 1730 | } |
||
| 1731 | |||
| 1732 | /** |
||
| 1733 | * Parses an embedded regular expression in the route pattern string. |
||
| 1734 | * |
||
| 1735 | * @param string $def The definition. |
||
| 1736 | * |
||
| 1737 | * @return array The name and the regexp. |
||
| 1738 | * |
||
| 1739 | * @author Dominik del Bondio <[email protected]> |
||
| 1740 | * @since 0.11.0 |
||
| 1741 | */ |
||
| 1742 | protected function parseParameterDefinition($def) |
||
| 1743 | { |
||
| 1744 | preg_match('#(?:([a-z0-9_-]+):)?(.*)#i', $def, $match); |
||
| 1745 | return array($match[1] !== '' ? $match[1] : null, $match[2]); |
||
| 1746 | } |
||
| 1747 | |||
| 1748 | /** |
||
| 1749 | * Creates and initializes a new RoutingValue. |
||
| 1750 | * |
||
| 1751 | * @param mixed $value The value of the returned routing value. |
||
| 1752 | * @param bool $valueNeedsEncoding Whether the $value needs to be encoded. |
||
| 1753 | * |
||
| 1754 | * @return RoutingValue |
||
| 1755 | * |
||
| 1756 | * @author Dominik del Bondio <[email protected]> |
||
| 1757 | * @since 1.0.0 |
||
| 1758 | */ |
||
| 1759 | public function createValue($value, $valueNeedsEncoding = true) |
||
| 1760 | { |
||
| 1761 | $value = new RoutingValue($value, $valueNeedsEncoding); |
||
| 1762 | $value->initialize($this->context); |
||
| 1763 | return $value; |
||
| 1764 | } |
||
| 1765 | } |
||
| 1766 |
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: