gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
If you started a brand new Symfony 3.3 project, its services.yml
file will look like this.
You're actually seeing at least four new features all at once! Wow. All of this is built on top of the existing service configuration system and you need to "opt in" to any of the new features. That means that the traditional way of configuring services that you've been using until now still works and always will. Winning!
But even if you ultimately choose not to use some of these new features, you need to understand how they work, because you'll see them a lot. For example, the Symfony documentation has already been updated to assume you're using these.
First, a word of warning: using the new features is fun. But, upgrading an existing project to use them... well... it's less fun. It takes some work, and when you're done... your project works... the same as before. I'm also going to show you the ugliest parts of the new system so you can handle them in your project. But stick with me! At the end, we'll use the new features to build some new code. And that, is a blast.
Let's look at this _defaults
thing first. Open up your app/config/services.yml
file. At the top of the services
section - though order isn't important - add _defaults
. Then below that, autowire: true
and autoconfigure: true
:
... lines 1 - 5 | |
services: | |
_defaults: | |
autowire: true | |
autoconfigure: true | |
... lines 10 - 41 |
Let's unpack this. First, _defaults
is a new special keyword that allows you to set default configuration for all services in this file. It's equivalent to adding autowire
and autoconfigure
keys under every service in this file only. And of course, any config from _defaults
can be overridden by a specific service.
Autowiring is not new: we talk about it in our Symfony series. When a service is autowired, it means that its constructor arguments are automatically configured when possible by reading type-hints. For example, the MarkdownExtension
is autowired:
... lines 1 - 5 | |
services: | |
... lines 7 - 10 | |
app.markdown_extension: | |
class: AppBundle\Twig\MarkdownExtension | |
tags: | |
- { name: twig.extension } | |
#arguments: ['@app.markdown_transformer'] | |
autowire: true | |
... lines 17 - 43 |
And its first constructor argument is type-hinted with MarkdownTransformer
:
... lines 1 - 2 | |
namespace AppBundle\Twig; | |
use AppBundle\Service\MarkdownTransformer; | |
class MarkdownExtension extends \Twig_Extension | |
{ | |
... lines 9 - 10 | |
public function __construct(MarkdownTransformer $markdownTransformer) | |
{ | |
... line 13 | |
} | |
... lines 15 - 33 | |
} |
Thanks to that, Symfony determines which service to pass here.
The way that autowiring works has changed in Symfony 3.3. But more on that later.
Since we have autowire
under _defaults
, we can remove it from everywhere else: it's redundant. And yes, this does mean that some services that were not autowired before are now set to autowire: true
. For example, app.markdown_transformer
is now being autowired:
... lines 1 - 5 | |
services: | |
app.markdown_transformer: | |
class: AppBundle\Service\MarkdownTransformer | |
arguments: ['@markdown.parser', '@doctrine_cache.providers.my_markdown_cache'] | |
... lines 10 - 43 |
But... that's no problem! Both of its arguments are being explicitly set:
... lines 1 - 2 | |
namespace AppBundle\Service; | |
use Doctrine\Common\Cache\Cache; | |
use Knp\Bundle\MarkdownBundle\MarkdownParserInterface; | |
class MarkdownTransformer | |
{ | |
... lines 10 - 12 | |
public function __construct(MarkdownParserInterface $markdownParser, Cache $cache) | |
{ | |
... lines 15 - 16 | |
} | |
... lines 18 - 33 | |
} |
so autowiring simply doesn't do anything. Setting autowire: true
under _defaults
is safe to add to an existing project.
Next, this autoconfigure
key is a brand new feature. When a service is autoconfigured, it means that Symfony will automatically tag it when possible. For example, our MarkdownExtension
extends \Twig_Extension
:
... lines 1 - 6 | |
class MarkdownExtension extends \Twig_Extension | |
{ | |
... lines 9 - 33 | |
} |
Which implements Twig_ExtensionInterface
:
abstract class Twig_Extension implements Twig_ExtensionInterface
{
// ...
}
That's actually the important part. When a service is autoconfigured and its class implements Twig_ExtensionInterface
, the twig.extension
tag is automatically added for you:
... lines 1 - 5 | |
services: | |
... lines 7 - 10 | |
app.markdown_extension: | |
... line 12 | |
tags: | |
- { name: twig.extension } | |
... lines 15 - 43 |
Basically, Symfony is saying:
Hey! I see you configured a service that implements
Twig_ExtensionInterface
. Obviously, that's a Twig extension, so let me configure it for you.
... lines 1 - 5 | |
services: | |
... lines 7 - 14 | |
app.markdown_extension: | |
class: AppBundle\Twig\MarkdownExtension | |
#arguments: ['@app.markdown_transformer'] | |
... lines 18 - 41 |
This works for many - but not all tags. It does not work for doctrine.event_subscriber
or form.type_extension
:
... lines 1 - 5 | |
services: | |
... lines 7 - 21 | |
app.doctrine.hash_password_listener: | |
class: AppBundle\Doctrine\HashPasswordListener | |
tags: | |
- { name: doctrine.event_subscriber } | |
app.form.help_form_extenion: | |
class: AppBundle\Form\TypeExtension\HelpFormExtension | |
tags: | |
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType } | |
... lines 31 - 41 |
Because it has an extended_type
tag option... which the system can't guess for you. When you're developing a feature, the docs will tell you whether or not you need to add the tag manually. If you do add a tag, even though you didn't need to, no problem! Your tag takes precedence.
So, all our services are autowired and autoconfigured! But, it doesn't make any difference, besides shortening our config just a little. And when we refresh, everything still works!
Hey Geoffrey M.
40 services.yaml
files? Can I ask why? In theory you only have one but it's pretty common to have one for prod, one for dev and one for testing
Hey MolloKhan
Because my app got around 40 differents bundles and each bundle has its own services declared in their own Resources/config/services.yml.
Ohh, I get it now. Then, no, I think you should start heading towards to a non-bundle structure, this will be helpful if you ever decide to upgrade to Symfony4. If that's not your case, then you can have a main services.yaml file in your "app/config" directory and in there set those keys for autowiring and autoconfigure. Or, if you are going to keep adding new bundles into the project, then you can add those keys to the new services.yaml files.
Cheers!
Ok, thanks ! Do you have any tips / hints on how to migrate from a bundle structure to a non-bundle structure when you have around 40 bundles living in ./src ?
Don't worry Geoffrey, we have your back covered with a full course of how to upgrade from Symfony3 to 4
Check it out: https://symfonycasts.com/sc...
Hello Ryan, i see two new services in the services.yml file :
app.encouraging_message_generator:
class: AppBundle\Service\MessageGenerator
arguments:
- ['You can do it!', 'Dude, sweet!', 'Woot!']
app.discouraging_message_generator:
class: AppBundle\Service\MessageGenerator
arguments:
- ['We are *never* going to figure this out', 'Why even try again?', 'Facepalm']
But i don't find the course where we are created them.
Can you help me ?
Thanks :)
Hey abdouniabdelkarim
Those services already came with the course code, but don't worry too much about them, they exist purely to demonstrate a couple of examples in the further episodes
Cheers!
// 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
}
}
Hi !
I have like 40 differents services.yml in my app.
Shall I add these keys in all this 40 files ?