Commits
-------
418d6a0 [Routing] Fix syntax error when dumping routes with single quotes in the requirements or pattern
2b5e22d [Routing] Fix ApacheDumper when a space appears in a default value
6c7f484 [Routing] Fix dumper so it doesn't print trailing whitespace
761724a [Routing] Adjust urlescaping rules, fixes#752
Discussion
----------
[Router] Bunch o' Fixes
The first commit changes the escaping rule to fix issues I had previously, and #752 as well, here's from the full commit message:
Only + and % are now encoded in generated routes, since they are the only characters that, if not encoded, could cause problems/conflicts when decoded. Namely + turns into a space, and % followed by numbers could do funky things.
The matcher decodes everything which works since nothing will have %NN without being escaped, and + are escaped as well.
Second commit is just a test fix for the first
Third and fourth are simply dumper escaping issues, nothing to argue about.
Note that all changes have had test cases added, and I spent a few hours torturing/testing all this stuff with both Apache and PHP dumpers, in many browsers, and with URLs as wonky as `/%01%02%03%04%05%06%07%08%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22$%25&%27%28%29*+,-./0123456789:;%3C=%3E@ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B|%7D~/baz` which essentially represent the 1-255 char range minus ? and #.
The only issues I really encountered after all the patches were applied is that Apache refuses to match `%22` (= `"`) and `*` in a url. I guess it's just because they're not allowed chars in windows paths, but | and < > works fine though. Anyway this works with the PHP dumper, and it didn't work either without my patches so it's not like I broke it, I'm just saying for the record.
Only + and % are now encoded in generated routes, since they are the only characters that, if not encoded, could cause problems/conflicts when decoded. Namely + turns into a space, and % followed by numbers could do funky things.
The matcher decodes everything which works since nothing will have %NN without being escaped, and + are escaped as well.
Commits
-------
49dd558 Couple more CS fixes
5a986bf Add $keysCount & minor CS fix
91f4097 [Routing] Better nesting for RouteCollections in dumped URL matcher classes With this change, a route prefixed with '/blogger' will be nested inside '/blog' (for example)
Discussion
----------
[Routing] Better nesting for RouteCollections in dumped URL matcher classes
Consider the following routing file:
_blog:
resource: "@AcmeDemoBundle/Resources/config/routing/BlogController.yml"
prefix: /blog
_blogger:
resource: "@AcmeDemoBundle/Resources/config/routing/BloggerController.yml"
prefix: /blogger
_bloggeroo:
resource: "@AcmeDemoBundle/Resources/config/routing/BloggerooController.yml"
prefix: /bloggeroo
_blogtest:
pattern: /blogtest
defaults: { _controller: AcmeDemoBundle:Blog:test }
login:
pattern: /login
defaults: { _controller: AcmeDemoBundle:Security:login }
Note: Each imported file contains two simple blog/blogger/bloggeroo routes (e.g. blog_index & blog_view)
With this change, the cached URL matcher looks something like this:
```php
<?php
class appprodUrlMatcher
{
public function match($pathinfo)
{
$allow = array();
if (0 === strpos($pathinfo, '/blog')) {
// blog_index
if (preg_match('#^/blog/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
// blog_view
if (preg_match('#^/blog/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
if (0 === strpos($pathinfo, '/blogger')) {
// blogger_index
if (preg_match('#^/blogger/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
// blogger_view
if (preg_match('#^/blogger/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
if (0 === strpos($pathinfo, '/bloggeroo')) {
// bloggeroo_index
if (preg_match('#^/bloggeroo/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
// bloggeroo_view
if (preg_match('#^/bloggeroo/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {...}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
// _blogtest
if ($pathinfo === '/blogtest') {...}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
// login
if ($pathinfo === '/login') {...}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
}
```
As far as I can see, you can throw the 404 earlier (as I've done), as by nesting all these possibilities, there is no chance another route will be matched outside the parent if statement.
---------------------------------------------------------------------------
by stloyd at 2011/06/11 08:37:15 -0700
You should follow Symfony [CS rules] (http://symfony.com/doc/current/contributing/code/standards.html), also you should modify tests.
---------------------------------------------------------------------------
by lmcd at 2011/06/11 08:46:32 -0700
Besides the inline `continue` statement, I can't see spot any other CS violations. I'm on to the updated tests.
---------------------------------------------------------------------------
by fabpot at 2011/06/13 02:19:14 -0700
What if you have this:
_blog:
resource: "@AcmeDemoBundle/Resources/config/routing/BlogController.yml"
prefix: /blog
login:
pattern: /login
defaults: { _controller: AcmeDemoBundle:Security:login }
_blogger:
resource: "@AcmeDemoBundle/Resources/config/routing/BloggerController.yml"
prefix: /blogger
You cannot send 404 early because the same `blog` prefix is used in two different places. I can see many things that will break with this patch. I'm pretty sure we can enhance the performance of the existing code but let's do that after 2.0.
---------------------------------------------------------------------------
by lmcd at 2011/06/13 05:04:03 -0700
@fabpot: The code was designed so it would work in these kind of circumstances. I ran the dumper against the routing file you provided and this is the output below.
I see no reason why you can't throw the 404 earlier, as by nesting everything with similar prefixes, we're eliminating the possibility that a route will ever be matched outside of that if statement.
```php
public function match($pathinfo)
{
$allow = array();
if (0 === strpos($pathinfo, '/blog')) {
// blog_index
if (preg_match('#^/blog/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
...
}
// blog_view
if (preg_match('#^/blog/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
...
}
if (0 === strpos($pathinfo, '/blogger')) {
// blog_index
if (preg_match('#^/blogger/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
...
}
// blog_view
if (preg_match('#^/blogger/(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
...
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
// login
if ($pathinfo === '/login') {
...
}
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
}
```
---------------------------------------------------------------------------
by fabpot at 2011/06/13 07:48:49 -0700
Can you add some more tests to ensure that everything works fine and that we won't have regressions later on? Thanks.
* lmcd/master:
$code referenced but not defined in compileRoute()
[Routing] Optimised the PHP URL matcher dumper The cached URL matcher classes contain some unneeded logic. Consider the following example:
The cached URL matcher classes contain some unneeded logic. Consider the following example:
if (0 === strpos($pathinfo, '/Blog')) {
// blog_index
if (0 === strpos($pathinfo, '/Blog') && preg_match('#^/Blog/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
return array_merge($this->mergeDefaults($matches, array ( '_action' => 'index',)), array('_route' => 'blog_index'));
}
}
The 2nd strpos is not required, as we have already satisfied this condition in the parent if statement.
My change will produce the following code for the same routing setup::
if (0 === strpos($pathinfo, '/Blog')) {
// blog_index
if (preg_match('#^/Blog/(?P<slug>[^/]+?)$#x', $pathinfo, $matches)) {
return array_merge($this->mergeDefaults($matches, array ( '_action' => 'index',)), array('_route' => 'blog_index'));
}
}
Here are the new simplified rules:
* Required cache warmers are *always* executed when the Kernel boots for the first time;
* Optional cache warmers are *only* executed from the CLI via cache:warmup
These new rules means that all the configuration settings for the cache
warmers have been removed. So, if you want the best performance, remember to
warmup the cache when going to production.
This also fixed quite a few bugs.
* Chekote/xmlfileloader_overload_refactor:
Refactored the processing of each individual node into it's own method, enabling easier overloading of behavior for Bundles such as FriendsOfSymfony/RestBundle
* alexandresalome/feat-routing-exceptions:
[Routing] Fix the exception inheritance + Add the LICENCE block in new files
[Routing] Change the Exception namespacing + base class for every exception + update PHPDoc
[Routing] Add specific exceptions for the UrlGenerator