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

Autowiring Aliases

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

The way we coded in Symfony 3 was a bit different than Symfony 4. And... well... we need to learn just a little bit about the Symfony 3 way. Why? Because, when you find bundles with outdated docs, or old StackOverflow answers, I want you to be able to translate that into Symfony 4.

Public Versus Private Services

In Symfony 3, services were defined as public. This means that you could use a $this->get() shortcut method in your controller to fetch a service by its id. Or, if you had the container object itself - yep, that's totally possible - you could say $container->get() to do the same thing.

But in Symfony 4, most services are private. What does that mean? Very simply, when a service is private, you cannot use the $this->get() shortcut to fetch it.

At first, it might seem like we're just making life more difficult! But actually, Symfony 4 simply has a new philosophy.

Tip

You may not see the public: false defined anymore because that’s the default value starting in Symfony 4.

Open services.yaml and, below _defaults, check out the public: false config:

... lines 1 - 5
services:
# default configuration for services in *this* file
_defaults:
... lines 9 - 10
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
... lines 14 - 34

Thanks to this, any service that we create is private. And so, we cannot fetch our services with $this->get(). Increasingly, more and more third-party bundles are also making their services private.

And because so many services are now private, instead of using $this->get(), we need to fetch services via "dependency injection" - a fancy, scary-sounding term that describes what we've been doing... this entire tutorial: passing services and config as arguments. This is considered a better coding practice than $this->get(), which means that we get to write nice code. Woo!

And actually... it also makes your app faster! It's not huge, but private services are faster than public services.

If you DO Want to use $this->get()

Side note, if you do want to use the $this->get() shortcut to fetch a public service - which you should not - you'll need to change your base controller class to Controller instead of AbstractController:

... lines 1 - 7
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
... lines 9 - 12
class ArticleController extends AbstractController
{
... lines 15 - 83
}

It's not important why... and you shouldn't do it anyways :p.

Fetching a Service by id

Okay okay, so if we can't use the $this->get() shortcut, how the heck can we fetch this service? Let's experiment! Copy the service id, find your terminal, and run:

php bin/console debug:container nexy_slack.client

Apparently the class for this object is Nexy\Slack\Client. We didn't see any autowiring type-hints that would work in debug:autowiring... but... maybe it will work if we type-hint this class?

Let's try it! In ArticleController::show(), add another argument: Client - make sure you get the one from Nexy\Slack - then $slack:

... lines 1 - 5
use Nexy\Slack\Client;
... lines 7 - 13
class ArticleController extends AbstractController
{
... lines 16 - 36
public function show($slug, MarkdownHelper $markdownHelper, Client $slack)
{
... lines 39 - 79
}
... lines 81 - 92
}

Add an if statement: if $slug === 'khaaaaaan':

... lines 1 - 5
use Nexy\Slack\Client;
... lines 7 - 13
class ArticleController extends AbstractController
{
... lines 16 - 36
public function show($slug, MarkdownHelper $markdownHelper, Client $slack)
{
if ($slug === 'khaaaaaan') {
... lines 40 - 44
}
... lines 46 - 79
}
... lines 81 - 92
}

Then we need to know about this! Go copy some code from the docs. Then, simplify a bit - we don't need the attachment stuff, this is coming from Khan and the text should be "Ah, Kirk, my old friend.":

... lines 1 - 5
use Nexy\Slack\Client;
... lines 7 - 13
class ArticleController extends AbstractController
{
... lines 16 - 36
public function show($slug, MarkdownHelper $markdownHelper, Client $slack)
{
if ($slug === 'khaaaaaan') {
$message = $slack->createMessage()
->from('Khan')
->withIcon(':ghost:')
->setText('Ah, Kirk, my old friend...');
$slack->sendMessage($message);
}
... lines 46 - 79
}
... lines 81 - 92
}

Excellent! Copy the slug. Then go to that page in your browser. And... it totally did not work: the $slack argument is missing.

Well... I guess debug:autowiring doesn't lie. Copy the $slack argument to the constructor:

... lines 1 - 5
use Nexy\Slack\Client;
... lines 7 - 13
class ArticleController extends AbstractController
{
... lines 16 - 20
public function __construct(bool $isDebug, Client $slack)
{
... line 23
}
... lines 25 - 92
}

No, it won't work here either... but we will get a better error message. Actually, this is due to another shortcoming with controller autowiring: when it fails, the error isn't great. That will hopefully also be improved in the future. Again, a few of these features are still brand new!

Refresh! Ah, much better:

Cannot autowire service ArticleController: argument $slack of method __construct() references class Nexy\Slack\Client, but no such service exists.

This basically means that we're missing configuration to tell the container which services to pass for this type-hint. So... are we dead? No way! We are in total control of autowiring.

Open services.yaml, then go copy the full class name for the client: Nexy\Slack\Client. Back under bind, instead of using the argument name, like $slack, put the class name: Nexy\Slack\Client. Set this to the target service id: @nexy_slack.client:

... lines 1 - 5
services:
# default configuration for services in *this* file
_defaults:
... lines 9 - 14
# setup special, global autowiring rules
bind:
... lines 17 - 18
Nexy\Slack\Client: '@nexy_slack.client'
... lines 20 - 35

That's it! Bind has two super-powers: you can bind by the argument name or you can bind by a class or interface. We're defining our own rules for autowiring!

Tip

You should comment this line out with nexylan/slack-bundle >=2.2.0 to avoid circular reference, as this alias is already added by the bundle

Let's make sure I'm not lying: refresh! Yes! There's our Slack notification.

Autowiring Aliases

But I want to make just one small tweak. In services.yaml, instead of putting this beneath _defaults and bind, let's un-indent it so that it's at the root of services:

... lines 1 - 5
services:
... lines 7 - 19
# custom aliases for autowiring
Nexy\Slack\Client: '@nexy_slack.client'
... lines 22 - 37

Refresh again. It works exactly like before!

The difference is subtle. Config beneath _defaults only affects services that are added in this file. But when you put this same config directly under services, it will affect all services in the system. In practice... that makes no difference: only our code uses autowiring: third-party libraries do not using autowiring, to keep things predicatable.

The biggest reason I did this is that, when you run debug:autowiring:

php bin/console debug:autowiring

and search for "Slack", there it is! When it's under bind, it won't show up here.

About Autowiring Logic

But... this trick also shows us a bit more about how autowiring works. By putting this config directly under services, we're creating a new service in the container with the id Nexy\Slack\Client. But this is not a real service, it's just an "alias" - a "shortcut" - to fetch the existing nexy_slack.client service.

Here's the important question: when an argument to a service hasn't been configured under bind or arguments, how does the autowiring figure out which service to pass? The answer is super simple: it just looks for a service whose id exactly matches the type-hint. Yep, now that there is a service whose id is Nexy\Slack\Client, we can use that class as a type-hint. That's also why our classes - like MarkdownHelper can be autowired: each class in src/ is auto-registered as a service and given an id that matches the class name.

Ok, it's time to turn to something different, but very important in Symfony 4: environment variables. This will help us to not hardcode our secret Slack URL inside our code.

Leave a comment!

71
Login or Register to join the conversation
B1 Avatar

So, regarding the public: false config in services.yaml, it's not there anymore in Symfony 4.2.2.

I guess it was removed probably because false is the default value for _defaults now, and not being there does not encourage the bad idea of changing it to true. I tried to look up something about this, and found the Service Container documentation for Symfony 4.2 to be outdated as it clearly shows public:false in the services.yaml example (in Automatic Service Loading in services.yaml section). ;)

2 Reply
weaverryan Avatar weaverryan | SFCASTS | B1 | posted 4 years ago | edited

Hey B1!

Yes, you're 100% correct that starting in Symfony 4.0 (actually), all services default to public: false. For a while, we still shipped that public: false part there, even though it wasn't needed, but starting in Symfony 4.2, we removed it. Unfortunately, sometimes when a little tweak like this is made to the recipe, the docs aren't always updated perfectly - it's something we're working on actually :).

Thanks for pinging us on this - I think we may add a note so others aren't confused!

Cheers!

Reply
odds Avatar

I'm guessing the real programmers know where to find this information (somewhere on Github), but not me. Where can I find that? It took me a while before I admitted defeat and found this post...

Reply

Hey odds

Can you tell me specifically what documentation are you tring to find?

Reply
odds Avatar

Hi Diego,

I was thinking about the Git-repo where the file lives and I could find some mentioning in git log. But, I'm just a hobbyist programmer, so just winging it...

Reply

Ah, I get it. This is the main Symfony repository: https://github.com/symfony/...
In there you can find all components and bundles (but not third party bundles)

Reply
Johan K. Avatar
Johan K. Avatar Johan K. | posted 2 years ago | edited

nexy_slack has been updated and now supports autowiring, so when you un-indent it as at 6:18 you get a ServiceCircularReferenceException

Actually, it doesn't need the

Nexy\Slack\Client: '@nexy_slack.client' config at all anymore

1 Reply

Hey there,

Yes, you're 100% right, that was an old problem and it's now fixed. Thanks for sharing it

Cheers!

Reply
Richard Avatar
Richard Avatar Richard | posted 3 years ago

Just a quick note for those tha t run into issues using the suggestion of installing 1.1.1 or 1.1.2 and so forth : there's a good chance the namespace is then "Maknz" and not Nexy. Quite a confusing intimidating lesson this one ;)

1 Reply

Hey Maxii123,

Thanks for this tip! Yep, it's easy to mess up namespaces, expecially if class name is the same. Keep eyes close to the namespaces you're autocompleting in PhpStorm :)

Cheers!

Reply
Tom Avatar

So why didn't we have to do any configuration for the KnpMarkdownBundle?

1 Reply

That's because Symfony4 uses Symfony Flex which leverage the "recipes" system. Ff a bundle has a recipe you will get a pretty default configuration automatically, plus, if the bundle is well designed, it will give you public services ready to use.

Reply

Is there any way to use third-party libraries with autowiring? Example: I download a library that sends messages to telegram and I want to receive it automatically in my controller, is this possible? when I say third-party libraries I'm referring to any library available in packagist

Reply

Hey RenatoAugustoFS

It depends on library if package/bundle provides public auto wireable service then you can just use it, but in most cases I think it won't be so, and you will need additional configuration to instantiate wireable services in your services.yaml, or create some internal factory that will use package class you need.

Cheers!

Reply

Hey there, I ran into some trouble I didn't see mentioned before here

Everything works fine until I add a use statement for Nexy\Slack\Client and autowire it. Then when I try to load any page of our app I get the following error:

No PSR-17 request factory found. Install a package from this list: https://packagist.org/providers/psr/http-factory-implementation<br />

I tried installing one of the packages from the list but that didn't help. I don't know what I'm doing wrong exactly

Reply

Yea... the newer versions of next/slack are much different to install... and confuse me. We added some notes to the video + script to guarantee that you install the older version to avoid all this. I talk about the newer version a bit here - https://symfonycasts.com/sc... - but (at least at this moment) the underlying way that this all works is almost more trouble than it's worth :).

Cheers!

Reply
Robertas Å . Avatar
Robertas Å . Avatar Robertas Å . | posted 3 years ago

At symfony 4.4.*. After making last edit for service.yaml, localhost:8000 gives me this error:

Circular reference detected for service "nexy_slack.client", path: "nexy_slack.client -> Nexy\Slack\Client -> nexy_slack.client".

Also I think it might do something with that [NOTE] I got before:

C:\the_spacebar>php bin/console debug:container nexy_slack.client

// This service is a public alias for the service Nexy\Slack\Client

Information for Service "Nexy\Slack\Client"
===========================================

---------------- -------------------
Option Value
---------------- -------------------
Service ID Nexy\Slack\Client
Class Nexy\Slack\Client
Tags -
Public yes
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired no
Autoconfigured no
---------------- -------------------


! [NOTE] The "nexy_slack.client" service or alias has been removed or inlined when the container was compiled.
Reply

Hey Robertas Å .!

I know this error :). Basically, you no longer need to add the autowiring alias to services.yaml because a newer version of the bundle does this for you :). The reason you get this error is that the bundle originally did this incorrectly, which caused the problem. Newer versions of the bundle have it fixed. So basically, remove the autowiring alias from services.yaml. The lesson we're teaching is still valid (this is how autowiring works), but that specific thing is not needed anymore which is great!

Cheers!

Reply
Robertas Å . Avatar
Robertas Å . Avatar Robertas Å . | weaverryan | posted 3 years ago

Great news! Thank you.

Reply

In Symfony 4.4, I did not have to bind the service in services.yaml. It worked straight out-of-the-box for the slack message

Reply

Hey jpfortuno!

You're 100% right. That's because the bundle has since "fixed" the problem - they are creating the *exact* same alias that we are creating inside the bundle itself (so our alias isn't needed anymore).

Cheers!

1 Reply
Karin W. Avatar
Karin W. Avatar Karin W. | posted 3 years ago | edited

I've had the cURL error 60 as well. I chose to go for the quick and dirty workaround of disabling the certificate verification. <i><b>Which is not recommended because it's not safe.</b></i>
But if anyone else just wants a really quick fix do this:

open the config\packages\httplug.yaml file and add factory and config/verify settings under app:


httplug:
    clients:
        app:
            factory: 'httplug.factory.guzzle6'
            config:
                verify: false

<i>EDIT: Why the hell is there no indentation in this post?!?
I placed . for indentations now...</i>

Reply

Hey Karin W.!

Thanks for sharing the work-around in case you get the SSL issue when talking to the Slack API :). I also fixed your indentation - Disqus is *terrible* for writing source code - the button in the editor doesn't give you everything you need - lame!

Cheers!

Reply

Hi fellas,
I'm a bit confused on how I can autowire my aliases:

Let's say I have a service at App\Service\TestService. This is by default autowirable to a controller's method argument as it should. It is also appearing as expected in the debug:autowiring section.

Then I want to create an alias for that (just to understand autowiring a bit better). So I proceed to the services.yaml and I add the following:
-------------------------------------------
app.tester:
alias: App\Service\TestService

App\MyService\Test: '@app.tester'
-------------------------------------------

debug:autowiring now seems OK ->
App\MyService\Test alias for "App\Service\TestService"

But when I try to typehint an argument with "App\MyService\Test" I get the error: "The argument is type-hinted with the non-existent class or interface: 'App\MyService\Test'.

Anything obvious I might be missing?
Thanks

Reply

Hey christosp

Yeah, I got you, it's a confusing topic. Since your classes are being automatically registered, then you only have to set up an alias without registering the class again. E.G.


// services.yaml
services:
    app.tester: '@App\MyService\Test' # Register the service "app.tester" as an alias of service "App\MyService\Test"

I hope it makes any sense to you :)
Cheers!

Reply

Hi MolloKhan and thanks for the reply.

Actually... I'm still a bit puzzled. My example is trying to make an alias to my existing class App\Service\TestService to an alias of a different class name App\MyService\Test (yeah, sorry about the slightly confusing - similar names) and then use the latter as a type hint.

Only reason that I tied to do this is by noticing that this exists already in some of the classes - for example
Knp\Bundle\MarkdownBundle\MarkdownParserInterface alias for "markdown.parser.light"
and
markdown.parser.light Knp\Bundle\MarkdownBundle\Parser\Preset\Light

So essentially, using the first one as type-hint results in the second one to be created.

Have I described it better?

Many thanks!

Reply

Nvm, I think I might have figured this out...
In my case, I was trying to create an alias to a non-existing class. debug:container was not complaining about that and it was displaying the mapping ok, but when I was trying to type-hint the non existing class I was getting the error defined above (The argument is type-hinted with the non-existent class or interface: 'App\MyService\Test').

Then I realized that usually the bundles devs create aliases to the interfaces so they can use the Interfaces instead of the actual classes easier (that's the example above with the MarkdownParserInterface aliasing to markdown.parser.light and then finally resolving to Knp\Bundle\MarkdownBundle\Parser\Preset\Light). I guess it makes configuration and decoupling easier that way.

Only thing that I still might not get is the "circular" definition of some aliases/services. For example:
Symfony\Component\Filesystem\Filesystem alias for "filesystem"
and later
filesystem Symfony\Component\Filesystem\Filesystem

Why it is displaying two times in the debug:container? I noticed it doesn't happen that way with other services, i.e.` assets.url_package

`

Once again, thanks a ton!

Reply

Hey christosp!

You are explaining things perfectly :). So I think you totally get it! Indeed, the way that 3rd party bundles do their aliasing is pretty cool - making the interfaces autowireable, and sometimes leveraging aliases to power their config system. For example, with KnpMarkdownBundle, based on your config, the MarkdownParserInterface alias might change from pointing to markdown.parser.light to some other service. That basically allows you to autowire MarkdownParserInterface everyone... and then change which "parser" you want via config... and everything will start using that.

About your last question: the first "alias for filesystem" is indeed saying that Symfony\...\Filesystem is an alias to the filesystem service. The second entry is actually saying that the filesystem service is an instance of the Filesystem class. It's basically say: "Hey! When you ask for the filesystem service, I will do a new Filesystem() to instantiate that. So that isn't an alias, but just the description of that service :).

Cheers!

Reply
Dmitriy Avatar
Dmitriy Avatar Dmitriy | posted 3 years ago

I have service:

App\Service\Converter:
alias: converter

converter:
autowire: false
class: App\Service\Converter

Why, although the parameter for this service autowire: false, when I run

bin/console debug:autowiring

it return:

Autowirable Types
=================
The following classes & interfaces can be used as type-hints when autowiring:
App\Service\Converter (converter)

I set parameter autowire for this service as "autowire: false".

Reply

Hey man!

If you disable the autowiring functionality on a service what it means is that that service's arguments won't be, well, autowired, you will have to specify all of its arguments. But, other classes that depends on such service will be able to be autowired with that service. Does it makes any sense to you?
Also, why you don't want it to be autowired?

Cheers!

1 Reply
Dmitriy Avatar

Thank, Diego. I think I figured it out.

1 Reply
Richard Avatar

Like me, the probably tried to turn off autowire so that the config steps outlined in this video for slack work with 4.+. Please see my Q regarding this ;)

Reply
Wagnner L. Avatar
Wagnner L. Avatar Wagnner L. | posted 3 years ago

Here I just added the use Nexy\Slack\Client and changed the $slack variable to our $client variable, and the message was sent perfecty! (on 4.3), also tested to add the Client in services.yaml, but this caused an circular reference error. At the end, my debug:autowiring use the class Nexy\Slack\Client directly, without alias, this is normal or the alias must be there anyway?
Thanks in advance,
Wagnner

Reply

Hey Wagnner L.

The SlackBundle just added support for the autowiring. Give it a check to this commit: https://github.com/nexylan/...
So, you don't need to set up the autowiring yourself as Ryan did on the video anymore :)

Cheers!

2 Reply
Richard Avatar

I had a similar "ciricular reference" problem when moving the Nexy/Slack/Client services bind to the top level so I thought I would try to "unwire" it and do it manually. No joy whatsoever. It's a bit of a problem with all the auto magic stiff. It seems so "obvious" when it works but soon becomes painful when it doesn't. So lets say I want to follow the vid by NOT have it autowired so the steps in the video work, I kind of thought this might work. Hopefully my intent is clear. Would you mind putting me right please ; )

top level in services.yaml:

Nexy\Slack\Client:
autowire: false
tags: ['nexy_slack.client']

App\Controller\ArticleController:
bind:
$slack: 'Nexy\Slack\Client'

error:

Too few arguments to function Nexy\Slack\Client::__construct(), 0 passed in /home/rgr/Dropbox/homefiles/development/Symfony/knp/02-Symfony4-Fundamentals/the_spacebar/var/cache/dev/ContainerAeZilLk/getArticleControllerService.php on line 15 and at least 1 expected

1 Reply
Richard Avatar
Richard Avatar Richard | Richard | posted 3 years ago | edited

answering my own Q, this seemed to fixit: in services.yaml

` Nexy\Slack\Client:

  autowire: false
  arguments: ["%nexy_endpoint%"]

`

Does that seem reasonable? it really is a suck it and see thing when things are done outside of the script.

Reply

Hey Richard

Sorry for the super late reply (Somehow I lost track of this thread)

What you did looks OK but the autowire: false is not needed. What you need to do is to define the arguments that cannot be autowired, for example any string arguments

I hope it helps. Cheers!

Reply

Hi there,

When I tried to acces the page http://localhost:8000/news/khaaaaaan I get the following error: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl... , see screenshot: https://monosnap.com/file/f...
I've installed the following versions: "nexylan/slack-bundle": "^2.2", "php-http/guzzle6-adapter": "1.1.1".
I also tried to follow the tips from this page, but without success: https://stackoverflow.com/q...

How can I manage it?

Best regards,
Mike

Reply

Hey Bee!

Ah, bummer! Thanks for the screenshot - that's very helpful :). It's definitely a system setup issue related to SSL. So, unfortunately, the solution will be dependent on your operating system. What operating system are you using?

Cheers!

Reply

Hey weaverryan!

Thanks for your answer!

I'm using windows 10 home edition.

Cheers!

Reply

Hey Bee!

Ah, I was afraid of that! Just because fixing & installing things is often a bit more difficult on Windows :/. I'm not sure what the fix is... and it even depends on how you've installed PHP :/. If you're not using it already, you could try Mamp - I'm not sure if it would fix the issue, but certificate support is a pretty fundamental thing for a PHP installation to give you, so I would be surprised if quality php distributions like that don't offer it.

Sorry I can't help more!

Cheers!

Reply

I've tried on a Wamp server.

Also I'm using 7.3.5 PHP verison.

Anyway, thanks for your effort!

Cheers!

Reply
MolloKhan Avatar MolloKhan | SFCASTS | Bee | posted 3 years ago | edited

Hey Bee

I feel you, Windows is just so painful to work with but have you tried Windows 10 WSL (Windows Subsystem Linux)? It's quite nice if you are familiar with Linux

Cheers!

Reply

Hey

Thanks for your suggestion!

I have managed to solve this problem. I've added a wrong "cacert.pem" path, I changed it and now all seems to be alright!

Cheers!

1 Reply
Ryan S. Avatar
Ryan S. Avatar Ryan S. | posted 4 years ago

I think my nexy_slack isn't being included properly. When you got that error installing the composer command it still worked but when i get it the last line of that error is: Installation failed, reverting ./composer.json to its original content.

So I feel like nexy_slack isn't getting pulled into the project(i don't get the auto complete for Client, it doesn't show the slack option.

EDIT: Long story short, it still worked eventually when I followed the rest I just had to manually put in the use statement at the top of the controller.

Reply

Hey Ryan S. ,

I'm glad you were able to solve this issue by yourself, and thanks for sharing your solution with others

Cheers!

Reply

I had a problem when updating the project. Composer uninstalled the nexy slack bundle and installed the nexy slack library. I had some message similar to

There is no extension able to load the configuration for "nexy_slack.

I had to remove the slack library manually and reinstall the slack bundle properly. If that could help anyone.

Reply
Ryan S. Avatar

I even manually added use Nexy\Slack\Client to the top of the file

Reply
Mykhailo B. Avatar
Mykhailo B. Avatar Mykhailo B. | posted 4 years ago

Hello, I have a little problem here. I created my own slack, added a webhook, added it to endpoint in nexy_slack.yaml, and after that added Nexy bind, imports, and params to show function, yet I run into "curl error 60 : The remote server's SSL certificate or SSH md5 fingerprint was deemed not OK." when i load the page

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.4
        "symfony/asset": "^4.0", // v4.0.4
        "symfony/console": "^4.0", // v4.0.14
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/framework-bundle": "^4.0", // v4.0.14
        "symfony/lts": "^4@dev", // dev-master
        "symfony/twig-bundle": "^4.0", // v4.0.4
        "symfony/web-server-bundle": "^4.0", // v4.0.4
        "symfony/yaml": "^4.0" // v4.0.14
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.4
        "symfony/dotenv": "^4.0", // v4.0.14
        "symfony/maker-bundle": "^1.0", // v1.0.2
        "symfony/monolog-bundle": "^3.0", // v3.1.2
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.0.4
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/var-dumper": "^3.3|^4.0" // v4.0.4
    }
}
userVoice