Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Adding Routes & Controllers

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 $8.00

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

Login Subscribe

If you watch a lot of KnpU tutorials, you know that I love to talk about how the whole point of a bundle is that it adds services to the container. But, even I have to admit that a bundle can do a lot more than that: it can add routes, controllers, translations, public assets, validation config and a bunch more!

Find your browser and Google for "Symfony bundle best practices". This is a really nice document that talks about how you're supposed to build re-usable bundles. We're following, um, most of the recommendations. It tells you the different directories where you should put different things. Some of these directories are just convention, but some are required. For example, if your bundle provides translations, they need to live in the Resources/translations directory next to the bundle class. If you follow that rule, Symfony will automatically load them.

Adding a Route + Controller

Here's our new goal: I want to add a route & controller to our bundle. We're going to create an optional API endpoint that returns some delightful lorem ipsum text.

Before we start, I'll open my PhpStorm preferences and, just to make this more fun, search for "Symfony" and enable the Symfony plugin. Also search for "Composer" and select the composer.json file so that PhpStorm knows about our autoload namespaces.

Back to work! In src/, create a Controller directory and inside of that, a new PHP class called IpsumApiController. We don't need to make this extend anything, but it's OK to extend AbstractController to get some shortcuts... except what!? AbstractController doesn't exist!

That's because the class lives in FrameworkBundle and... remember! Our bundle does not require that! Ignore this problem for now. Instead, find our app code, open AbstractController, copy its namespace, and use it to add the use statement manually to the controller.

... lines 1 - 5
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
... line 7
class IpsumApiController extends AbstractController
... lines 9 - 25

Next, add a public function called index. Here, we're going to use the KnpUIpsum class to return a JSON response with some dummy text. When you create a controller in a reusable bundle, the best practice is to register your controller as a proper service and use dependency injection to get anything you need.

... lines 1 - 16
public function index()
{
... lines 19 - 22
}
... lines 24 - 25

Add public function __construct() and type-hint the first argument with KnpUIpsum. I'll press Alt+Enter and choose Initialize Fields so that PhpStorm creates and sets a property for that.

... lines 1 - 9
private $knpUIpsum;
... line 11
public function __construct(KnpUIpsum $knpUIpsum)
{
$this->knpUIpsum = $knpUIpsum;
}
... lines 16 - 25

Down below, return $this->json() - we will not have auto-complete for that method because of the missing AbstractController - with a paragraphs key set to $this->knpUIpsum->getParagraphs() and a sentences key set to $this->knpUIpsum->getSentences()

... lines 1 - 16
public function index()
{
return $this->json([
'paragraphs' => $this->knpUIpsum->getParagraphs(),
'sentences' => $this->knpUIpsum->getSentences(),
]);
}
... lines 24 - 25

Excellent!

Registering your Controller as a Service

Next, we need to register this as a service. In services.xml, copy the first service, call this one ipsum_api_controller, and set its class name. For now, don't add public="true" or false: we'll learn more about this in a minute. Pass one argument: the main knpu_lorem_ipsum.knpu_ipsum service.

... lines 1 - 6
<services>
... lines 8 - 13
<service id="knpu_lorem_ipsum.ipsum_api_controller" class="KnpU\LoremIpsumBundle\Controller\IpsumApiController">
<argument type="service" id="knpu_lorem_ipsum.knpu_ipsum" />
</service>
... lines 17 - 19
</services>
... lines 21 - 22

Tip

In Symfony 5, you'll need a bit more config to get your controller service working:

<service id="knpu_lorem_ipsum.ipsum_api_controller" class="KnpU\LoremIpsumBundle\Controller\IpsumApiController" public="true">
    <call method="setContainer">
        <argument type="service" id="Psr\Container\ContainerInterface"/>
    </call>
    <tag name="container.service_subscriber"/>
    <argument type="service" id="knpu_lorem_ipsum.knpu_ipsum"/>
</service>

For a full explanation, see this thread: https://bit.ly/abstract-controller-tag

Perfect!

Routing

Finally, let's add some routing! In Resources/config, create a new routes.xml file. This could be called anything because the user will import this file manually from their app.

To fill this in, as usual, we'll cheat! Google for "Symfony Routing" and, just like we did with services, search for "XML" until you find a good example.

Copy that code and paste it into our file. Let's call the one route knpu_lorem_ipsum_api. For controller, copy the service id, paste, and add a single colon then index.

<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="knpu_lorem_ipsum_api" controller="knpu_lorem_ipsum.ipsum_api_controller:index" path="/" >
<!-- settings -->
</route>
</routes>

Fun fact: in Symfony 4.1, the syntax changes to a double :: and using a single colon is deprecated. Keep a single : for now if you want your bundle to work in Symfony 4.0.

Finally, for path, the user will probably want something like /api/lorem-ipsum. But instead of guessing what they want, just set this to /, or at least, something short. We'll allow the user to choose the path prefix.

And that's it! But... how can we make sure it works? In a few minutes, we're going to write a legitimate functional test for this. But, for now, let's just test it in our app!

In the config directory, we have a routes.yaml file, and we could import the routes.xml file from here. But, it's more common to go into the routes/ directory and create a separate file: knpu_lorem_ipsum.yaml.

Add a root key - _lorem_ipsum - this is meaningless, then resources set to @KnpULoremIpsumBundle and then the path to the file: /Resources/config/routes.xml. Then, give this a prefix! How about /api/ipsum.

_lorem_ipsum:
resource: '@KnpULoremIpsumBundle/Resources/config/routes.xml'
prefix: /api/ipsum

Did it work? Let's find out: find your terminal tab for the application, and use the trusty old:

php bin/console debug:router

There it is! /api/ipsum/. Copy that, find our browser, paste and.... nope. Error!

Controller ipsum_api_controller cannot be fetched from the container because it is private. Did you forget to tag the service with controller.service_arguments.

The error is not entirely correct for our circumstance. First, yes, at this time, controllers are the one type of service that must be public. If you're building an app, you can give it this tag, which will automatically make it public. But for a reusable bundle, in services.xml, we need to set public="true".

... lines 1 - 6
<services>
... lines 8 - 13
<service id="knpu_lorem_ipsum.ipsum_api_controller" class="KnpU\LoremIpsumBundle\Controller\IpsumApiController" public="true">
... line 15
</service>
... lines 17 - 19
</services>
... lines 21 - 22

Try that again! Now it works. And... you might be surprised! After all, our bundle references a class that does not exist! This is a problem... at least, a minor problem. But, because FrameworkBundle is included in our app, it does work.

But to really make things solid, let's add a proper functional test to the bundle that guarantees that this route and controller work. And when we do that, it'll become profoundly obvious that we are, yet again, not properly requiring all the dependencies we need.

Leave a comment!

38
Login or Register to join the conversation
Mindgruve Avatar
Mindgruve Avatar Mindgruve | posted 2 years ago

First of all, thanks for this tutorial. Super clear, although when doing it using symfony 5 I always get stuck on this issue:

{{my_route}} has no container set, did you forget to define it as a service subscriber

.

Anybody having the same issue?

Edited
----------
Found the issue,
needed to add <defaults autowire="true" autoconfigure="true"/> on your service.xml file to enable auto wiring.

1 Reply
Default user avatar

I think that autowiring in the bundle is explicitly discouraged. Another way around this is to add `<call>` to each handler with method `setContainer` (which is admittedly a pain). Tbh, idk how that works exactly (are you creating a *new* container? Nesting a container? Setting something *on* a container?) but both methods don't appear to be necessary to work with bundles which appear to account for Symfony 5 such as:
https://github.com/willdura...

Does anyone have any other input on this?!

Edit
-----
I have not personally tested that bundle out on a Symfony 5 install myself; I just read the commit comments.

Reply

Hey ash-m!

Yep, you are correct :). You CAN use autowiring in your bundle, but as a best practice, it IS discouraged. The reason is that wiring things manually helps make your bundle a bit faster (on dev mode, it would be the same in prod) and makes your service config easier to read by others because it's explicit.

> Another way around this is to add `<call>` to each handler with method `setContainer` (which is admittedly a pain).

Yes, this is basically what autowiring is doing normally in this case. So, you're doing it manually. For others, there is a larger conversation about this over here: https://symfonycasts.com/sc...

> Tbh, idk how that works exactly (are you creating a *new* container? Nesting a container? Setting something *on* a container?)

It's a really cool, but complex feature :). You're creating a mini-container that has *some* services in it. You can learn about the idea here: https://symfonycasts.com/sc...

> but both methods don't appear to be necessary to work with bundles which appear to account for Symfony 5 such as: https://github.com/willdura...

If a controller doesn't extend AbstractController - https://github.com/willdura... - then none of this is needed. The AbstractController class is what tries to use this mini-service container :).

Cheers!

Reply
Default user avatar

Thank you for the detailed reply! I am glad you mentioned the abstract controller thing because I attempted this a again using the ADR pattern and it ended up working and I didn't know why.

Reply
Damien millet Avatar
Damien millet Avatar Damien millet | Mindgruve | posted 2 years ago

THK YOU BROTHER !

Reply

Hey Mindgruve

Sorry for being late to help you out but I'm glad that you could find and share the solution. Cheers!

Reply
Default user avatar
Default user avatar Saif Ali Ansari | posted 11 months ago

Hey

I am facing issue in this video section i am running the command
bin/console debug:router
but its throw the error
In FileLoader.php line 168:

Unable to find file "@KnpULoremIpsumBundle/Resources/config/routes.xml" in @KnpULoremIpsumBundle/Resources/config/r
outes.xml (which is being imported from "C:\xampp\htdocs\ReusableBundleSymfony\config/routes/knpu_lorem_ipsum.yaml"
). Make sure the "KnpULoremIpsumBundle/Resources/config/routes.xml" bundle is correctly registered and loaded in th
e application kernel class. If the bundle is registered, make sure the bundle path "@KnpULoremIpsumBundle/Resources
/config/routes.xml" is not empty.

In Kernel.php line 275:

Unable to find file "@KnpULoremIpsumBundle/Resources/config/routes.xml".

debug:router [--show-controllers] [--format FORMAT] [--raw] [-h|--help] [-q|--quiet] [-v|vv|vvv|--verbose] [-V|--version] [--ansi] [--no-ansi] [-n|--no-interaction] [-e|outes--env ENV] [--no-debug] [--] <command> [<name>]

file path and code .
LoremIpsumBundle/src/Resources/config/routes.xml


<routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">

<route id="knpu_lorem_ipsum_api" controller="knpu_lorem_ipsum.ipsum_api_controller:index" path="/">

</route>

</routes>

file path code
LoremIpsumBundle/src/Controller/IpsumApiController.php
knpUIpsum = $knpUIpsum;
}

public function index()
{
return $this->json([
'paragraphs' => $this->knpUIpsum->getParagraphs(),
'sentences' => $this->knpUIpsum->getSentences(),
]);
}
}

file path and code
config/routes/knpu_lorem_ipsum.yaml
_lorem_ipsum:
resource: '@KnpULoremIpsumBundle/Resources/config/routes.xml'
prefix: '/api/ipsum'

Reply

Hey Saif Ali Ansari!

Hmm. Before we dig in too far, this may be something simple. The error says:

> Unable to find file "@KnpULoremIpsumBundle/Resources/config/routes.xml

But you said the file is located at:

> LoremIpsumBundle/src/Resources/config/routes.xml

Try moving the Resources/ directory into LoremIpsumBundle directly - NOT inside of src/. If that doesn't help, let me know :).

Cheers!

Reply
Default user avatar
Default user avatar Saif Ali Ansari | weaverryan | posted 11 months ago

Hey weaverryan

Thank you to reply

But i can remove from src but steel its gives same error .
i am stuck in this tutorial from last three day .

Reply

Hi Saif Ali Ansari!

Sorry for the slow reply! Ok, so let's at what's going on. First, in your config/routes/knpu_lorem_ipsum.yaml, you have something that looks like this:


_lorem_ipsum:
resource: '@KnpULoremIpsumBundle/Resources/config/routes.xml'
prefix: /api/ipsum

And... that's great! For our purposes, the only really important part is the path: @KnpULoremIpsumBundle/Resources/config/routes.xml.

When Symfony sees this, it looks for the location of KnpULoremIpsumBundle and then looks for the path Resources/config/routes.xml inside of it to find the file. If you're following the tutorial exactly (which it seems like you are), then your bundle lives in the LoremIpsumBundle/. Directory, this means that Symfony is looking for the file in this EXACT path:


LoremIpsumBundle/Resources/config/routes.xml

Do you have a file at this path? I'm asking because, from your original message, you mentioned that your routing file lives at:


LoremIpsumBundle/src/Resources/config/routes.xml

And this is NOT the correct path. The correct path is LoremIpsumBundle/Resources/config/routes.xml. If you DO move the file to LoremIpsumBundle/Resources/config/routes.xml and you still get the error, then there are only 2 other possibilities I can think of:

A) The KnpULoremIpsumBundle is not registered in your config/bundles.php... or it has a different name
B) The KnpULoremIpsumBundle class does not live at LoremIpsumBundle/KnpULoremIpsumBundle.php. And so, the "root directory" of your bundle is somewhere else.

Let me know what you find out :).

Cheers!

Reply
triemli Avatar
triemli Avatar triemli | posted 2 years ago

Hi guys, i see an error here:
"knpu_lorem_ipsum.controller.ipsum_api_controller" has no container set, did you forget to define it as a service subscriber?
In comments people write autowire is fix for an error, but the others not recommend it. So how resolve it then?

Reply

Hey triemli!

Sorry about the trouble - let's see if we can work it out :). Check out my answer here: https://symfonycasts.com/sc...

There was a subtle change in the core of Symfony, which makes this now required. Actually, I need to add a note about this to the tutorial - my fault for not doing it already!

Let me know if the solution I linked to helps - and if you want any further explanation.

Cheers!

1 Reply
triemli Avatar

Thanks a lot! It works!

Reply
Jose carlos C. Avatar
Jose carlos C. Avatar Jose carlos C. | posted 2 years ago

Hello,

I'm working with Symfony 4, I created a bundle and added the routes inside the bundle /resources/config/routes.yaml, because I have to add the routes again in the global configuration, can't it be done automatically from the bundle?

Reply
Mindgruve Avatar
Mindgruve Avatar Mindgruve | Jose carlos C. | posted 2 years ago | edited

Hey Jose carlos C.

You don't need to add the routes all over again. You need to tell the app to look into your route config file, in this case, your bundle route config.

One way is adding to the routes folder a reference for what you want:

// config/routes/my_bundle.yaml
_my_bundle:
resource: '@MyBundle/Resources/config/routes.xml'
prefix: /

Hope that helps.

Reply
Jose carlos C. Avatar
Jose carlos C. Avatar Jose carlos C. | Mindgruve | posted 2 years ago

I just don't want it to depend on the global configuration, once it's defined in the Bundle, it doesn't need to be loaded again, so I'm looking for an option if it exists in Symfony to be able to have routes from the Bundle.

Reply

Hey Jose carlos C.

Pretty interesting question =) Of course you can use recipe system, but I think it's not suitable if you have not open source bundle. But there is another way. You can try make Custom route loader, and load routes from your bundle config file. It's described a little here https://symfony.com/doc/cur...

Cheers!

Reply
Jose carlos C. Avatar
Jose carlos C. Avatar Jose carlos C. | sadikoff | posted 2 years ago

Thanks for the answer. I tried that already and it doesn't work. I have to include the routes.yml file back into app/config/routes.yml, https://stackoverflow.com/a... which means I have to include it out of the Bundle.

But there is good news! There is a solution that you only write once and it works for all your bundles, I found it here.
https://github.com/symfony/...

bundle_routes:
resource: "../src/Bundles/*/Resources/config/routes.yml"

Reply
Mindgruve Avatar

Oh! Thanks fro sharing it!

Reply
Mindgruve Avatar

Without telling the app where are your routes I don't see a way. But you can create your config file that register your bundle route paths on the config folder as part of your bundle installation, like most of the bundles.

If you find a different workaround, please share here. I would be interested to know.

Reply

Hey Mindgruve

Thanks for you assistance with this question =) If you interested in another workaround check my answer above =)

Cheers!

Reply
Yaroslav Y. Avatar
Yaroslav Y. Avatar Yaroslav Y. | posted 3 years ago

hey, thanks for this tutorial;
I still wonder though, if there is a way for Symfony (Flex?...) to auto-add the bundle's routing file (as resource) - so that I would not do it manually? can / should I do that manually in the load() method maybe? could you please just give a hint?

Reply

Hey Yaroslav,

Actually, Symfony Flex can auto-add routes.... Are we talking about Symfony 4? For example, here's the routes for EasyAdminBundle that Flex will automatically add when you require this package: https://github.com/symfony/... - i.e. Flex just copy/paste the easy_admin.yaml file with routes into "config/routes/easy_admin.yaml" in your project, and if you have good Symfony 4 application - that file will be automatically read by the application, see "configureRoutes()" in Kernel that responsible to load those files: https://github.com/symfony/...

Did you upgrade to Symfony 4 your application from 3.x? Or did you create Symfony 4 application from scratch? Probably you missed something during your update?

Cheers!

Reply
Yaroslav Y. Avatar
Yaroslav Y. Avatar Yaroslav Y. | victor | posted 3 years ago

btw, I also tried to do a routes file copy with the means of composer.json of my bundle

"scripts": {
"post-install-cmd": "php -r \"copy('Resources/config/routes.yml', '../config/routes/my-bundle.yml');\"",
"post-package-install": "php -r \"copy('Resources/config/routes.yml', '../config/routes/my-bundle.yml');\"",
"post-package-uninstall": "php -r \"unlink('../config/routes/my-bundle.yml')\""
}

but none of these worked (looks like none of these was called at all, because I tried echoing and got no output)...

Reply

Hey Yaroslav,

Well, doing so with Composer is not a correct way in my opinion.

Cheers!

Reply
Yaroslav Y. Avatar
Yaroslav Y. Avatar Yaroslav Y. | victor | posted 3 years ago

hi Victor,

thank you for the prompt reply. yes, I'm using Smf 4.2, and just follow this tutorial instructions (except for manual addition of bundle's resource to app routes config).

I tried install / uninstall my bundle via composer, but the routes file was never auto-copied.

should I probably create some instructions for Flex (a recipe) so that it would know what file to copy?

Reply

Hey Yaroslav,

Ah, yes, now I see the problem. You're talking about *your* bundle, sure Flex does not know nothing about it except that it's a Symfony bundle so it just includes the bundle in bundles.php and that's it. To teach Flex that when you require your bundle Flex should copy some extra files as well - you need to create a recipe for your bundle. Recipe is just a set of instructions, you can see the same EasyAdminBundle as example: https://github.com/symfony/... . But that's the official recipe, your recipe should be in https://github.com/symfony/... repository where other non-official bundles are.

Here's more info about how to create a recipe: https://github.com/symfony/...

I hope that helps!

Cheers!

Reply
Yaroslav Y. Avatar
Yaroslav Y. Avatar Yaroslav Y. | victor | posted 3 years ago

hi Viktor,

great, thank you for the reply! will surely give it a try.

thank you for your support!

Reply

You're welcome! ;)

Cheers!

Reply
MichalWilczynski Avatar
MichalWilczynski Avatar MichalWilczynski | posted 3 years ago

Hey! I have error:

Type error: Too few

arguments to function

Mwil\DummyArticleBundle\Controller\DummyArticleApiController::__construct(),

0 passed in

C:\github\create-bundle\vendor\symfony\http-kernel\Controller\ControllerResolver.php

on line 111 and exactly 1 expected

in services.xml I have registered new service for controller with argument:

<service id="mwil_dummy_article_bundle.dummy_article_api_controller" class="Mwil\DummyArticleBundle\Controller\DummyArticleApiController">
<argument type="service" id="mwil_dummy_article_bundle.mwil_dummy_article"/>
</service>

But it not passing argument to constructor in DummyArticleApiController class

{{ PROBLEM RESOLVED }} I can't believe I missed typo and I was looking for a problem for an hour ;)

Reply

Hey, I've been going crazy trying to find why this bit will not work for me.
I keep gettin the error : [ERROR 1845] Element '{http://symfony.com/schema/d...}container': No matching global declaration available for the validation root.

Now from what I've gathered so far this is due to discrepancy between the xsd defintion and the actual xml file.

However my xml file just contains the defintions from the official symfony docs and one service :

<container xmlns="http://symfony.com/schema/d..." xmlns:xsi="http://www.w3.org/2001/XMLS..." xsi:schemalocation="http://symfony.com/schema/d...
http://symfony.com/schema/d...">

<services>
<service id="ddb_stuart_api.stuart_api" class="DdB\StuartApiBundle\StuartApi" public="true"/>

</services>
</container>

Does anyone have a clue why I might be getting this error ?

Thanks in advance for any help

Reply

Turns out i'm an idiot, when including the routes.xml file in my actual application I actually included the services.xml instead, please disregard my previous message

Reply

Hey DennisdeBest!

No worries! Let's just say that making mistakes is the best way to learn - so now you're an expert in this area ;). Good job figuring out the issue.

Cheers!

Reply
tomchkkk Avatar
tomchkkk Avatar tomchkkk | posted 4 years ago

Hi guys, I found a discrepancy between the name of the controller service in the example file in the script, and the name that appears in the video. In the example it is `knpu_lorem_ipsum.controller.ipsum_api_controller`, but in the script it appears as `knpu_lorem_ipsum.ipsum_api_controller`.

Reply

Hey Tom,

Thanks for mentioning it! Yes, it looks like we have a little discrepancy between the video and its scripts, in the video we missed that "controller" string between "knpu_lorem_ipsum" and "ipsum_api_controller". Probably not a big deal, but it might be good to know for others.

Cheers!

Reply
Default user avatar
Default user avatar Lucas Baldassari | posted 4 years ago

I need to create some Doctrine Entities in my bundle, to be used by the external App. How can I add and configure these Entities?

Reply

Hey Lucas,

Good question! You can create an entity in your bundle and even use Doctrine annotation for mapping. Then in your app that uses the bundle you can create an empty class in src/Entity/ dir that will extend the one from the bundle - Doctrine will see all the parents fields. Or even better to create a Trait in your bundle instead of a class, so you don't need to inherit any class in your app, just *use* the trait - this way is even more flexible, thanks to PHP traits.

Cheers!

1 Reply
Cat in space

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

This tutorial is built using Symfony 4, but most of the concepts apply fine to Symfony 5!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "ext-iconv": "*",
        "doctrine/annotations": "^1.8", // v1.8.0
        "knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
        "knpuniversity/lorem-ipsum-bundle": "*@dev", // dev-master
        "nexylan/slack-bundle": "^2.0,<2.2", // v2.0.1
        "php-http/guzzle6-adapter": "^1.1", // v1.1.1
        "sensio/framework-extra-bundle": "^5.1", // v5.1.6
        "symfony/asset": "^4.0", // v4.0.6
        "symfony/console": "^4.0", // v4.0.6
        "symfony/flex": "^1.0", // v1.18.7
        "symfony/framework-bundle": "^4.0", // v4.0.6
        "symfony/lts": "^4@dev", // dev-master
        "symfony/twig-bundle": "^4.0", // v4.0.6
        "symfony/web-server-bundle": "^4.0", // v4.0.6
        "symfony/yaml": "^4.0", // v4.0.6
        "weaverryan_test/lorem-ipsum-bundle": "^1.0" // v1.0.0
    },
    "require-dev": {
        "easycorp/easy-log-handler": "^1.0.2", // v1.0.4
        "sensiolabs/security-checker": "^4.1", // v4.1.8
        "symfony/debug-bundle": "^3.3|^4.0", // v4.0.6
        "symfony/dotenv": "^4.0", // v4.0.6
        "symfony/maker-bundle": "^1.0", // v1.1.1
        "symfony/monolog-bundle": "^3.0", // v3.2.0
        "symfony/phpunit-bridge": "^3.3|^4.0", // v4.3.3
        "symfony/stopwatch": "^3.3|^4.0", // v4.0.6
        "symfony/var-dumper": "^3.3|^4.0", // v4.0.6
        "symfony/web-profiler-bundle": "^3.3|^4.0" // v4.0.6
    }
}