Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Create Service

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.

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.

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

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

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

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

9
Login or Register to join the conversation

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

Reply

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

Reply

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

Reply

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

Reply
Default user avatar
Default user avatar Luka Sikic | posted 4 years ago

Whoops, Looks like there's a bug in the course code. Function getId() is defined twice in the GenusNote entity.

Reply

Hey Luka Sikic

You are totally right! It's declared twice (I guess we just can't get enough id's)

Thanks for letting us know, we will fix it as soon as possible :)

Reply
Default user avatar

Hi there, are there some files missing from this download? /app/autoload references a file in __DIR__.'/../vendor/autoload.php' which doesn't seem to exist, or perhaps I am doing something else? Cheers...

Reply
Victor Avatar Victor | SFCASTS | Dan | posted 4 years ago | edited

Hey Dan,

Yes, you have to install dependencies with Composer before you start:


$ composer install

Also check the README file in dowloaded archive, it contains more instructions how to launch the project. If you don't familiar with Composer - we have a short course about it: http://knpuniversity.com/screencast/composer

Cheers!

Reply
Default user avatar

Easy fix, thanks a heap :)

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

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
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}
userVoice