Annotation & Wildcard Routes

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Creating a route in YAML that points to a controller function is pretty simple. But there's an even easier way to create routes... and I love it. It's called: annotations.

First, comment-out the YAML route. Basically, remove it entirely. To prove it's not working, refresh the homepage. Yep! It's back to the welcome page.

#index:
# path: /
# controller: App\Controller\QuestionController::homepage

Installing Annotations Support

Annotations are a special config format... and support for annotations is not something that comes standard in our tiny Symfony app. And... that's fine! In fact, that's the whole philosophy of Symfony: start small and add features when you need them.

To add annotations support, we'll use Composer to require a new package. If you don't have Composer installed already, go to https://getcomposer.org.

Once you do, run:

composer require annotations

If you're familiar with composer, that package name might look strange. And in reality, it installed a totally different package: sensio/framework-extra-bundle. Near the bottom of the command, it mentions something about two recipes. We'll talk about what's going on soon: it's part of what makes Symfony special.

Adding a Route Annotation

Anyways, now that annotations support is installed, we can re-add our route via annotations. What does that mean? Above your controller function, say /** and hit enter to create a PHPDoc section. Then say @Route and auto-complete the one from the Routing component. Just like before, PhpStorm added the use statement at the top of the class automatically.

Inside the parentheses, say "/".

... lines 1 - 5
use Symfony\Component\Routing\Annotation\Route;
class QuestionController
{
/**
* @Route("/")
*/
public function homepage()
{
... line 15
}
}

That's it! When the user goes to the homepage, it will execute the function right below this. I love annotations because they're simple to read and keep the route and controller right next to each other. And yes... annotations are literally configuration inside PHP comments. If you don't like them, you can always use YAML or XML instead: Symfony is super flexible. From a performance standpoint, all the formats are the same.

Now when we refresh the homepage... we're back!

A Second Route and Controller

This page will eventually list some recently-asked questions. When you click on a specific question, it will need its own page. Let's create a second route and controller for that. How? By creating a second method. How about: public function show().

... lines 1 - 7
class QuestionController
{
... lines 10 - 20
public function show()
{
... line 23
}
}

Above this, add @Route() and set the URL to, how about, /questions/how-to-tie-my-shoes-with-magic. That would be awesome!

... lines 1 - 7
class QuestionController
{
... lines 10 - 17
/**
* @Route("/questions/how-to-tie-my-shoes-with-magic")
*/
public function show()
{
... line 23
}
}

Inside, just like last time, return a new Response: the one from HttpFoundation.

Future page to show a question

... lines 1 - 7
class QuestionController
{
... lines 10 - 17
/**
* @Route("/questions/how-to-tie-my-shoes-with-magic")
*/
public function show()
{
return new Response('Future page to show a question!');
}
}

Let's try it! Copy the URL, move over to your browser, paste and... it works! We just created a second page... in less than a minute.

The Front Controller: Working Behind-the-Scenes

By the way, no matter what URL we go to - like this one or the homepage - the PHP file that our web server is executing is index.php. It's as if we are going to /index.php/questions/how-to-tie-my-shoes-with-magic. The only reason you don't need to have index.php in the URL is because our local web server is configured to execute index.php automatically. On production, your Nginx or Apache config will do the same. Check the Symfony docs to learn how.

A Wildcard Route

Eventually, we're going to have a database full of questions. And so, no, we are not going to manually create one route per question. Instead, we can make this route smarter. Replace the how-to-tie-my-shoes-with-magic part with {slug}.

When you have something between curly braces in a route, it becomes a wildcard. This route now matches /questions/ANYTHING. The name {slug} is not important: we could have used anything... like {slugulusErecto}! That makes no difference.

But whatever we call this wildcard - like {slug} - we are now allowed to have an argument to our controller with the same name: $slug... which will be set to whatever that part of the URL is.

... lines 1 - 7
class QuestionController
{
... lines 10 - 17
/**
* @Route("/questions/{slug}")
*/
public function show($slug)
{
... lines 23 - 26
}
}

Let's use that to make our page fancier! Let's use sprintf(), say "the" question and add a %s placeholder. Pass $slug for that placeholder.

... lines 1 - 7
class QuestionController
{
... lines 10 - 17
/**
* @Route("/questions/{slug}")
*/
public function show($slug)
{
return new Response(sprintf(
'Future page to show the question "%s"!',
$slug
));
}
}

Sweet! Move over, refresh and... love it! Change the URL to /questions/accidentally-turned-cat-into-furry-shoes and... that works too.

In the future, we'll use the $slug to query the database for the question. But since we're not there yet, I'll use str_replace() ... and ucwords() to make this just a little more elegant. It's still early, but the page is starting come alive!

... lines 1 - 7
class QuestionController
{
... lines 10 - 20
public function show($slug)
{
return new Response(sprintf(
... line 24
ucwords(str_replace('-', ' ', $slug))
));
}
}

Next, our new app is hiding a secret! A little command-line executable that's filled with goodies.

Leave a comment!

  • 2020-07-13 Victor Bocharsky

    Hey Mike,

    Unfortunately, I personally use PhpStorm, so don't know much about VSCode. I believe that the most powerful autocompletion for Symfony project available in PhpStorm only thanks to Symfony Plugin, but I might be wrong. Probably some users who use VSCode could give you some tips about it.

    Cheers!

  • 2020-07-11 Mike Hunt

    Is there a VSCode equivalent to the auto-completion phpStorm does?

  • 2020-07-08 Diego Aguiar

    Lol Oliver Wagner, it happens :)

    By the way, there is a library that helps you with the .htaccess file and here are some good recomendations about how configuring your Apache server https://symfony.com/doc/cur...

    I hope it helps. Cheers!

  • 2020-07-08 Oliver Wagner

    I've got 2 Symfonyprojects with annotations - on the same XAMPP. On one of them the routing works on the other one I get a 404 for a route other than "/". If I call server/index.php/route it works. I can't find the error. Thx for any hints.

    Btw: there is no .htaccess on none of the two projects. I work with vhosts.

    @maxii123 Me tooooo, I love PHPStorm!

    Arrrrghhh: typical I/O-Error (Idiot Operator). There is a .htaccess for the working project. But not in the root of the project but, of corse, in the public folder!!!

  • 2020-05-14 Antonio Gigante Arias

    The problem was solved, thank you.

  • 2020-05-13 Diego Aguiar

    Hey Antonio Gigante Arias

    Let's try a couple of things
    First, double check that the class name of the controller matches to its file, in other words MainController.php file must contain a class named MainController
    Second, clear your cache manually rm -rf var/cache it's rare, but sometimes the cache is bugged.
    Third, re-install your vendors. rm -rf vendor && composer install
    If nothing works, please let me know

    Cheers!

  • 2020-05-13 Antonio Gigante Arias

    i'm using symfony 5 on windows

  • 2020-05-13 Antonio Gigante Arias

    Hello,
    i'm trying to install "sensioframework", but when type "composer require annotations" i got this error.

    The autoloader expected class "App\Controller\MainController" to be defined
    !! in file "C:\xampp\htdocs\SES\vendor\composer/../../src\Controller\MainCont
    !! roller.php". The file was found but the class was not in it, the class name
    !! or namespace probably has a typo.
  • 2020-04-30 Ethel Henrard

    i found why!!!!

    Regards

    Telou

  • 2020-04-30 Telou

    Hello,
    i just installed the Annotations Plugin but i have no autocompletion. I haven't been able to find why! Maybe you can help me?
    Thank you so much for this videos, i love them!

  • 2020-04-30 Tim K.

    HeyVladimir Sadicov
    thanks for the answer. The problem was mod_rewrite. Once enabled in httpd.conf (and restart of apache server) the problem was solved.

    Many Thanks!!!
    Tim

  • 2020-04-29 Vladimir Sadicov

    Hey @Tim

    do you have mod_rewrite enabled? Also if you are using htaccess than I'd recommend to configure mi]nimal support for you virtual host :

    <virtualhost *:80="">
    ServerName domain.tld
    ServerAlias www.domain.tld

    DocumentRoot /var/www/project/public
    <directory var="" www="" project="" public="">
    AllowOverride All
    Order Allow,Deny
    Allow from All
    </directory>

    # uncomment the following lines if you install assets as symlinks
    # or run into problems when compiling LESS/Sass/CoffeeScript assets
    # <directory var="" www="" project="">
    # Options FollowSymlinks
    # </directory>

    ErrorLog /var/log/apache2/project_error.log
    CustomLog /var/log/apache2/project_access.log combined
    </virtualhost>

    Cheers!

  • 2020-04-29 Tim K.

    ok, so I did two things now:

    1) installing:

    "symfony/apache-pack"


    2) updating:

    "/private/etc/apache2/extra/httpd-vhosts.conf"


    <virtualhost *:80="">
    DocumentRoot "/xxxxxxxxxxxxxxxx/symfony5/public"
    ServerName dev.symfony5.local


    DirectoryIndex /index.php


    <directory "="" xxxxxxxxxxxxxxxx="" symfony5="" public"="">
    AllowOverride All

    Require all granted
    Allow from All


    FallbackResource /index.php
    </directory>
    </virtualhost>

    It is now routing correct, but the landing page has in the URL the "index.php". Like

    dev.symfony5.local/index.php

    Any idea what I need to change?

  • 2020-04-28 Tim K.

    Just installing symfony/apache-pack? Anything else? - sorry but I dont really understand the support here. Do I have to follow any of these actions too?

    I am using symfony5 with MacOS (without Homebrew).

  • 2020-04-20 Vladimir Sadicov

    Hey Markus Michalski

    Yes that can be confused :) And the easiest way to solve it is installing symfony/apache-pack it will bring you cool and fast configuration for apache!

    Cheers!

  • 2020-04-19 Markus Michalski

    Just in case someone is confused why they geh URL not found after adding the second route (like me :)) and you're using Apache (like me :) - actually using a Vagrant maschine) - you have to add an .htaccess to the public folder with rewriting rules.

  • 2020-03-17 weaverryan

    Yea, sorry about this. In this intro course, I really try to show that it's being used. But after awhile, if we scroll up to add the use statement every time manually, I think a whole other group of people will be mad at me for wasting their time :). It's tough to please everyone - but sorry if it confused :).

  • 2020-03-11 Diego Aguiar

    Hey maxii123

    We usually mention or show what it's PHPStorm doing behind the scenes, I apologize if this confused you.
    BTW, we highly recommend (no body is paying us) to develop with PHPStorm any PHP project because it's by far the best IDE in the market

    Cheers!

  • 2020-03-11 Robertino Vasilescu

    @maxii123 I respectfully disagree somehow; for someone starting into developing yes it might be a bit expensive but even for a beginner dev 70 EUR (50 EUR third year) per year is not expensive at all; if one doesn't do this much in a year it is hopeless :-)

  • 2020-03-09 maxii123

    You really need to stop assumimg PHPStorm. Yes it is great but its also expensive. Show things without PHPStorm smart completion.