Chapters
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
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:<6.2.10"
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 "/"
.
Show Lines
|
// ... lines 1 - 5 |
use Symfony\Component\Routing\Annotation\Route; | |
class QuestionController | |
{ | |
/** | |
* @Route("/") | |
*/ | |
public function homepage() | |
{ | |
Show Lines
|
// ... 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()
.
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... lines 10 - 20 |
public function show() | |
{ | |
Show Lines
|
// ... 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!
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... lines 10 - 17 |
/** | |
* @Route("/questions/how-to-tie-my-shoes-with-magic") | |
*/ | |
public function show() | |
{ | |
Show Lines
|
// ... line 23 |
} | |
} |
Inside, just like last time, return a new Response
: the one from HttpFoundation
.
Future page to show a question
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... 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.
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... lines 10 - 17 |
/** | |
* @Route("/questions/{slug}") | |
*/ | |
public function show($slug) | |
{ | |
Show Lines
|
// ... 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.
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... 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!
Show Lines
|
// ... lines 1 - 7 |
class QuestionController | |
{ | |
Show Lines
|
// ... lines 10 - 20 |
public function show($slug) | |
{ | |
return new Response(sprintf( | |
Show Lines
|
// ... line 24 |
ucwords(str_replace('-', ' ', $slug)) | |
)); | |
} | |
} |
Next, our new app is hiding a secret! A little command-line executable that's filled with goodies.
47 Comments
Hey Bob19,
Thanks for sharing this tip with others!
Cheers!
@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 :-)
Hi,
I am using symfony version 5.1.11 for my project
when I run composer require annotations command I get this error :
In App_KernelDevDebugContainer.php line 317:
Attempted to call an undefined method named "registerLoader" of class "Doctrine\Common\Annotations\AnnotationRegistry".
could you help me
THANKS
Had the same problem with Symfony 5.0.
See: https://github.com/symfony/symfony/issues/48717
Maunally change version of doctrine/annotations to ^1.14
Hi Agne,
thanks a lot for your answer
the problem is solved :)
Is there a VSCode equivalent to the auto-completion phpStorm does?
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!
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!!!
Lol Oliver W., 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!
It worked finally ! For begineers, you should really obligate, in the first tutorial, to pull Symfony by specifying the version 5 on "Symfony new myproject --version=5.4". It seems that not choosing it, will pull by default Symfony >=v6. Symfony 6 doesnt come with annotaions.yaml file and uses default routes.yaml configuration even after requiring annotation.
Hey mimoudi!
Thanks for sharing it with others. And yes, if you don't specify, Symfony CLI will install the latest stable symfony version that is supported by your PHP version. Oh, and you can avoid this issues if you download the course code from this page
Cheers!
Hello, my @Route does not shows homepage, how should I to fix it? It require some new lines in routes.yaml file?
Hey Szymon,
That's odd, did you give it a name for your route? Also, this is basically all the config you need to load routes defined with PHP attributes
controllers:
resource: ../src/Controller/
type: attribute
You can run bin/console debug:router
to debug all the routes defined in your application
Cheers!
my @Route doesn't work? someone has this problem before
`<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class QuestionController
{
/**
* @Route("/")
*/
public function homepage()
{
return new Response('What a bewitching controller we have conjured!');
}
}`
Hey Jitze,
Sometimes it happens :) Please, double-check the namespace, do you this "use Symfony\Component\Routing\Annotation\Route;" line in the controller? If no - please, add it and try again. If still nothing - let us know, but provide a bit more info please, do you see any errors? How is your PHPDoc looks like exactly?
Cheers!
The solution for this problems is to install the annotations as package. Cause the routing.yaml has only defined the specific controllers. For this project I must configure the annotations for all controllers. https://symfony.com/doc/cur....
Hey Jitze
Yes, you need to install the annotations library (but not necessarily as a package), and then, in the routing.yaml
file, set the type key to annotation
, and all the controllers living under the specified directory will have annotations support
Cheers!
Hey there
str_replace
is not the best solution for it, yeah you can use it in your template when generate the link with {{ path() }}
function, but honestly it's better to use slug system for urls
Cheers
Small question.. in Symfony 5.2+ there using Attributes from php8 instead of doctrine Annotations... if your environment (php is >8+)... my question is how to handle the {} in annotations to attributes
`/**
* @Route("/create", name="create_something", methods = {"POST"})
*/
#[Route('/create', name: 'create_something', methods: 'POST')]`
my phpstorm is angry if i want use {} in attributes :( like methods: {'POST'} and still getting warning about Expected parameter of type 'string[]|void', 'string' provided if i let there only methods: 'POST'
Did i attribute in right way or i am missing something? i tried find some official documentations.. but i didn't
Update:
i got now that must be an array and answer is => methods: ['POST']
Hey Miky
I found this docs about attributes https://wiki.php.net/rfc/named_params (scroll down to the attributes part)
It says that the syntax should be like this (in case it was accepted because it seems outdated)#[Route("/api/posts/{id}", ["methods" => ["GET", "HEAD"]])]
Cheers!
I have tried everything still I am getting no route for "GET/.....error everytime
Hey @Sonam
if you run bin/console debug:router
can you see your routes there?
Cheers!
No I can only see _preview_error after running php bin/console debug:router
Ok, in that case your routes are not being loaded. Are you using annotations for your routes? If that's the case you need to double-check your config/routes/annotations.yaml
file has these lines:
controllers:
resource: ../../src/Controller/
type: annotation
kernel:
resource: ../../src/Kernel.php
type: annotation
I'm assuming you're on Symfony 5
Cheers!
Why my browser not updated the code? but if i am stop server and start again, code updated
Hey Rizky,
It depends on what exactly code you're changing. But mostly, clearing the cache should help you, especially if you use any virtualization tool locally. If you don't see changes - the first thing you can try - clear the cache with "bin/console cache:clear". It should help 99%. Btw, make sure you're in dev Symfony environment. If you're in prod env - you will always need to clear the cache manually, Symfony recompile the cache only in dev / test envs.
I hope this helps!
Cheers!
I entered /questions/<textarea>
in the address bar and it injected the HTML. I assumed the Symfony Response object would wrap it in something like htmlentities. I assumed wrong!
Hey Jack K.!
You're right about that! But, if you passed that value into Twig and rendered it, then it *would* automatically be escaped. So, in reality, it *is* escaped if you ever try to use that value in a real HTML page :).
Cheers!
Hi.
I need a redirect from path /important-pages///.... to /important-pages.
I tried writing like this, but it doesn't work. How can i solve this problem?
config/routes.yaml
test:
path: ^/important-pages
controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction
defaults:
path: /important-pages
permanent: true
Hey Dmitriy
Pretty common situation, but as I know path
is not compatible with regular expressions. So in such case it's better to create some request listener, which will check url and return a redirect instead of response
Cheers!
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.
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!
The problem was solved, thank you.
i'm using symfony 5 on windows
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!
i found why!!!!
Regards
Telou
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.
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!
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).
ok, so I did two things now:
1) installing: <blockquote>"symfony/apache-pack"</blockquote>
2) updating: <blockquote>"/private/etc/apache2/extra/httpd-vhosts.conf"</blockquote>
`
<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 <blockquote>dev.symfony5.local/index.php</blockquote>
Any idea what I need to change?
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!
Heysadikoff
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
You really need to stop assumimg PHPStorm. Yes it is great but its also expensive. Show things without PHPStorm smart completion.
Hey Richard
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!
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 :).
Hey @maxii123,
You can download and try it with trial period. Or take a look at PhpStorm Early Access Program: https://www.jetbrains.com/r... - a little known fact but it allows you to test latest beta versions of this for free. Feel free to report bugs and help improving it, of course.
I hope this helps!
Cheers!
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.3.0 || ^8.0.0",
"ext-ctype": "*",
"ext-iconv": "*",
"easycorp/easy-log-handler": "^1.0.7", // v1.0.9
"sensio/framework-extra-bundle": "^6.0", // v6.2.1
"symfony/asset": "5.0.*", // v5.0.11
"symfony/console": "5.0.*", // v5.0.11
"symfony/debug-bundle": "5.0.*", // v5.0.11
"symfony/dotenv": "5.0.*", // v5.0.11
"symfony/flex": "^1.3.1", // v1.21.6
"symfony/framework-bundle": "5.0.*", // v5.0.11
"symfony/monolog-bundle": "^3.0", // v3.5.0
"symfony/profiler-pack": "*", // v1.0.5
"symfony/routing": "5.1.*", // v5.1.11
"symfony/twig-pack": "^1.0", // v1.0.1
"symfony/var-dumper": "5.0.*", // v5.0.11
"symfony/webpack-encore-bundle": "^1.7", // v1.8.0
"symfony/yaml": "5.0.*" // v5.0.11
},
"require-dev": {
"symfony/profiler-pack": "^1.0" // v1.0.5
}
}
Sucessfully installed annotations with:
php74 /usr/bin/composer require -W sensio/framework-extra-bundle:"^5.2"
php74 /usr/bin/composer require annotations