Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2: URLs with trailing slash and an optional parameter

I want all URLs in my application to have a trailing slash. I have the following route in my route.yml:

foo_route:
    pattern:  /foo/{page}/
    defaults: { _controller: FooBundle:Foo:list, page: 1 }
    requirements:
      page:  \d+

Requests to '/foo/1/' work fine, however requests to '/foo/' are not matched because of the trailing slash in the URL pattern.

How can I define routes with trailing slashes and an optional parameter? I am aware I can define 2 different routes for the two cases, but I want to avoid that.

like image 602
Gerry Avatar asked Apr 10 '12 15:04

Gerry


People also ask

How do you add a trailing slash to a URL?

A trailing slash is a forward slash (“/”) placed at the end of a URL such as domain.com/ or domain.com/page/. The trailing slash is generally used to distinguish a directory which has the trailing slash from a file that does not have the trailing slash.

Why do some URLs have a trailing slash?

Conventionally, a trailing slash (/) at the end of a URL meant that the URL was a folder or directory. A URL without a trailing slash at the end used to mean that the URL was a file.

Should URLs have a trailing slash?

If your site has a directory structure, it's more conventional to use a trailing slash with your directory URLs (for example, example.com/directory/ rather than example.com/directory ), but you can choose whichever you like. Be consistent with the preferred version. Use it in your internal links.

Can a URL have a slash?

“The slash after a hostname or domain name is irrelevant; you can use it or not when referring to the URL, it ends up being the same thing… However, a slash anywhere else is a significant part of the URL and will change the URL if it's there or not.”


2 Answers

In a separate but related case, you can match the following three patterns:

/foo
/foo/
/foo/page/1

by eliminating the trailing backslash in the route and relaxing the regular expression to match 0 or more characters (*), instead of 1 or more (+):

foo_route:
    pattern:  /foo/{page}
    defaults: { _controller: FooBundle:Foo:list, page: 1 }
    requirements:
      page:  \d*

However that will not match /foo/page/1/

like image 190
Brave Dave Avatar answered Oct 04 '22 09:10

Brave Dave


Perhaps its easier to define the Controller over an annotation.

in route.yml:

MineTestBundle:
    resource: "@MineTestBundle/Controller/"
    type:     annotation

Then you can define the route direct in your controller.

/**
 * @Route("/foo")
 */
class FooController extends Controller {
    /**
     * @Route("/", name="_foo_index")
     * @Template()
     */
    public function indexAction() {
        return array();
    }

    /**
     * @Route("/{page}/", name="_foo_page")
     * @Template()
     */
    public function pageAction($page) {
        return array('page' => $page);
    }
}

Now when you try to access /foo you come to the indexAction and when you access /foo/1/ you come to the pageAction.

Edit:

Sorry for the misunderstanding. I've tried to reproduce your problem. The easiest way is to define 2 Routes in your config like this:

foo_route:
    pattern:  /foo/{page}/
    defaults: { _controller: AcmeDemoBundle:Foo:list }
    requirements:
        name: ".+"  

foo_route_foo:
    pattern:  /foo
    defaults: { _controller: AcmeDemoBundle:Foo:list, page: 1 }
    requirements:
        name: ".+"

In the Route without the parameter {page} You can set the page default to 1.

But here in the Cookbook is a chapter How to allow a "/" character in a route parameter so its possible to allow a / in the route so all that comes after /foo/123/234/ is in the variable $page and you can split them for yourself in your function.

like image 38
René Höhle Avatar answered Oct 04 '22 08:10

René Höhle