Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Making all Services Private

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.

There is one more key that lives under _defaults in a new Symfony 3.3 project: public: false:

... lines 1 - 8
services:
_defaults:
... lines 11 - 12
public: false
... lines 14 - 42

The idea of public versus private services is not new in Symfony 3.3... but defaulting all services to private is new, and it's a critical change. Thanks to this, every service in this file is now private. What does that mean? One simple thing: when a service is private, you cannot fetch it directly from the container via $container->get(). So, for example, $container->get('AppBundle\Service\MarkdownTransformer') will not work.

Tip

In Symfony 3.3, sometimes you can fetch a private service directly from the container. But doing this has been deprecated and will be removed in Symfony 4.

But, everything else works the same: I can pass this service as an argument and it can be autowired into an argument. Only the $container->get() usage changed.

In our app, making this change is safe! We just created all of these service ids a minute ago and they're not being used anywhere yet, definitely not with $container->get(). The exception is the last two services: we might be fetching these services directly from the container. And in fact, I know we are: in src/AppBundle/Controller/Admin/GenusAdminController.php. Down in editAction(), we're fetching both services via $this->get(), which is a shortcut for $this->container->get():

... lines 1 - 15
class GenusAdminController extends Controller
{
... lines 18 - 63
public function editAction(Request $request, Genus $genus)
{
... lines 66 - 69
if ($form->isSubmitted() && $form->isValid()) {
... lines 71 - 76
$this->addFlash(
'success',
$this->get('app.encouraging_message_generator')->getMessage()
);
... lines 81 - 84
} elseif ($form->isSubmitted()) {
$this->addFlash(
'error',
$this->get('app.discouraging_message_generator')->getMessage()
);
}
... lines 91 - 94
}
}

That means, for now, to keep our app working, add public: true under each service:

... lines 1 - 8
services:
... lines 10 - 30
app.encouraging_message_generator:
... lines 32 - 34
public: true
... line 36
app.discouraging_message_generator:
... lines 38 - 40
public: true

Aliases can also be private... but in legacy_aliases.yml, there is no _defaults key with public: false. So, these are all public aliases... which is exactly what we want, ya know, because we're trying not to break our app!

Like with every step so far, our app should still work fine. Woohoo! But... you may be wondering why we made the services private. Doesn't this just make our services harder to use? As we'll learn soon, when you use private services, it becomes impossible to make a mistake and accidentally reference a non-existent service. Private services are going to make our app even more dependable than before. And also, a little bit faster.

Next, let's talk about the biggest change to this file: auto-registration of all classes in src/AppBundle as services. Woh.

Leave a comment!

4
Login or Register to join the conversation
Default user avatar

Hi, from what vodeo comes app.enouraging_message_generator in services.yml & GenusAdminController, tell please.

Reply

Hey @Andrey!

This tutorial is built on top of the course that we built during the Symfony 3 series: https://symfonycasts.com/tr.... You can download the course code from this page - we mention a few of these details during the first video - https://symfonycasts.com/sc...

Cheers!

Reply
Mike P. Avatar
Mike P. Avatar Mike P. | posted 5 years ago

Well one more service is used via the container: $transformer = $this->get('AppBundle\Service\MarkdownTransformer');
in the new genusController showAction(). So this has to be public as well.

Reply

Yo Mike P.!

Actually, at this exact moment in the tutorial, we're still using $this->get('app.markdown_transformer'), which in legacy_aliases.yml (and those aliases are public). We do change to use the private, class id later - https://knpuniversity.com/screencast/symfony-3.3/controller-di-cleanup#private-services-and-container-gt-get - and we see an error and refactor to a controller argument.

But yea, you're right - you can't fetch a private service from the container. But instead of making it public, in that later chapter, we use special controller argument dependency injection!

Cheers!

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.3.0-RC1", // v3.3.0-RC1
        "doctrine/orm": "^2.5", // 2.7.5
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.7
        "symfony/monolog-bundle": "^3.1", // v3.2.0
        "symfony/polyfill-apcu": "^1.0", // v1.23.0
        "sensio/distribution-bundle": "^5.0", // v5.0.25
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.4
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "knplabs/knp-markdown-bundle": "^1.4", // 1.7.1
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "stof/doctrine-extensions-bundle": "^1.2" // v1.3.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.7
        "symfony/phpunit-bridge": "^3.0", // v3.4.47
        "nelmio/alice": "^2.1", // v2.3.6
        "doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
    }
}
userVoice