Buy

Hey, hey, friends! Back for more!? You should be feeling pretty good about yourself already - but you're about to feel like a kid in a very nerdy, borderline embarrassing candy store. In this course, we fully uncover services: those little useful objects that literally do everything in Symfony.

Now as always, you should code along with me - otherwise we'll find out and it's kinda company policy to mail you a big package full of glitter. But if you code along - and we meet in person, well, there's a cookie with your name on it.

So find the "Download" button on any of the tutorial pages, download the code, unzip it and move into the start directory. As always, I already have the start directory code here, so I'll skip to the last step: open up a new terminal and launch the built-in PHP web server with:

php bin/console server:run

In your case, open up the README.md file in the start directory - it has a few extra instructions.

Services: Doers of Good

In the last courses, if I repeated anything too many times, it was this: Refresh! But second would be that Symfony is basically just a big container of useful objects called services... and everything that happens is actually done by one of these.

125 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 13
class GenusController extends Controller
{
... lines 16 - 43
public function listAction()
{
... lines 46 - 50
return $this->render('genus/list.html.twig', [
'genuses' => $genuses
]);
}
... lines 55 - 123
}

For example, the render() function - it's the key to rendering templates, right? No - it's a fraud! Open up Symfony's base Controller:

398 lines vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php
... lines 1 - 38
abstract class Controller implements ContainerAwareInterface
{
... lines 41 - 185
protected function render($view, array $parameters = array(), Response $response = null)
{
if ($this->container->has('templating')) {
return $this->container->get('templating')->renderResponse($view, $parameters, $response);
}
if (!$this->container->has('twig')) {
throw new \LogicException('You can not use the "render" method if the Templating Component or the Twig Bundle are not available.');
}
if (null === $response) {
$response = new Response();
}
$response->setContent($this->container->get('twig')->render($view, $parameters));
return $response;
}
... lines 204 - 396
}

it doesn't do any work: it just finds the templating service and tells it to do all the work. Ah, management.

This means that Symfony doesn't render templates: The templating service renders templates. To get a big list of birthday wishes, I mean services, run:

./bin/console debug:container

That's a lot of firepower at our fingertips.

We also found out that we can control these services in app/config/config.yml:

72 lines app/config/config.yml
... lines 1 - 36
# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
number_format:
thousands_separator: ','
... lines 43 - 72

New Goal: Service Architecture

But now we have a new, daring goal: adding our own services to the container. It turns out, learning to do this will unlock almost everything else in Symfony.

Open up GenusController and look at showAction():

125 lines src/AppBundle/Controller/GenusController.php
... lines 1 - 13
class GenusController extends Controller
{
... lines 16 - 58
public function showAction($genusName)
{
... lines 61 - 72
// todo - add the caching back later
/*
$cache = $this->get('doctrine_cache.providers.my_markdown_cache');
$key = md5($funFact);
if ($cache->contains($key)) {
$funFact = $cache->fetch($key);
} else {
sleep(1); // fake how slow this could be
$funFact = $this->get('markdown.parser')
->transform($funFact);
$cache->save($key, $funFact);
}
*/
... lines 86 - 97
}
... lines 99 - 123
}

We used to have about 15 lines of code that parsed the $funFact through Markdown and then cached it. I want that back. But, but but! I don't want to have these 15 lines of code live here, in my controller.

Why not? Three reasons:

  1. I can't re-use this. If I need to do parse some markdown somewhere else... well, I could copy-and-paste? But then, how would I sleep at night?

  2. It's not instantly clear what these 15 lines do: I have to actually take time and read them to find out. If you have a lot of chunks like this, suddenly nobody knows what's going on in your app. You know what I'm talking about?

  3. If you want to unit test this code... well, you can't. To unit test something, it needs to live in its own, isolated, focused class.

Well hey, that's a great idea - let's move this outside of our controller and solve all three problems at once... plus impress our developer friends with our sweet code organizational skills.

Leave a comment!

  • 2016-11-23 Victor Bocharsky

    I think so! Delicious cookies shipping works badly - they are constantly eaten along the way :)

  • 2016-11-22 somecallmetim27

    So if I come to Grand Rapids, MI, you'll give me cookies?

  • 2016-11-21 weaverryan

    somecallmetim27 Come visit us in Grand Rapids, MI - we promise free cookies! ;)

  • 2016-11-19 somecallmetim27

    Ok, seriously, I want my cookie. I'm a cookie fiend. You can't tease me like that and then not deliver. :P