This tutorial has a new version, check it out!

Intro to Services

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.

Ok! The first half of Symfony: route-controller-response is in the books!

The second half is all about useful objects. Obviously, returning a string response like this is not going to take us very far. Our aquanauts demand more! In real life, we might need to render a template, query a database, or even turn objects into JSON for an API!

Symfony comes with many, optional, useful objects to help out with stuff like this. For example, want to send an email? Symfony has an object for that. How about log something? There's an object for that.

These objects are commonly called services, and that's important: when you hear the word service, just think "useful object".

Service Container

To keep track of all of these services, Symfony puts them into one big associative array called the container. Each object has a key - like mailer or logger. And to be more honest with you - sorry, I do like to lie temporarily - the container is actually an object. But think of it like an array: each useful object has an associated key. If I give you the container, you can ask for the logger service and it'll give you that object.

The second half of Symfony is all about finding out what objects are available and how to use them. Heck, we'll even add our own service objects to the container before too long. That's when things get really cool.

Accessing the Container

The first useful object is the templating service: it renders Twig templates. To get access to the service container, you need to extend Symfony's base controller.

Go Deeper!

Why does extending Controller give you access to the container? Find out: Injecting the Container: ContainerAwareInterface (advanced).

In GenusController, add extends Controller from FrameworkBundle. Hit tab to autocomplete and get the use statement:

... lines 1 - 5
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
... lines 7 - 8
class GenusController extends Controller
{
... lines 11 - 22
}

To get the templating service, add $templating = $this->container->get('templating'):

... lines 1 - 8
class GenusController extends Controller
{
... lines 11 - 13
public function showAction($genusName)
{
$templating = $this->container->get('templating');
... lines 17 - 21
}
}

The container pretty much only has one method: get. Give it the nickname to the service and it will return that object. It's super simple.

Quickly, open the var directory, right click on the cache directory and click "mark this directory as excluded". Symfony caches things... that's not important yet, but excluding this is important: this directory confuses autocompletion.

Now type $this->container->get('templating'). Well hey autocompletion!

Rendering a Template

With the templating object we can... well... render a template! Add $html = $templating->render('') followed by the name of the template. This could be anything, but let's be logical: genus/show.html.twig. I'll show you where this lives in a second:

... lines 1 - 8
class GenusController extends Controller
{
... lines 11 - 13
public function showAction($genusName)
{
$templating = $this->container->get('templating');
$html = $templating->render('genus/show.html.twig', array(
'name' => $genusName
));
... lines 20 - 21
}
}

We'll also want to pass some variables into the template. Pass a name variable into Twig that's set to $genusName.

Finally, what do we always do in Symfony controllers? We always return a Symfony's Response object. Stick, that $html into the response object and return it:

... lines 1 - 8
class GenusController extends Controller
{
... lines 11 - 13
public function showAction($genusName)
{
... lines 16 - 20
return new Response($html);
}
}

Go Deeper!

You can actually return anything from a controller via the kernel.view event: The kernel.view Event (advanced)

Create the Template

Ok, where do templates live? Ah, it's so simple: templates live in app/Resources/views. The one we're looking for will be in app/Resources/views/genus/show.html.twig. The existing index.html.twig template was for the original homepage. Check it out if you want to, then delete it!

Create a new genus directory and then a new file: show.html.twig. Welcome to Twig! You'll love it. Add an <h1> tag with The Genus and then {{ name }} to print the name variable. More on Twig in a second:

<h1>The Genus {{ name }}</h1>

But that's it! Refresh the browser. Check out that sweet h1 tag.

Now back up: we just did something really cool: used our first service. We now know that rendering a template isn't done by some deep, dark part of Symfony: it's done by the templating object. In fact, Symfony doesn't really do anything: everything is done by one of these services.

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
    }
}