Explorar el Código

[Routing] Make trailing slashes in urls optional

Jordi Boggiano hace 14 años
padre
commit
fe694de746

+ 31 - 0
src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php

@@ -54,4 +54,35 @@ class RedirectController extends ContainerAware
 
         return $response;
     }
+
+    /**
+     * Redirects to a URL.
+     *
+     * It expects a url path parameter.
+     * By default, the response status code is 301.
+     *
+     * If the url is empty, the status code will be 410.
+     * If the permanent path parameter is set, the status code will be 302.
+     *
+     * @param string  $url       The url to redirect to
+     * @param Boolean $permanent Whether the redirect is permanent or not
+     *
+     * @return Response A Response instance
+     */
+    public function urlRedirectAction($url, $permanent = false)
+    {
+        if (!$url) {
+            $response = $this->container->get('response');
+            $response->setStatusCode(410);
+
+            return $response;
+        }
+
+        $code = $permanent ? 301 : 302;
+
+        $response = $this->container->get('response');
+        $response->setRedirect($url, $code);
+
+        return $response;
+    }
 }

+ 28 - 3
src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

@@ -60,8 +60,14 @@ class PhpMatcherDumper extends MatcherDumper
                 $conditions[] = sprintf("isset(\$this->context['method']) && preg_match('#^(%s)$#xi', \$this->context['method'])", $req);
             }
 
+            $hasTrailingSlash = false;
             if (!count($compiledRoute->getVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
-                $conditions[] = sprintf("\$url === '%s'", str_replace('\\', '', $m['url']));
+                if (substr($m['url'], -1) === '/' && $m['url'] !== '/') {
+                    $conditions[] = sprintf("rtrim(\$url, '/') === '%s'", rtrim(str_replace('\\', '', $m['url']), '/'));
+                    $hasTrailingSlash = true;
+                } else {
+                    $conditions[] = sprintf("\$url === '%s'", str_replace('\\', '', $m['url']));
+                }
 
                 $matches = 'array()';
             } else {
@@ -69,15 +75,34 @@ class PhpMatcherDumper extends MatcherDumper
                     $conditions[] = sprintf("0 === strpos(\$url, '%s')", $compiledRoute->getStaticPrefix());
                 }
 
-                $conditions[] = sprintf("preg_match('%s', \$url, \$matches)", $compiledRoute->getRegex());
+                $regex = $compiledRoute->getRegex();
+                if ($pos = strpos($regex, '/$')) {
+                    $regex = substr($regex, 0, $pos) . '/?$' . substr($regex, $pos+2);
+                    $conditions[] = sprintf("preg_match('%s', \$url, \$matches)", $regex);
+                    $hasTrailingSlash = true;
+                } else {
+                    $conditions[] = sprintf("preg_match('%s', \$url, \$matches)", $regex);
+                }
 
                 $matches = '$matches';
             }
 
             $conditions = implode(' && ', $conditions);
 
-            $code[] = sprintf(<<<EOF
+            $code[] = <<<EOF
         if ($conditions) {
+EOF;
+
+            if ($hasTrailingSlash) {
+                $code[] = sprintf(<<<EOF
+            if (substr(\$url, -1) !== '/') {
+                return array('_controller' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\RedirectController::urlRedirectAction', 'url' => \$this->context['base_url'].\$url.'/', 'permanent' => true, '_route' => '%s');
+            }
+EOF
+            , $name);
+            }
+
+            $code[] = sprintf(<<<EOF
             return array_merge(\$this->mergeDefaults($matches, %s), array('_route' => '%s'));
         }