Routing Wildcards

This page has a boring, hardcoded URL. What our aquanauts deserve is a dynamic route that can handle the URL for any genus - like /genus/octopus or /genus/hippocampus which is the genus that sea horses belong to. Oh man, sea horses are cute.

How? Change the URL to /genus/{genusName}:

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 7
class GenusController
{
/**
* @Route("/genus/{genusName}")
*/
public function showAction($genusName)
... lines 14 - 16
}

This genusName part could be named anything: the important part is that it is surrounded by curly braces. As soon as you do this, you are allowed to have a $genusName argument to your controller. When we go to /genus/octopus this variable will be set to octopus. That's pretty awesome.

The important thing is that the routing wildcard matches the variable name.

To test this is, change the message in the response to 'The genus: '.$genusName:

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 7
class GenusController
{
/**
* @Route("/genus/{genusName}")
*/
public function showAction($genusName)
{
return new Response('The genus: '.$genusName);
}
}

Tip

Be careful when rendering direct user input (like we are here)! It introduces a security issue called XSS - read more about XSS here.

Head back to the browser and refresh. Ah! A 404 error. That's because the URL is no longer /genus, it's now /genus/something: we have to have something on the other side of the URL. Throw octopus on the end of that (/genus/octopus). There's the new message. And of course, we could change this to whatever we want.

So what would happen if the wildcard and the variable name didn't match? Um I don't know: let's try it: change the wildcard name and refresh!

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 7
class GenusController
{
/**
* @Route("/genus/{genusName2}")
*/
public function showAction($genusName)
... lines 14 - 16
}

OMG: that's a sweet error:

The Controller::showAction() requires that you provide a value for the $genusName argument.

What Symfony is trying to tell you is:

Hey fellow ocean explorer, I'm trying to call your showAction(), but I can't figure out what value to pass to genusName because I don't see a {genusName} wildcard in the route. I'm shore you can help me.

As long as those always match, you'll be great.

Listing all Routes

When you load this page, Symfony loops over all the routes in your system and asks them one-by-one: do you match /genus/octopus? Do you match /genus/octopus? As soon as it finds one route that matches that URL, it stops and calls that controller.

So far, we only have one route, but eventually we'll have a lot, organized across many files. It would be swimming if we could get a big list of every route. Ha! We can!

Symfony comes with an awesome debugging tool called the console. To use it, go to the terminal and run

php bin/console

This returns a big list of commands that you can run. Most of these help you with debugging, some generate code and others do things like clear caches. We're interested in debug:router. Let's run that:

php bin/console debug:router

Nice! This prints out every route. You can see our route at the bottom: /genus/{genusName}. But there are other routes, I wonder where those are coming from? Those routes give you some debugging tools - like the little web debug toolbar we saw earlier. I'll show you where these are coming from later.

When we add more routes later, they'll show up here too.

Ok, fun fact! A baby seahorse is called a "fry".

How about a relevant fun fact? You now know 50% of Symfony. Was that really hard? The routing-controller-response flow is the first half of Symfony, and we've got it crossed off.

Now, let's dive into the second half.

Leave a comment!

  • 2016-06-26 weaverryan

    Hey Enkhbilguun E.!

    Good question :). If you're using annotation routes (like in this course), give you argument a default value:


    public function showAction($genusName = 'foo')

    When you do that, when you go to http://domain/genus, it will *now* match your route and use this default.

    Cheers!

  • 2016-06-26 Enkhbilguun E.

    Hi,
    How can we set a default value for the $genusName variable if http://domain/genus/{genusName} is empty?

  • 2016-05-18 weaverryan

    Hi Konrad!

    Apologies for my slow reply on your comments :). But now I've answered this question over on another comment: https://knpuniversity.com/scre...

    Cheers!

  • 2016-05-14 Konrad ZajÄ…c

    Hi,about this use argument/
    I heve these two use statements:

    use Symfony\Component\BrowserKit\Response

    use Symfony\Component\HttpFoundation\Response;
    when I use symfonys autocompletion - I get the first one.
    But the second one is the one that works, could somone explain?
    -----edit-----
    sometimes it's the other way:
    use Symfony\Component\HttpKernel\Tests\Controller;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    symfony gave me the first, but the second one works