Changeset 7525
- Timestamp:
- 02/17/08 11:30:23 (9 months ago)
- Files:
-
- branches/1.1/lib/routing/sfNoRouting.class.php (modified) (2 diffs)
- branches/1.1/lib/routing/sfPathInfoRouting.class.php (modified) (1 diff)
- branches/1.1/lib/routing/sfPatternRouting.class.php (modified) (15 diffs)
- branches/1.1/lib/routing/sfRouting.class.php (modified) (1 diff)
- branches/1.1/test/unit/routing/sfPatternRoutingTest.php (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/1.1/lib/routing/sfNoRouting.class.php
r7518 r7525 24 24 public function getCurrentInternalUri($with_route_name = false) 25 25 { 26 $parameters = $this->fixDefaults( array_merge($this->defaultParameters, $_GET));26 $parameters = $this->fixDefaults($this->mergeArrays($this->defaultParameters, $_GET)); 27 27 $action = sprintf('%s/%s', $parameters['module'], $parameters['action']); 28 28 … … 40 40 public function generate($name, $params, $querydiv = '/', $divider = '/', $equals = '/') 41 41 { 42 $parameters = http_build_query( array_merge($this->defaultParameters, $params), null, '&');42 $parameters = http_build_query($this->mergeArrays($this->defaultParameters, $params), null, '&'); 43 43 44 44 return '/'.($parameters ? '?'.$parameters : ''); branches/1.1/lib/routing/sfPathInfoRouting.class.php
r7518 r7525 43 43 { 44 44 $url = ''; 45 foreach ( array_merge($this->defaultParameters, $params) as $key => $value)45 foreach ($this->mergeArrays($this->defaultParameters, $params) as $key => $value) 46 46 { 47 47 $url .= '/'.$key.'/'.$value; branches/1.1/lib/routing/sfPatternRouting.class.php
r7518 r7525 3 3 /* 4 4 * This file is part of the symfony package. 5 * (c) 2004-2006Fabien Potencier <fabien.potencier@symfony-project.com>5 * (c) Fabien Potencier <fabien.potencier@symfony-project.com> 6 6 * 7 7 * For the full copyright and license information, please view the LICENSE … … 13 13 * 14 14 * It maps an array of parameters to URLs definition. Each map is called a route. 15 *16 * This class was initialy based on the Routes class of the Cake framework.17 15 * 18 16 * @package symfony … … 31 29 32 30 /** 31 * Initializes this Routing. 32 * 33 * Available options: 34 * 35 * * suffix: The default suffix 36 * * variable_prefixes: An array of characters that starts a variable name (: by default) 37 * * segment_separators: An array of allowed characters for segment separators (/ and . by default) 38 * * variable_regex: A regex that match a valid variable name ([\w\d_]+ by default) 39 * 33 40 * @see sfRouting 34 41 */ 35 42 public function initialize(sfEventDispatcher $dispatcher, $options = array()) 36 43 { 44 if (!isset($options['variable_prefixes'])) 45 { 46 $options['variable_prefixes'] = array(':'); 47 } 48 49 if (!isset($options['segment_separators'])) 50 { 51 $options['segment_separators'] = array('/', '.'); 52 } 53 54 if (!isset($options['variable_regex'])) 55 { 56 $options['variable_regex'] = '[\w\d_]+'; 57 } 58 59 $options['variable_prefix_regex'] = '(?:'.implode('|', array_map(create_function('$a', 'return preg_quote($a, \'#\');'), $options['variable_prefixes'])).')'; 60 $options['segment_separators_regex'] = '(?:'.implode('|', array_map(create_function('$a', 'return preg_quote($a, \'#\');'), $options['segment_separators'])).')'; 61 $options['variable_content_regex'] = '[^'.implode('', array_map(create_function('$a', 'return str_replace(\'-\', \'\-\', preg_quote($a, \'#\'));'), $options['segment_separators'])).']+'; 62 37 63 parent::initialize($dispatcher, $options); 38 64 … … 69 95 $parameters = $this->currentRouteParameters; 70 96 71 list($url, $regex p, $names, $namesHash, $defaults, $requirements, $suffix) = $this->routes[$this->currentRouteName];97 list($url, $regex, $variables, $defaults, $requirements) = $this->routes[$this->currentRouteName]; 72 98 73 99 $internalUri = $withRouteName ? '@'.$this->currentRouteName : $parameters['module'].'/'.$parameters['action']; … … 76 102 77 103 // add parameters 78 foreach ( $names as $name)79 { 80 if ($ name == 'module' || $name == 'action')104 foreach (array_keys($variables) as $variable) 105 { 106 if ($variable == 'module' || $variable == 'action') 81 107 { 82 108 continue; 83 109 } 84 110 85 $params[] = $ name.'='.(isset($parameters[$name]) ? $parameters[$name] : (isset($defaults[$name]) ? $defaults[$name] : ''));111 $params[] = $variable.'='.(isset($parameters[$variable]) ? $parameters[$variable] : (isset($defaults[$variable]) ? $defaults[$variable] : '')); 86 112 } 87 113 88 114 // add * parameters if needed 89 if ( strpos($url, '*'))115 if (false !== strpos($regex, '_star')) 90 116 { 91 117 foreach ($parameters as $key => $value) 92 118 { 93 if ($key == 'module' || $key == 'action' || i n_array($key, $names))119 if ($key == 'module' || $key == 'action' || isset($variables[$key])) 94 120 { 95 121 continue; … … 205 231 * 206 232 * <code> 207 * $r->connect(' /:module/:action/*');233 * $r->connect('default', '/:module/:action/*'); 208 234 * </code> 209 235 * … … 215 241 * @return array current routes 216 242 */ 217 public function connect($name, $route, $default = array(), $requirements = array())243 public function connect($name, $route, $defaults = array(), $requirements = array()) 218 244 { 219 245 // route already exists? … … 223 249 } 224 250 225 $parsed = array();226 $names = array();227 251 $suffix = $this->defaultSuffix; 228 229 // a route must start by a slash. If there is none, add it automatically 230 if ('/' != $route[0]) 231 { 232 $route = '/'.$route; 233 } 234 235 if ($route == '/') 236 { 237 $this->routes[$name] = array($route, '/^[\/]*$/', array(), array(), $default, $requirements, $suffix); 252 $route = trim($route); 253 254 // fix defaults 255 foreach ($defaults as $key => $value) 256 { 257 if (ctype_digit($key)) 258 { 259 $defaults[$value] = true; 260 } 261 else 262 { 263 $defaults[$key] = urldecode($value); 264 } 265 } 266 $defaults = $this->fixDefaults($defaults); 267 268 // fix requirements regexs 269 foreach ($requirements as $key => $regex) 270 { 271 if ('^' == $regex[0]) 272 { 273 $regex = substr($regex, 1); 274 } 275 if ('$' == substr($regex, -1)) 276 { 277 $regex = substr($regex, 0, -1); 278 } 279 280 $requirements[$key] = $regex; 281 } 282 283 // a route can start by a slash. remove it for parsing. 284 if (!empty($route) && '/' == $route[0]) 285 { 286 $route = substr($route, 1); 287 } 288 289 if ($route == '') 290 { 291 $this->routes[$name] = array('/', '/^\/*$/', array(), $defaults, $requirements); 238 292 } 239 293 else 240 294 { 241 // used for performance reasons 242 $namesHash = array(); 243 $r = null; 244 $elements = array(); 245 foreach (explode('/', $route) as $element) 246 { 247 if (trim($element)) 248 { 249 $elements[] = $element; 250 } 251 } 252 253 if (!isset($elements[0])) 254 { 255 return false; 256 } 257 258 // specific suffix for this route? 259 // or /$ directory 260 if (preg_match('/^(.+)(\.\w*)$/i', $elements[count($elements) - 1], $matches)) 261 { 262 $suffix = '.' == $matches[2] ? '' : $matches[2]; 263 $elements[count($elements) - 1] = $matches[1]; 264 $route = '/'.implode('/', $elements); 265 } 266 else if ($route{strlen($route) - 1} == '/') 267 { 268 $suffix = '/'; 269 } 270 271 $regexp_suffix = preg_quote($suffix); 272 273 foreach ($elements as $element) 274 { 275 if (preg_match('/^:(.+)$/', $element, $r)) 276 { 277 $element = $r[1]; 278 279 // regex is [^\/]+ or the requirement regex 280 if (isset($requirements[$element])) 281 { 282 $regex = $requirements[$element]; 283 if (0 === strpos($regex, '^')) 284 { 285 $regex = substr($regex, 1); 286 } 287 if (strlen($regex) - 1 === strpos($regex, '$')) 288 { 289 $regex = substr($regex, 0, -1); 290 } 295 // ignore the default suffix if one is already provided in the route 296 if ('/' == $route[strlen($route) - 1]) 297 { 298 // route ends by / (directory) 299 $suffix = ''; 300 } 301 else if ('.' == $route[strlen($route) - 1]) 302 { 303 // route ends by . (no suffix) 304 $suffix = ''; 305 $route = substr($route, 0, strlen($route) -1); 306 } 307 else if (preg_match('#\.(?:'.$this->options['variable_prefix_regex'].$this->options['variable_regex'].'|'.$this->options['variable_content_regex'].')$#i', $route)) 308 { 309 // specific suffix for this route 310 // a . with a variable after or some cars without any separators 311 $suffix = ''; 312 } 313 314 // parse the route 315 $segments = array(); 316 $firstOptional = 0; 317 $buffer = $route; 318 $afterASeparator = true; 319 $currentSeparator = ''; 320 $variables = array(); 321 322 // a route is an array of (separator + variable) or (separator + text) segments 323 while (strlen($buffer)) 324 { 325 if ($afterASeparator && preg_match('#^'.$this->options['variable_prefix_regex'].'('.$this->options['variable_regex'].')#', $buffer, $match)) 326 { 327 // a variable (like :foo) 328 $variable = $match[1]; 329 330 if (!isset($requirements[$variable])) 331 { 332 $requirements[$variable] = $this->options['variable_content_regex']; 333 } 334 335 $segments[] = $currentSeparator.'(?P<'.$variable.'>'.$requirements[$variable].')'; 336 $currentSeparator = ''; 337 338 if (!isset($defaults[$variable])) 339 { 340 $defaults[$variable] = null; 341 } 342 343 $buffer = substr($buffer, strlen($match[0])); 344 $variables[$variable] = $match[0]; 345 $afterASeparator = false; 346 } 347 else if ($afterASeparator) 348 { 349 // a static text 350 if (!preg_match('#^(.+?)(?:'.$this->options['segment_separators_regex'].'|$)#', $buffer, $match)) 351 { 352 throw new InvalidArgumentException(sprintf('Unable to parse "%s" route near "%s".', $route, $buffer)); 353 } 354 355 if ('*' == $match[1]) 356 { 357 $segments[] = '(?:'.$currentSeparator.'(?P<_star>.*))?'; 291 358 } 292 359 else 293 360 { 294 $regex = '[^\/]+'; 295 } 296 297 $parsed[] = '(?:\/('.$regex.'))?'; 298 $names[] = $element; 299 $namesHash[$element] = 1; 300 } 301 elseif (preg_match('/^\*$/', $element, $r)) 302 { 303 $parsed[] = '(?:\/(.*))?'; 361 $segments[] = $currentSeparator.preg_quote($match[1], '#'); 362 $firstOptional = count($segments); 363 } 364 $currentSeparator = ''; 365 366 $buffer = substr($buffer, strlen($match[1])); 367 $afterASeparator = false; 368 } 369 else if (preg_match('#^'.$this->options['segment_separators_regex'].'#', $buffer, $match)) 370 { 371 // a separator (like / or .) 372 $currentSeparator = preg_quote($match[0], '#'); 373 374 $buffer = substr($buffer, strlen($match[0])); 375 $afterASeparator = true; 304 376 } 305 377 else 306 378 { 307 $parsed[] = '/'.$element; 308 } 309 } 310 $regexp = '#^'.join('', $parsed).$regexp_suffix.'$#'; 311 312 $this->routes[$name] = array($route, $regexp, $names, $namesHash, $default, $requirements, $suffix); 379 // parsing problem 380 throw new InvalidArgumentException(sprintf('Unable to parse "%s" route near "%s".', $route, $buffer)); 381 } 382 } 383 384 // all segments after the last static segment are optional 385 // be careful, the n-1 is optional only if n is empty 386 for ($i = $firstOptional, $max = count($segments); $i < $max; $i++) 387 { 388 $segments[$i] = str_repeat(' ', $i - $firstOptional).'(?:'.$segments[$i]; 389 $segments[] = str_repeat(' ', $max - $i - 1).')?'; 390 } 391 392 $regex = "#^/\n".implode("\n", $segments)."\n".$currentSeparator.preg_quote($suffix, '#')."$#x"; 393 $this->routes[$name] = array('/'.$route.$suffix, $regex, $variables, $defaults, $requirements); 313 394 } 314 395 … … 336 417 } 337 418 338 list($url, $regexp, $names, $namesHash, $defaults, $requirements, $suffix) = $this->routes[$name]; 339 $defaults = array_merge($defaults, $this->defaultParameters); 419 list($url, $regex, $variables, $defaults, $requirements) = $this->routes[$name]; 420 $defaults = $this->mergeArrays($defaults, $this->defaultParameters); 421 $tparams = $this->mergeArrays($defaults, $params); 340 422 341 423 // all params must be given 342 foreach ($names as $tmp) 343 { 344 if (!isset($params[$tmp]) && !isset($defaults[$tmp])) 345 { 346 throw new sfException(sprintf('Route named "%s" have a mandatory "%s" parameter.', $name, $tmp)); 347 } 424 if ($diff = array_diff_key($variables, array_filter($tparams))) 425 { 426 throw new InvalidArgumentException(sprintf('The "%s" route has some missing mandatory parameters (%s).', $name, implode(', ', $diff))); 348 427 } 349 428 } … … 354 433 foreach ($this->routes as $name => $route) 355 434 { 356 list($url, $regexp, $names, $namesHash, $defaults, $requirements, $suffix) = $route; 357 $defaults = array_merge($defaults, $this->defaultParameters); 358 359 $tparams = array_merge($defaults, $params); 360 361 // we must match all names (all $names keys must be in $params array) 362 foreach ($names as $key) 363 { 364 if (!isset($tparams[$key])) continue 2; 365 } 366 367 // we must match all defaults with value except if present in names 368 foreach ($defaults as $key => $value) 369 { 370 if (isset($namesHash[$key])) continue; 371 372 if (!isset($tparams[$key]) || $tparams[$key] != $value) continue 2; 373 } 374 375 // we must match all requirements for rule 376 foreach ($requirements as $req_param => $req_regexp) 377 { 378 if (!preg_match('/'.str_replace('/', '\\/', $req_regexp).'/', $tparams[$req_param])) 435 list($url, $regex, $variables, $defaults, $requirements) = $route; 436 $defaults = $this->mergeArrays($defaults, $this->defaultParameters); 437 $tparams = $this->mergeArrays($defaults, $params); 438 439 // all $variables must be defined in the $tparams array 440 if (array_diff_key($variables, array_filter($tparams))) 441 { 442 continue; 443 } 444 445 // check requirements 446 foreach ($requirements as $reqParam => $reqRegexp) 447 { 448 if (!is_null($tparams[$reqParam]) && !preg_match('#'.$reqRegexp.'#', $tparams[$reqParam])) 379 449 { 380 450 continue 2; … … 382 452 } 383 453 384 // we must have consumed all $params keys if there is no * in route 385 if (!strpos($url, '*')) 386 { 387 if (count(array_diff(array_keys($tparams), $names, array_keys($defaults)))) 388 { 389 continue; 390 } 391 } 392 393 // match found 454 // all $params must be in $variables or $defaults if there is no * in route 455 if (false === strpos($regex, '_star') && array_diff_key(array_filter($params), $variables, $defaults)) 456 { 457 continue; 458 } 459 460 // check that $params does not override a default value that is not a variable 461 foreach (array_filter($defaults) as $key => $value) 462 { 463 if (!isset($variables[$key]) && $tparams[$key] != $value) 464 { 465 continue 2; 466 } 467 } 468 469 // found 394 470 $found = true; 395 471 break; … … 402 478 } 403 479 404 $params = sfToolkit::arrayDeepMerge($defaults, $params); 405 406 $realUrl = preg_replace('/\:([^\/]+)/e', 'urlencode($params["\\1"])', $url); 407 408 // we add all other params if * 409 if (strpos($realUrl, '*')) 480 // replace variables 481 $realUrl = $url; 482 foreach ($variables as $variable => $value) 483 { 484 $realUrl = str_replace($value, urlencode($tparams[$variable]), $realUrl); 485 } 486 487 // add extra params if the route contains * 488 if (false !== strpos($regex, '_star')) 410 489 { 411 490 $tmp = array(); 412 foreach ($params as $key => $value) 413 { 414 if (isset($namesHash[$key]) || isset($defaults[$key])) continue; 415 491 foreach (array_diff_key($tparams, $variables, $defaults) as $key => $value) 492 { 416 493 if (is_array($value)) 417 494 { … … 427 504 } 428 505 $tmp = implode($divider, $tmp); 429 if ( strlen($tmp) > 0)506 if ($tmp) 430 507 { 431 508 $tmp = $querydiv.$tmp; 432 509 } 433 $realUrl = preg_replace('/\/\*(\/|$)/', "$tmp$1", $realUrl); 434 435 // strip off last divider character 436 if (strlen($realUrl) > 1) 437 { 438 $realUrl = rtrim($realUrl, $divider); 439 } 440 } 441 442 if ('/' != $realUrl && '/' != substr($realUrl, -1)) 443 { 444 $realUrl .= $suffix; 510 511 $realUrl = preg_replace('#'.$this->options['segment_separators_regex'].'\*('.$this->options['segment_separators_regex'].'|$)#', "$tmp$1", $realUrl); 445 512 } 446 513 … … 454 521 { 455 522 // an URL should start with a '/', mod_rewrite doesn't respect that, but no-mod_rewrite version does. 456 if ( $url && ('/' != $url[0]))523 if ('/' != $url[0]) 457 524 { 458 525 $url = '/'.$url; … … 460 527 461 528 // we remove the query string 462 if ( $pos = strpos($url, '?'))529 if (false !== $pos = strpos($url, '?')) 463 530 { 464 531 $url = substr($url, 0, $pos); 465 532 } 466 533 467 // weremove multiple /534 // remove multiple / 468 535 $url = preg_replace('#/+#', '/', $url); 469 $out = array(); 470 $ break= false;536 537 $found = false; 471 538 foreach ($this->routes as $routeName => $route) 472 539 { 473 $out = array(); 474 $r = null; 475 476 list($route, $regexp, $names, $namesHash, $defaults, $requirements, $suffix) = $route; 540 list($route, $regex, $variables, $defaults, $requirements) = $route; 541 if (!preg_match($regex, $url, $r)) 542 { 543 continue; 544 } 545 477 546 $defaults = array_merge($defaults, $this->defaultParameters); 478 479 $break = false; 480 481 if (preg_match($regexp, $url, $r)) 482 { 483 $break = true; 484 485 // remove the first element, which is the url 486 array_shift($r); 487 488 // hack, pre-fill the default route names 489 foreach ($names as $name) 490 { 491 $out[$name] = null; 492 } 493 494 // defaults 495 foreach ($defaults as $name => $value) 496 { 497 if (preg_match('#[a-z_\-]#i', $name)) 498 { 499 $out[$name] = urldecode($value); 500 } 501 else 502 { 503 $out[$value] = true; 504 } 505 } 506 507 $pos = 0; 508 foreach ($r as $found) 509 { 510 // if $found is a named url element (i.e. ':action') 511 if (isset($names[$pos])) 512 { 513 $out[$names[$pos]] = urldecode($found); 514 } 515 // unnamed elements go in as 'pass' 516 else 517 { 518 $pass = explode('/', $found); 519 $found = ''; 520 for ($i = 0, $max = count($pass); $i < $max; $i += 2) 521 { 522 if (!isset($pass[$i + 1])) 523 { 524 continue; 525 } 526 527 $found .= $pass[$i].'='.$pass[$i + 1].'&'; 528 } 529 parse_str($found, $pass); 530 531 if (get_magic_quotes_gpc()) 532 { 533 $pass = sfToolkit::stripslashesDeep((array) $pass); 534 } 535 536 foreach ($pass as $key => $value) 537 { 538 // we add this parameters if not in conflict with named url element (i.e. ':action') 539 if (!isset($namesHash[$key])) 540 { 541 $out[$key] = $value; 542 } 543 } 544 } 545 $pos++; 546 } 547 548 // we must have found all :var stuffs in url? except if default values exists 549 foreach ($names as $name) 550 { 551 if (is_null($out[$name])) 552 { 553 $break = false; 554 } 555 } 556 557 if ($break) 558 { 559 // we store route name 560 $this->currentRouteName = $routeName; 561 $this->currentInternalUri = array(); 562 563 if ($this->options['logging']) 564 { 565 $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Match route [%s] "%s"', $routeName, $route)))); 566 } 567 568 break; 569 } 570 } 547 $found = true; 548 $out = array(); 549 550 // * 551 if (isset($r['_star'])) 552 { 553 $out = $this->parseStarParameter($r['_star']); 554 unset($r['_star']); 555 } 556 557 // defaults 558 $out = $this->mergeArrays($out, $defaults); 559 560 // variables 561 foreach ($r as $key => $value) 562 { 563 if (!is_int($key)) 564 { 565 $out[$key] = $value; 566 } 567 } 568 569 // store the route name 570 $this->currentRouteName = $routeName; 571 $this->currentInternalUri = array(); 572 573 if ($this->options['logging']) 574 { 575 $this->dispatcher->notify(new sfEvent($this, 'application.log', array(sprintf('Match route [%s] for "%s"', $routeName, $route)))); 576 } 577 578 break; 571 579 } 572 580 573 581 // no route found 574 if (!$break) 575 { 576 if ($this->options['logging']) 577 { 578 $this->dispatcher->notify(new sfEvent($this, 'application.log', array('No matching route found'))); 579 } 580 581 $this->currentRouteParameters = null; 582 582 if (!$found) 583 { 583 584 throw new sfError404Exception(sprintf('No matching route found for "%s"', $url)); 584 585 } 585 586 586 $this->currentRouteParameters = $this->fixDefaults($out); 587 588 return $this->currentRouteParameters; 587 return $this->currentRouteParameters = $this->fixDefaults($out); 588 } 589 590 protected function parseStarParameter($star) 591 { 592 $parameters = array(); 593 $tmp = explode('/', $star); 594 for ($i = 0, $max = count($tmp); $i < $max; $i += 2) 595 { 596 $parameters[$tmp[$i]] = isset($tmp[$i + 1]) ? urldecode($tmp[$i + 1]) : true; 597 } 598 599 return $parameters; 589 600 } 590 601 } branches/1.1/lib/routing/sfRouting.class.php
r7518 r7525 180 180 } 181 181 182 protected function mergeArrays($arr1, $arr2) 183 { 184 foreach ($arr2 as $key => $value) 185 { 186 $arr1[$key] = $value; 187 } 188 189 return $arr1; 190 } 191 182 192 /** 183 193 * Listens to the user.change_culture event. branches/1.1/test/unit/routing/sfPatternRoutingTest.php
r7519 r7525 11 11 require_once(dirname(__FILE__).'/../../bootstrap/unit.php'); 12 12 13 $t = new lime_test( 74, new lime_output_color());13 $t = new lime_test(122, new lime_output_color()); 14 14 15 15 class sfPatternRoutingTest extends sfPatternRouting … … 22 22 23 23 // public methods 24 $r = new sfPatternRoutingTest(new sfEventDispatcher() , array('default_module' => 'default', 'default_action' => 'index'));25 foreach (array(' clearRoutes', 'connect', 'generate', 'getCurrentInternalUri', 'getCurrentRouteName', 'getRoutes', 'hasRoutes', 'parse', 'setRoutes') as $method)24 $r = new sfPatternRoutingTest(new sfEventDispatcher()); 25 foreach (array('initialize', 'getCurrentInternalUri', 'getRoutes', 'setRoutes', 'hasRoutes', 'clearRoutes', 'hasRouteName', 'prependRoute', 'appendRoute', 'connect', 'generate', 'parse') as $method) 26 26 { 27 27 $t->can_ok($r, $method, sprintf('"%s" is a method of sfRouting', $method)); … … 63 63 $t->is($r->hasRoutes(), true, '->hasRoutes() returns true if some routes are registered'); 64 64 65 // ->connect(), ->parse(), ->generate() 66 $t->diag('->connect(), ->parse(), ->generate()'); 65 // ->connect() 66 $t->diag('->connect()'); 67 $r->clearRoutes(); 68 $msg = '->connect() throws an sfConfigurationException when a route already exists with same name'; 69 $r->connect('test', '/index.php/:module/:action', array('module' => 'default', 'action' => 'index')); 70 try 71 { 72 $r->connect('test', '/index.php/:module/:action', array('module' => 'default', 'action' => 'index')); 73 74 $t->fail($msg); 75 } 76 catch (sfConfigurationException $e) 77 { 78 $t->pass($msg); 79 } 80 $r->clearRoutes(); 81 $routes = $r->connect('test', ':module/:action', array('module' => 'default', 'action' => 'index')); 82 $t->is($routes['test'][0], '/:module/:action', '->connect() automatically adds trailing / to route if missing'); 83 $routes = $r->connect('test1', '', array('module' => 'default', 'action' => 'index')); 84 $t->is($routes['test1'][1], '/^\/*$/', '->connect() detects empty routes'); 85 $routes = $r->connect('test2', '/', array('module' => 'default', 'action' => 'index')); 86 $t->is($routes['test1'][1], '/^\/*$/', '->connect() detects empty routes'); 87 88 // route syntax 89 $t->diag('route syntax'); 67 90 68 91 // simple routes … … 78 101 $t->is($r->generate('', $params), $url, 'generate /:module/:action url'); 79 102 103 // order 104 $t->diag('route order'); 105 $r->clearRoutes(); 106 $r->connect('test', '/test/:id', array('module' => 'default1', 'action' => 'index1'), array('id' => '\d+')); 107 $r->connect('test1', '/test/:id', array('module' => 'default2', 'action' => 'index2')); 108 $params = array('module' => 'default1', 'action' => 'index1', 'id' => '12'); 109 $url = '/test/12'; 110 $t->is($r->parse($url), $params, '->parse() takes the first matching route'); 111 $t->is($r->generate('', $params), $url, '->generate() takes the first matching route'); 112 113 $params = array('module' => 'default2', 'action' => 'index2', 'id' => 'foo'); 114 $url = '/test/foo'; 115 $t->is($r->parse($url), $params, '->parse() takes the first matching route'); 116 $t->is($r->generate('', $params), $url, '->generate() takes the first matching route'); 117 118 $r->clearRoutes(); 119 $r->connect('test', '/:module/:action/test/:id/:test', array('module' => 'default', 'action' => 'index')); 120 $r->connect('test1', '/:module/:action/test/:id', array('module' => 'default', 'action' => 'index', 'id' => 'foo')); 121 $params = array('module' => 'default', 'action' => 'index', 'id' => 'foo', 'test' => null); 122 $url = '/default/index/test/foo'; 123 $t->is($r->parse($url), $params, '->parse() takes the first matching route'); 124 $t->is($r->generate('', $params), $url, '->generate() takes the first matching route'); 125 80 126 // suffix 127 $t->diag('suffix'); 81 128 $r->clearRoutes(); 82 129 $r->setDefaultSuffix('.html'); 83 $r->connect('foo ', '/foo/:module/:action/:param.foo', array('module' => 'default', 'action' => 'index'));84 $url = '/foo/default/index/foo.foo';130 $r->connect('foo0', '/foo0/:module/:action/:param0', array('module' => 'default', 'action' => 'index0')); 131 $url0 = '/foo0/default/index0/foo0.html'; 85 132 $r->connect('foo1', '/foo1/:module/:action/:param1.', array('module' => 'default', 'action' => 'index1')); 86 133 $url1 = '/foo1/default/index1/foo1'; 87 134 $r->connect('foo2', '/foo2/:module/:action/:param2/', array('module' => 'default', 'action' => 'index2')); 88 135 $url2 = '/foo2/default/index2/foo2/'; 89 $r->connect('foo3', '/foo3/:module/:action/:param3', array('module' => 'default', 'action' => 'index3')); 90 $url3 = '/foo3/default/index3/foo3.html'; 91 92 $t->is($r->generate('', array('module' => 'default', 'action' => 'index', 'param' => 'foo'), '/', '/', '='), $url, '->generate() routes can override the default suffix'); 93 $t->is($r->generate('', array('module' => 'default', 'action' => 'index1', 'param1' => 'foo1')), $url1, '->generate() routes can remove the default suffix'); 94 $t->is($r->generate('', array('module' => 'default', 'action' => 'index2', 'param2' => 'foo2')), $url2, '->generate() routes does not have suffix when they end by /'); 95 $t->is($r->generate('', array('module' => 'default', 'action' => 'index3', 'param3' => 'foo3')), $url3, '->generate() routes takes a suffix defined by the "suffix" parameter'); 96 97 $t->is($r->parse($url), array('module' => 'default', 'action' => 'index', 'param' => 'foo'), '->parse() routes can override the default suffix'); 98 $t->is($r->parse($url1), array('module' => 'default', 'action' => 'index1', 'param1' => 'foo1'), '->parse() routes can remove the default suffix'); 99 $t->is($r->parse($url2), array('module' => 'default', 'action' => 'index2', 'param2' => 'foo2'), '->parse() routes does not have suffix when they end by /'); 100 $t->is($r->parse($url3), array('module' => 'default', 'action' => 'index3', 'param3' => 'foo3'), '->parse() routes takes a suffix defined by the "suffix" parameter'); 136 $r->connect('foo3', '/foo3/:module/:action/:param3.foo', array('module' => 'default', 'action' => 'index3')); 137 $url3 = '/foo3/default/index3/foo3.foo'; 138 $r->connect('foo4', '/foo4/:module/:action/:param4.:param_5', array('module' => 'default', 'action' => 'index4')); 139 $url4 = '/foo4/default/index4/foo.bar'; 140 141 $t->is($r->generate('', array('module' => 'default', 'action' => 'index0', 'param0' => 'foo0')), $url0, '->generate() creates URL suffixed by "sf_suffix" parameter'); 142 $t->is($r->generate('', array('module' => 'default', 'action' => 'index1', 'param1' => 'foo1')), $url1, '->generate() creates URL with no suffix when route ends with .'); 143 $t->is($r->generate('', array('module' => 'default', 'action' => 'index2', 'param2' => 'foo2')), $url2, '->generate() creates URL with no suffix when route ends with /'); 144 $t->is($r->generate('', array('module' => 'default', 'action' => 'index3', 'param3' => 'foo3'), '/', '/', '='), $url3, '->generate() creates URL with special suffix when route ends with .suffix'); 145 $t->is($r->generate('', array('module' => 'default', 'action' => 'index4', 'param4' => 'foo', 'param_5' => 'bar')), $url4, '->generate() creates URL with no special suffix when route ends with .:suffix'); 146 147 148 $t->is($r->parse($url0), array('module' => 'default', 'action' => 'index0', 'param0' => 'foo0'), '->parse() finds route from URL suffixed by "sf_suffix"'); 149 $t->is($r->parse($url1), array('module' => 'default', 'action' => 'index1', 'param1' => 'foo1'), '->parse() finds route with no suffix when route ends with .'); 150 $t->is($r->parse($url2), array('module' => 'default', 'action' => 'index2', 'param2' => 'foo2'), '->parse() finds route with no suffix when route ends with /'); 151 $t->is($r->parse($url3), array('module' => 'default', 'action' => 'index3', 'param3' => 'foo3'), '->parse() finds route with special suffix when route ends with .suffix'); 152 $t->is($r->parse($url4), array('module' => 'default', 'action' => 'index4', 'param4' => 'foo', 'param_5' => 'bar'), '->parse() finds route with special suffix when route ends with .:suffix'); 153 101 154 $r->setDefaultSuffix('.'); 102 155 103 // duplicate names104 $msg = '->connect() throws an sfConfigurationException when a route already exists with same name';105 $r->clearRoutes();106 $r->connect('test', '/index.php/:module/:action', array('module' => 'default', 'action' => 'index'));107 try108 {109 $r->connect('test', '/index.php/:module/:action', array('module' => 'default', 'action' => 'index'));110 111 $t->fail($msg);112 }113 catch (sfConfigurationException $e)114 {115 $t->pass($msg);116 }117 118 156 // query string 157 $t->diag('query string'); 119 158 $r->clearRoutes(); 120 159 $r->connect('test', '/index.php/:module/:action', array('module' => 'default', 'action' => 'index')); … … 124 163 125 164 // default values 165 $t->diag('default values'); 126 166 $r->clearRoutes(); 127 167 $r->connect('test', '/:module/:action', array('module' => 'default', 'action' => 'index')); 168 $t->is($r->generate('', array('module' => 'default')), '/default/index', 169 '->generate() creates URL for route with missing parameter if parameter is set in the default values'); 170 $t->is($r->parse('/default'), array('module' => 'default', 'action' => 'index'), 171 '->parse() finds route for URL with missing parameter if parameter is set in the default values'); 172 173 $r->clearRoutes(); 174 $r->connect('test', '/:module/:action/:foo', array('module' => 'default', 'action' => 'index', 'foo' => 'bar')); 175 $t->is($r->generate('', array('module' => 'default')), '/default/index/bar', 176 '->generate() creates URL for route with more than one missing parameter if default values are set'); 177 $t->is($r->parse('/default'), array('module' => 'default', 'action' => 'index', 'foo' => 'bar'), 178 '->parse() finds route for URL with more than one missing parameter if default values are set'); 179 180 $r->clearRoutes(); 181 $r->connect('test', '/:module/:action', array('module' => 'default', 'action' => 'index')); 182 $params = array('module' => 'foo', 'action' => 'bar'); 183 $url = '/foo/bar'; 184 $t->is($r->generate('', $params), $url, '->generate() parameters override the route default values'); 185 $t->is($r->parse($url), $params, '->parse() finds route with parameters distinct from the default values'); 186 187 $r->clearRoutes(); 188 $r->connect('test', '/:module/:action', array('module' => 'default')); 128 189 $params = array('module' => 'default', 'action' => 'index'); 129 190 $url = '/default/index'; 130 $t->is($r->parse($url), $params, '->parse() routes can have default values for its parameters'); 131 $t->is($r->generate('', $params), $url, '->generate() routes can have default values for its parameters'); 132 133 // params 134 $r->clearRoutes(); 135 $r->connect('test', '/:module/:action/test/:id', array('module' => 'default', 'action' => 'index')); 136 $params = array('module' => 'default', 'action' => 'index', 'id' => 4); 137 $url = '/default/index/test/4'; 138 $t->is($r->parse($url), $params, '->parse() routes can have parameters with no default'); 139 $t->is($r->generate('', $params), $url, '->generate() routes can have parameters with no default'); 140 141 // order 142 $r->clearRoutes(); 143 $r->connect('test', '/:module/:action/test/:id/:test', array('module' => 'default', 'action' => 'index')); 144 $r->connect('test1', '/:module/:action/test/:id', array('module' => 'default', 'action' => 'index', 'id' => 'foo')); 145 $params = array('module' => 'default', 'action' => 'index', 'id' => 'foo'); 146 $url = '/default/index/test/foo'; 147 $t->is($r->parse($url), $params, '->parse() takes the first matching route'); 148 $t->is($r->generate('', $params), $url, '->generate() takes the first matching route'); 149 150 // multiple params 191 $t->is($r->generate('', $params), $url, '->generate() creates URL even if there is no default value'); 192 $t->is($r->parse($url), $params, '->parse() finds route even when route has no default value'); 193 194 // combined examples 151 195 $r->clearRoutes(); 152 196 $r->connect('test', '/:module/:action/:test/:id', array('module' => 'default', 'action' => 'index', 'id' => 'toto')); 153 197 $params = array('module' => 'default', 'action' => 'index', 'test' => 'foo', 'id' => 'bar'); 154 198 $url = '/default/index/foo/bar'; 155 $t->is($r->parse($url), $params, '->parse() routes have default parameters value that can be overriden');156 199 $t->is($r->generate('', $params), $url, '->generate() routes have default parameters value that can be overriden'); 200 $t->is($r->parse($url), $params, '->parse() routes have default parameters value that can be overriden'); 157 201 $params = array('module' => 'default', 'action' => 'index', 'test' => 'foo', 'id' => 'toto'); 158 202 $url = '/default/index/foo'; 159 $t->is($r->parse($url), $params, '->parse() removes the last parameter if the parameter is default value'); 160 //$t->is($r->generate('', $params), $url, '->generate() removes the last parameter if the parameter is default value'); 161 162 // numerics params 163 $r->clearRoutes(); 164 $r->connect('test', '/:module/:action/*', array('module' => 'default', 'action' => 'index')); 165 $params = array('module' => 'default', 'action' => 'index', 15 => 'foo', 32 => 'bar', 'foo' => 'bar'); 166 $url = '/default/index/15/foo/32/bar/foo/bar'; 167 $t->is($r->parse($url), $params, '->parse() routes can have numeric parameters'); 168 $t->is($r->generate('', $params), $url, '->generate() routes can have numeric parameters'); 169 203 $t->isnt($r->generate('', $params), $url, '->generate() does not remove the last parameter if the parameter is default value'); 204 $t->is($r->parse($url), $params, '->parse() removes the last parameter if the parameter is default value'); 170 205 171 206 $r->clearRoutes(); … … 173 208 $params = array('module' => 'default', 'action' => 'index', 'test' => 'foo', 'id' => 'bar'); 174 209 $url = '/default/index'; 175 $t->is($r->parse($url), $params, '->parse() removes last parameters if they have default values'); 176 //$t->is($r->generate('', $params), $url, '->generate() removes last parameters if they have default values'); 177 178 // star parameter 210 $t->isnt($r->generate('', $params), $url, '->generate() does not remove last parameters if they have default values'); 211 $t->is($r->parse($url), $params, '->parse() removes last parameters if they have default values'); 212 213 // routing defaults parameters 214 $r->setDefaultParameter('foo', 'bar'); 215 $r->clearRoutes(); 216 $r->connect('test', '/test/:foo/:id', array('module' => 'default', 'action' => 'index')); 217 $params = array('module' => 'default', 'action' => 'index', 'id' => 12); 218 $url = '/test/bar/12'; 219 $t->is($r->generate('', $params), $url, '->generate() merges parameters with defaults from "sf_routing_defaults"'); 220 $r->setDefaultParameters(array()); 221 222 // unnamed wildcard * 223 $t->diag('unnamed wildcard *'); 179 224 $r->clearRoutes(); 180 225 $r->connect('test', '/:module/:action/test/*', array('module' => 'default', 'action' => 'index')); 226 $params = array('module' => 'default', 'action' => 'index'); 227 $url = '/default/index/test'; 228 $t->is($r->parse($url), $params, '->parse() finds route for URL with no additional parameters when route ends with unnamed wildcard *'); 229 $t->is($r->generate('', $params), $url, '->generate() creates URL for route with no additional parameters when route ends with unnamed wildcard *'); 181 230 $params = array('module' => 'default', 'action' => 'index', 'page' => '4.html', 'toto' => true, 'titi' => 'toto', 'OK' => true); 182 231 $url = '/default/index/test/page/4.html/toto/1/titi/toto/OK/1'; 183 $t->is($r->parse($url), $params, '->parse() routes can take a * as its last parameter'); 184 $t->is($r->parse('/default/index/test/page/4.html/toto/1/titi/toto/OK/1/module/test/action/tutu'), $params, '->parse() routes can take a * as its last parameter'); 185 $t->is($r->parse('/default/index/test/page/4.html////toto//1/titi//toto//OK/1'), $params, '->parse() routes can take a * as its last parameter'); 186 $t->is($r->generate('', $params), $url, '->generate() routes can take a * as its last parameter'); 187 232 $t->is($r->parse($url), $params, '->parse() finds route for URL with additional parameters when route ends with unnamed wildcard *'); 233 $t->is($r->generate('', $params), $url, '->generate() creates URL for route with additional parameters when route ends with unnamed wildcard *'); 234 $t->is($r->parse('/default/index/test/page/4.html/toto/1/titi/toto/OK/1/module/test/action/tutu'), $params, '->parse() does not override named wildcards with parameters passed in unnamed wildcard *'); 235 $t->is($r->parse('/default/index/test/page/4.html////toto//1/titi//toto//OK/1'), $params, '->parse() considers multiple separators as single in unnamed wildcard *'); 236 237 // unnamed wildcard * after a token 188 238 $r->clearRoutes(); 189 239 $r->connect('test', '/:module', array('action' => 'index')); … … 191 241 $params = array('module' => 'default', 'action' => 'index', 'toto' => 'titi'); 192 242 $url = '/default/index/toto/titi'; 193 $t->is($r->parse($url), $params, '->parse() takes the first matching route but takes * into accounts');243 $t->is($r->parse($url), $params, '->parse() takes the first matching route but takes * into accounts'); 194 244 $t->is($r->generate('', $params), $url, '->generate() takes the first matching route but takes * into accounts'); 195 245 $params = array('module' => 'default', 'action' => 'index'); 196 246 $url = '/default'; 197 $t->is($r->parse($url), $params, '->parse() takes the first matching route but takes * into accounts');247 $t->is($r->parse($url), $params, '->parse()