This tutorial has a new version, check it out!

First Page

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.

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:

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():

... 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":

... 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!':

... 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!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11" // 1.11.99
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0" // v3.1.3