Code goes in src/ and app/

You may have noticed that most of the committed files were in app/ and src/. That's on purpose: these are the only two directories you need to worry about. src/ will hold all the PHP classes you create and app/ will hold everything else: mostly configuration and template files. Ignore all the other directories for now and just focus on src/ and app/.

Building the First Page

Remember the functional homepage? It's coming from this DefaultController.php file. Delete that! Do it! Now we have an absolutely empty project. Refresh the homepage!

No route found for "GET /"

Perfect! That's Symfony's way of saying "Yo! There's no page here."

Now back to the main event: building a real page.

Our top secret project is called AquaNote: a research database for Aquanauts. These cool underwater explorers log their discoveries of different sea creatures to this nautical site. Our first page will show details about a specific genus, for example, the octopus genus.

Creating a page in Symfony - or any modern framework - is two steps: a route and a controller. The route is a bit of configuration that says what the URL is. The controller is a function that builds that page.


So, step 1: create a route! Actually, we're going to start with step 2: you'll see why. Create a new class in AppBundle/Controller called GenusController. But wait! The namespace box is empty. That's ok, but PhpStorm can help us out a bit more. Hit escape and then right-click on src and select "mark directory as sources root".

Now re-create GenusController. This time it fills in the namespace for me:

18 lines src/AppBundle/Controller/GenusController.php
namespace AppBundle\Controller;
... lines 4 - 7
class GenusController
... lines 10 - 16

Go Deeper!

If namespaces are new to you, welcome! Take a break and watch our PHP Namespaces Tutorial.

The most important thing is that the namespace must match the directory structure. If it doesn't, Symfony won't be able to find the class. By setting the sources root, PhpStorm is able to guess the namespace. And that saves us precious time.

Controller and Route

Inside, add a public function showAction():

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 7
class GenusController
... lines 10 - 12
public function showAction()
... line 15

Hey, this is the controller - the function that will (eventually) build the page - and its name isn't important. To create the route, we'll use annotations: a comment that is parsed as configuration. Start with /** and add @Route. Be sure to let PhpStorm autocomplete that from the FrameworkExtraBundle by hitting tab. This is important: it added a use statement at the top of the class that we need. Finish this by adding "/genus":

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 4
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
... lines 6 - 7
class GenusController
* @Route("/genus")
public function showAction()
... lines 14 - 16

Beautiful, that's the route and the URL for the page is /genus.

Returning a Response

As I already said: the controller is the function right below this, and its job is to build the page. The only rule for a controller is that it must return a Symfony Response object.

But hold on. Let's just all remember what our only job is as web developers: to understand the incoming request and send back a response, whether that's an HTML response, a JSON response of a PDF file. Symfony is modeled around this idea.

Keep things simple: return new Response. The Response class is the one from the HttpFoundation component. Hit tab to auto-complete it. This adds the use statement on top that we need. For the content, how about: 'Under the Sea!':

18 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 5
use Symfony\Component\HttpFoundation\Response;
class GenusController
* @Route("/genus")
public function showAction()
return new Response('Under the sea!');

That's it!

We've only created one file with one function, but we already have a route, a controller and a lot of sea floor that needs discovering!

If you refresh the homepage, well... that's not going to work. Navigate instead to the URL: /genus. Woh! There's your first page in Symfony, done in about 10 lines of code. Simple enough for you?

Next, let's create a dynamic URL.

Leave a comment!

  • 2017-03-04 weaverryan

    Yo Blaise!

    I think you're doing *almost* everything right. First, right now, we want to boot Symfony in the dev environment. That means either setting your Nginx conf to use app_dev.php as the default script, OR, just putting this in your URL - e.g. URLs (locally) like this:


    One way or another, you want your web server to execute the web/app_dev.php file. If you do this, even if you see an error or a 404 page, it should be a big, beautiful debugging error page (versus the simple, ugly 500 Internal Server Error you're seeing now). So, let's get this working as step 1!

    When you actually deploy, you *do* want to set your configuration to execute app.php. The only caveat is that whenever you switch to the "prod" environment (this is the "environment" used when you execute the app.php file), you need to clear your prod cache via:

    php bin/console cache:clear --env=prod

    This is obviously an important detail! So we talk about it in the next tutorial - and the next 2 chapters after that. My guess is that it's working in production now because when you deployed your code, the cache directory was empty, so Symfony correctly built new cache files on production from the latest versions of your files. But locally, as soon as you execute your app in the "prod" environment the first time, it creates a bunch of cache files. If you change something (e.g. delete DefaultController), then it's still using that old, now-outdated cache. Behind the scenes, the cached route still exists, but since the controller was deleted - you're getting a 500 error. Oh, and one last thing - you can always see what the error was in the prod environment by looking at the var/logs/prod.log file.

    Let me know if that helps!

  • 2017-03-03 Blaise

    Hey. I've got this problem:
    I am using external server on Linux with NGINX running.
    As long as symfony DefaultController is on server routing only works for "/" as set to default. When i delete it, i get

    Oops! An Error Occurred

    The server returned a "500 Internal Server Error".

    Something is broken. Please let us know what you were doing when this error occurred.
    We will fix it as soon as possible. Sorry for any inconvenience caused.
    When i do everything step by step via tutorial i get 404 not found. Tried /app.php/~~ tried app_dev.php - does not work.
    NGINX conf file is set from symfony documentation.
    Deployment is set and works.
    What the fudge is going on? :)

  • 2017-01-06 Victor Bocharsky

    Hey Marlene,

    Not `composer update` but `composer install`. You could check the README file inside downloaded code - there's instructions how to bootstrap project. Let us know if `composer install` doesn't help you.


  • 2017-01-05 Marlene Ayers

    I had to go into Terminal and run composer update????????

  • 2017-01-05 weaverryan

    Hey Marlene!

    Dang, sorry about that - not having auto-complete takes all the fun out of it! A few questions:

    1) When you type @Route, are you using a capital R - it'll only auto-complete if you are!
    2) If you ignore the fact that it doesn't auto-complete and manually add the @Route (and manually add the use statement at the top of the class - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route) - does the page work? I'm trying to make sure something else isn't going wrong.

    If you ARE using a capital R and the page works when you setup things correctly... but still don't get auto-complete, you may need to check with the PhpStorm guys - I've never seen this specifically not work!

    Good luck!

  • 2017-01-05 Marlene Ayers

    Using the latest PhpStorm 2016.3.2. Have enabled, installed and reinstalled Symfony and PHP Annotations, restarted, invalidated cache, etc. I still cannot get @route to autocomplete. When I go to Settings>Editor>Inspections I see "Symfony | Route | Symfony: Route settings deprecated" I have googled but nothing. Help! Also this message in PHPAnnotations: Doc block annotation class found, but its missing in use statement You should import the class as use statement

  • 2016-12-21 weaverryan

    Hi Lazar Aleksic!

    Hmm. so, as you can see in the video, when you type @Route - and let it auto-complete, it should add the use statement on top. If it didn't, double-check that you installed the "PHP Annotations" PHPStorm plugin. I forgot to show this in the screencast (but we did add a note later about it).

    Let me know if that helps!

  • 2016-12-21 Lazar Aleksic

    Hi there i have a problem.

    I typed : /**
    * @Route("/Genus")
    and it didnt set the USE sensio. I still see that my Route(genus) didnt became Green as it shd.

  • 2016-12-05 Victor Bocharsky

    Hey Sebastian,

    Actually, we do teach how to do a login form, but in another course. This topic is pretty complex to cover it in this intro tutorial. Please, check our Symfony Security: Beautiful Authentication, Powerful Authorization course.


  • 2016-12-02 weaverryan

    Hey Sebastian Torres!

    This is a classic problem / challenge we have with the Symfony documentation: there are so many different and valid ways to do things, that sometimes one topic can become disjointed. I recommend checkout out our security tutorial - - we build a traditional login form that loads users from the database. The whole setup is there (it's a bit of a different approach than in the Symfony docs - one that I slightly prefer).

    Cheers and good luck!

  • 2016-12-01 Sebastian Torres

    When i was seeing

    How to Build a Traditional Login Form

    i was hoping that I would create a login form using database but when I see "In this entry, you'll build a traditional login form. Of course, when the user logs in, you can load your users from anywhere - like the database. See B) Configuring how Users are Loaded for details". It was the beginner of the confusion. I followed those steps. but I could not to do the login form. I have been trying to understand the documentation of symfony

  • 2016-12-01 Sebastian Torres

    Why don't you teach how to do a login form. You said in this videos that we know about 50% . why don't you teach how to do a login ? how to create. I mean the documentation about symfony is very confuse, i was trying do design an app with a simple login form but when i see that i see
    "you need to design a form with database click here. Before to read this topic you need to have an entity. see FosUserBundle . After see ForUserBundle i see put your own logic here with the correct parameters. I come back to the symfony.
    class: AppBundle:User
    property: username"
    our_db_provider is for what i do not understand.


  • 2016-11-09 Victor Bocharsky

    Hey Megakills ,

    What do you mean about the "controller map"? i.e. PhpStorm also removes annotation routes? I think this magic could come with Symfony plugin, but I'm not sure. Probably, I have never encountered with this problem because of keeping this controller or just rename it in some cases :p


  • 2016-11-08 Megakills

    When i delete DefaultController.php phpstorm also delelte the controller map.

  • 2016-11-08 Victor Bocharsky

    Hi Jelle,

    Quick catch! ;)


  • 2016-11-08 Jelle Schouwstra

    Sorry, forgot to add the double quotes around "/genus" !

  • 2016-11-08 Jelle Schouwstra

    First off, great tutorial!

    When I added the annotation /genus and I tried to access it I get the following error:

    [Syntax Error] Expected PlainValue, got '/' at position 7
    in method AppBundle\Controller\GenusController::showAction() in
    C:\inetpub\wwwroot\aqua_note\src\AppBundle/Controller/ (which is being
    imported from "C:\inetpub\wwwroot\aqua_note\app/config\routing.yml").

    500 Internal Server Error - FileLoaderLoadException

    This is my controller code:
    namespace AppBundle\Controller;

    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Symfony\Component\HttpFoundation\Response;

    class GenusController
    * @Route(/genus)
    public function showAction(){
    return new Response('Under the sea!');

  • 2016-09-25 weaverryan

    Hey Mamun!

    I think I know the problem :). Whatever the URL is in your browser - add an app_dev.php to it. For example, if you setup XAMPP to have a URL like http://symfony.l, then go to http://symfony.l/app_dev.php. In fact, while developing, you'll always have that app_dev.php in your URL - e.g. http://symfony.l/app_dev.php/products (instead of just /products).

    Having the app_dev.php in the URL loads Symfony in the "dev" environment, where you see any errors and your cache is always rebuilt. The reason you don't see this in the video is that we're using the built-in PHP web server through Symfony, which does this (automatically & invisibly) for you. But, if you're using your own web server, that's great - you just need to add that app_dev.php to the URL yourself. When you do that, I think you won't see this error anymore. There's more info about this here:

    Let me know if that helps!

  • 2016-09-25 Mamun

    After deleting DefaultController.php, I got 500 Internal server error.

    Here is the message": Oops! An Error Occurred

    The server returned a "500 Internal Server Error".

    Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any inconvenience caused."

    I'm using widows 10, PHP version: 5.6.24, Symfony 3 . As PHP server I'm using XAMPP.

    What could be the reason for this error?

  • 2016-09-19 weaverryan

    Hey Leon!

    Hmmm. I'm sure we can figure this out! A few questions:

    1) Did you run the bin/console server:run to start the built-in web server? Or did you configure a web server to point to your project?
    2) What is the URL in your browser?
    3) Is the 404 error a "pretty" error that's coming from Symfony, or is it much more plain?

    Let me know and we'll find the problem :).


  • 2016-09-16 Leon Hitzer

    I Symfony just install and so far everything runs. I followed your video but unfortunately get in the browser the message: The server returned a "404 Not Found".

  • 2016-09-07 Victor Bocharsky

    +1 It makes sense to clear the cache. Also ensure that the "Power Save Mode" is off: "File" -> uncheck "Power Save Mode".

  • 2016-09-07 PlayIt

    I had the same problem, I did two things, I believe the latter fixed it.
    Uninstalled plugin / restart /reinstalled plugin / restart..
    Still didn't work.
    File -> Invalidate Caches / Restart
    Wait for indices to finish building on restart ( takes a min )

  • 2016-08-25 Victor Bocharsky

    Hm, I think internal server error is not so bad here. I suppose your server configured properly, you just don't clear prod cache. Symfony recompile cache for changed files by itself in dev mode, but in prod mode you should clear it manually each time you make any changes. So try to clear cache for prod with the next Symfony console command:

    $ bin/console clear:cache --env prod

    Or just manually remove "/path-to-your-symfony-app-root-dir/var/prod" folder, it should help you. Let me know if you still has this error after clearing the prod cache.


  • 2016-08-23 Kaiser

    Thanks for quick response. :)

    The root directory is now /web.
    When launching the app.php (which correctly is set as directory index i .htaccess) i get the "500 internal..." error. but app_dev.php works fine (though it has the debug bottom bar).

    If I'm running the application without MAMP, but just starting the server through terminal, i get another 500-error stating "An error occurred while loading the web debug toolbar (500: Internal Server Error)"
    This occurs both through app.php and app_dev.php?

    I am pretty new to all serber & system settings as well as managing bigger projects. I was used to just fire up MAMP, and build the directory structure myself without frameworks. So I am not sure at all how to follow the guide "Configuring a Web server" as in where those settings should be applied etc..

  • 2016-08-23 Victor Bocharsky

    Hey Kaiser,

    Yes, you should set the "/web" directory as a document root for Symfony projects.
    Also make the "web/app.php" as a directory index file. This actually set up in "/web/.htaccess" already, but your server could ignore it, depends on server configuration.

    BTW, the correct example of configuring a virtual host for Symfony project you could find here: Configuring a Web Server. There're few examples for both Apache and Nginx web servers.


  • 2016-08-22 Kaiser

    First of all these tutorials are great! Thank you so much for making them!
    However. I can't seem to get this default routing working.

    I'm on mac El Capitan
    PHPstorm 2016.2
    Symfony 3.1.2

    I've set up MAMP to my projects directory as document root, but when typing localhost:8000 i just get a list of files in th edirectory.
    When typing localhost:8000/web
    or localhost:8000/web/app_dev.php
    it loads the "Welcome to symfony" page.

    Without the defaultController. i get the right result with localhost:8000/web/app_dev.php
    and with localhost:8000/web i get a basic "500 internal server error". ?

  • 2016-08-16 Vlad

    Thank you, Ryan!

  • 2016-08-15 weaverryan

    Yo Vlad!

    There is a proper way to do this - with $this->forward(). But - by design - this creates a sub-request in the system, so there is some performance impact for doing this (you can look in the Performance tab in the Profiler for this page - you'll see exactly what I mean and how much of an impact there is). Otherwise, yes, you could instantiate the controller directly (and call setContainer() on it) - it is just an object, of course. But, there's some risk in this, because certain normal pre-controller hooks won't fire, so you could rely on some functionality there that suddenly doesn't work. The longer, more proper answer is that if you need to call something, you should extract it to a service and call that service.

    But there you go - there's the long answer, because I know you'll find it interesting anyways!


  • 2016-08-12 Vlad

    If I want to call a controller action inside of another controller, is there a proper way of doing it (via routes, etc.), or do I simply instantiate the target controller and call it's function directly?

  • 2016-07-16 Luciano Marinho

    Sorry, the error was mine. I'm new in this symfony world. Learning well with this tutorial. Thanks a lot;

  • 2016-07-16 weaverryan

    Hey Luciano!

    Everything should still work just fine in 3.1.2 - what problems are you having? Do you have a "Route Not Found" error? What URL are you going to?


  • 2016-07-15 Luciano Marinho

    I'm trying this with symfony 3.1.2 but this chapter does not work.....the router not work =(

  • 2016-05-25 weaverryan


  • 2016-05-25 Mike

    I fixed my problem. I am using Sourcetree to push my changes but it is not updating my remote server. I had to us the CLI to pull my changes

  • 2016-05-24 Mike

    I deleted the DefaultController and it still loads the welcome to symfony page. Why is this? Also, when I create the genus route it says no route found. I'm using a remote server instead of my local pc. The symfony project is located in this directory /var/www/html/my_project

  • 2016-05-02 weaverryan

    Cheers! Yes, bin/console cache-clear --env=prod is your friend for the prod environment :)

  • 2016-05-02 Yoni L.

    Thank you for this great tutorial! just to share I had some trouble with an error 500 with /genus route. That was due to the cache in /app/cache/prod.

  • 2016-04-27 Konrad Zając

    Yes, thanks!

  • 2016-04-27 weaverryan

    Hi Konrad!

    I don't understand your question - can you ask it again? Which folder are you talking about? Are you talking about creating an empty project in PHPStorm? If so, I usually create my project with the Symfony installer. Then, in PHP storm, I go to "File -> Open Directory" and choose the directory that was just created. This "makes" a new project in PHPStorm, using that directory. I hope I answered your question :).


  • 2016-04-26 Konrad Zając

    Create an empty project or a PHP empty project and load that folder created with the command line?

  • 2016-04-26 weaverryan

    Hi Josh!

    Yea, unfortunately we use "controller" interchangeably to refer to *both* the class, and the individual methods in the class (sometimes the individual methods are sometimes called "actions"). When I say "controller", I am typically referring to the single method that returns the Response object. When I'm talking about the class, I'll usually say "controller class". I can totally see how that can cross some wires :)


  • 2016-04-26 weaverryan

    I do! Install the "PHP Annotations" plugin for PHPStorm - this gives PHPStorm intelligence about how annotations and use statements work. You'll also start to get awesome auto-complete when you use annotations.


  • 2016-04-25 Emilien Ramos

    I'm sorry but I don't have the @Route completion ...

    I have the others (Response, ...) and the "use Sensio\Bundle\...\Route" message is highlighted with the note : "Usage of statement use was not found"

    Do you know why ?

  • 2016-04-25 Emilien Ramos

    Thanks ! :)

  • 2016-04-25 Josh Hardman

    Hey weaverryan,

    Thanks for your quick response! Your explanation does help. In my experience the controller has referred to the entire class, which has various methods that handles business logic, along with a display function that passes variables on to the template. In Symfony, is the controller simply the single method associated with the matched route which returns a response object? I'm sure this will all make better sense as I keep working through the videos!

  • 2016-04-24 weaverryan

    Hi Josh!

    It's actually the internal a of Symfony that call showAction. Here's what happens:

    1) the user loads the page - Symfony boots up

    2) Synfony reads the routing info (the @Route annotation) to determine which route matches the current URL

    3) Symfony calls the method associated with the matched route (called the controller) so that we can build the page.

    Does that help? It's a good question - understanding this flow is a crucial step!


  • 2016-04-24 Josh Hardman

    What is actually calling showAction()?

  • 2016-04-24 weaverryan

    PHPstorm! With the Darcula theme :). We have some other PHPStorm goodies over here:


  • 2016-04-23 Emilien Ramos

    Please what's your IDE ?

  • 2016-03-23 weaverryan

    Oh no! I have seen in rare cases that it doesn't work for *some* people. I would open a support request with PhpStorm to see if they can help. Make sure you're also using the latest version of PhpStorm - that might not make a difference, but it's worth a try.

  • 2016-03-22 utkarsh srivastava


    I've added php annotations plugin and restarted phpstorm but it still doesnt prompt the autocomplete. Please help me with this.

  • 2016-01-26 weaverryan

    Yea, thanks for pointing this out! There was at least one other user that also commented (on another chapter) - so I've added a note about this: It was an oversight - you *definitely* want this awesome plugin :).


  • 2016-01-24 Levan Lomia

    omg man thank you. I was struggling abaout that too. just read your comment accidentally

  • 2016-01-24 ZB

    Make sure to also install the PHP Annotations plugin to PHP Storm. I was struggling to make that @Route auto-complete work