Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Migrating framework Config

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

Most of our old code lives in app/config, and also src/AppBundle. We'll talk about that directory later - it's easier.

Yep, most of the work of migrating our code to the new app involves moving each piece of config into the new location. Honestly, it's tedious and slow. But you're going to learn a lot, and the end result is totally worth it.

Moving Parameters

Start in config.yml. Ignore imports: we'll look at each file one-by-one. The first key is parameters. Copy those, delete them, and open config/services.yaml. This is where your parameters and services will live. Paste them here. Oh, but remove the strict_mode line: autowiring always works in "strict mode" in Symfony 4.

... lines 1 - 2
parameters:
locale: en
cache_type: file_system
... lines 6 - 30

Environment Variables

Keep going! Back to config.yml. The keys under framework will be the most work to migrate... by far. In Flex, this configuration will live in config/packages/framework.yaml: each package has its own config file.

Remove the esi line from the old file: it's also commented out in the new one: nothing to migrate.

Check out the secret config: it's set to %env(APP_SECRET)%. That's a relatively new syntax that reads from environment variables. In the dev environment, Symfony loads the .env file, which sets all these keys as environment variables, including APP_SECRET.

Delete the old secret key. The way this value is set is a bit different, but, the point is, it's handled.

Requiring translator

The next key is translator. Are you ready? Because this is where things get fun! You might think that all we need to do is copy this line into framework.yaml. But no!

Many of the keys under framework represent components. In Symfony 3, by adding the translator key, you activated that component.

But with Flex, the Translator component isn't even installed yet. Yep, if you want a translator, you need to install it. In your terminal, run:

composer require translator

If that package name looks funny... it should! There is no package called translator! But look! It added a new symfony/translator key to composer.json.

This is another superpower of Flex. Go to https://symfony.sh/. This is a list of all of the packages that have a recipe. Search for "translation" to find symfony/translation. See those Aliases? Yep, we can reference translation, translations or translator and Flex will, um, translate that into symfony/translator automatically.

The translator Recipe

Back to the terminal! Before I started recording, I committed all of our changes so far. That was no accident: Flex just installed a recipe and I want to see exactly what it did! Run:

git status

Cool! It created a new translation.yaml file and a translation/ directory.

framework:
default_locale: '%locale%'
translator:
paths:
- '%kernel.project_dir%/translations'
fallbacks:
- '%locale%'

That is where translation files should live in Symfony 4. And even though the translator config lives under framework, in Flex, it has its own configuration file. Oh, and this is one of my favorite things about Flex. Why should my translation files live in a translations/ directory? Is that hardcoded somewhere deep in core? Nope: it's right here in your configuration file. Want to put them somewhere else? Just update that line or add a second path.

So, do we need to move the translator config from our old project? Actually, no! It's already in the new file. Delete it.

And since we now know that translations should live in this new translations/ directory, let's move our existing files... well file. In app/Resources/translations, move validators.en.yml down into translations/.

Migrating router Config

We're on a roll! What about the router config? It told Symfony to load routing.yml. All of that is taken care of in the new app: it loads a routes.yaml file and anything in the routes/ directory, like annotations.yaml.

There's also a config/packages/routing.yaml file, and even another one in dev/ to tweak that strict_requirements setting.

The point is this: routing is handled. Delete that stuff!

Migrating Forms and Validator

Next, forms! Like with translations, this activates a component that is not installed yet. We do have forms in our app, so we need this and validation. Let's get them installed:

composer require form validator

Yep! More aliases! Perfect! This time, it did not install any recipes. That's cool: not all packages need a recipe.

So, do we need to move these 2 lines of config into framework.yaml? Actually, no!

Go back to your terminal and run:

./bin/console debug:config framework

This prints out the current framework configuration. Search for form. Nice! It's already enabled, even without any config! This is really common with Flex: as soon as a component is installed, FrameworkBundle automatically enables it. No configuration is needed unless you want to change something. Delete the form line.

Search for "validation" next: it's even more interesting! It's also enabled, and enable_annotations is set to true. Great! Delete the validation line! What's really interesting is that enable_annotations is set to true because it detected that we have the Doctrine annotations package installed. This is the flow with Flex: install a package and you're done.

Ok! It might not look like it, but we're almost done with the framework stuff. Let's finish it next!

Leave a comment!

5
Login or Register to join the conversation
Andreas B. Avatar
Andreas B. Avatar Andreas B. | posted 3 years ago

We have an application where the ESI functionality is necessary, so we have the esi.enabled option set to true. When I remove this from our config.yml and paste it into the new framework.yaml, I get an error that says 'An exception has been thrown during the rendering of a template ("The "esi" renderer does not exist.").' - so I guess that this file sets the configuration only for the new App namespace, is that right?
If so, it's not really a gently migration imho. Because we have an old application with multiple custom "bundles", we need to make sure that we adopt a two-pronged strategy. Also, we don't have any code freeze so we have to go one step after another for the migration.
My question is now: is there also another (more gentle) way to accomplish the migration? (Or did I do something wrong?)

Reply

Hey Andreas B. !

An exception has been thrown during the rendering of a template ("The "esi" renderer does not exist.").' - so I guess that this file sets the configuration only for the new App namespace, is that right?

Hmm, that is a strange error. First, to answer your question, no: this file sets config for the FrameworkBundle in general - it should activate ESI for your entire system, not just for the App namespace. Do you have framework.esi config anywhere else in your app? I want to make sure that you don't have ESI disabled on accident in the "dev" environment. Otherwise, this "should work" - but obviously... it's not. Let me know if you have any other framework.esi config. Or, a good way to check is to run bin/console debug:config framework to see what the final, resolved value of framework.esi.enabled is.

If so, it's not really a gently migration imho. Because we have an old application with multiple custom "bundles", we need to make sure that we adopt a two-pronged strategy. Also, we don't have any code freeze so we have to go one step after another for the migration.
My question is now: is there also another (more gentle) way to accomplish the migration? (Or did I do something wrong?)

This is a tricky migration, I'd admit. However, as I mentioned above, your assumption that the framework.yaml file affects only the App\ namespace is (thankfully) incorrect :). In our app, we kept our existing bundles during this transition. And then after it was complete, we started slowly moving things out of our bundles and into App. That's what we do in this tutorial - we don't remove the AppBundle stuff until the final step (after we have things working).

Cheers!

Reply
Andreas B. Avatar
Andreas B. Avatar Andreas B. | weaverryan | posted 3 years ago | edited

Hey weaverryan ,
at first I want to thank you for this really precise reply! I really appreciate your help!
Unfortunately, it seems that there're some really weird things going on.
Namely the following:

If I set
`
framework:

esi: 
    enabled: true

`
in the app/config/config.yml file:

  • return value of "bin/console debug:config framework" is esi: enabled: false
  • site IS working

If I set
`
framework:

esi: 
    enabled: true

`
in the config/packages/framework.yaml file:

  • return value of "bin/console debug:config framework" is esi: enabled: true
  • site is NOT working

But the output of the bin/console command might be misleading, because I don't know if migrated the bin/console file correctly. As shown in the tutorial, I replaced our file with the new one from the recipes repository (https://github.com/symfony/recipes/blob/master/symfony/console/4.4/bin/console) but it seems that the output is only based on the new Flex app. If I simply execute bin/console debug:config with the OLD bin/console file then all of our custom "bundles" are listed. But if I instead replace the bin/console file and then execute the debug:config command, our custom bundles are not listed, only the "external" bundles.
But either way, that shouldn't have any consequence of the real handling of the Flex app, right? Means: even if bin/console might not be correct, the framework.yaml file should work for both "apps". But maybe I did something wrong with the migration and the new config files of the Flex app aren't "really" registered?

I tried to add a new controller with indexAction + route /foobar in the routes.yaml file, and when I execute "bin/console debug:router" it outputs "index ANY ANY ANY /foobar" but when I try to access the route I get a 404 response.

Maybe it has something to do with the public/index.php? Do I have to merge both app.php and app_dev.php with this new file before I get the new flex app to work or am I missing something else? Do I have to do something else to "activate" the new framework.yaml and it's components?

Best regards,
Andy

Reply
Andreas B. Avatar

Ok I think I got one step further! I included the new public/index.php within the app_dev.php (and commented all other lines within app_dev.php), then I added the constants and things from app_dev.php in config/bootstrap.php.
Now, the new route /foobar is accessible BUT all the old routes are not.

I guess now that I "activated" the new Flex environment, all old config files (within app/config) are not loaded any more, is that correct?

That means that all the old stuff won't work until I migrated the services etc. into the new environment?
Or is there another way I could keep the old configurations as well?

Reply

Hey Andreas B.!

Excellent debugging with the index.php file! That file should have been added for you around this step - https://symfonycasts.com/screencast/symfony4-upgrade/flex-composer.json#scaffold-the-full-structure - where you allow Flex to execute all the recipes for you. I'm not sure why that would have no happened in your case.

I guess now that I "activated" the new Flex environment, all old config files (within app/config) are not loaded any more, is that correct?

Yes, this is correct! But it's not nearly as bad as you think :). The new directory structure (it's not really Flex, Flex is just a new tool that installs recipes and works well with the new directory structure) loads service and package configuration from config/services.yaml and config/packages/* - you can see this right in the src/Kernel.php file. It does not load any other config files (unless you have a bundle with a "DependencyInjection" class that loads its own services file).

So let's look at each type of config:

A) services: suppose you have some other configuration files with service definitions, maybe in a bundle or somewhere else. I would simply go into the new config/services.yaml file and import the old file from there. That should handle it just fine, and you can migrate over time.

B) bundle config (e.g. services, twig, etc): you could also import these from services.yaml - that should also work fine. But in this tutorial, I chose to move those into their new locations in config/ (mostly splitting config.yml into multiple files). If you didn't do this, you might have some trouble with new files in config/packages/ (that were added by the recipes) overriding your config.

C) routing: if you have routing files somewhere else in your app, you can move them into config/routing/ or import the routing files from config/routes.yaml - your call.

Oh, and if you still have some bundles in your app, you can totally keep those. You'll just need to make sure that they are initialized correctly in the config/bundles.php file.

Let me know if that helps! You can absolutely get your app running with the new and old code. But it is a tricky "dance" to get everything in the right spot and loaded.

Cheers!

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",
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^1.6", // 1.8.1
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.1
        "doctrine/orm": "^2.5", // v2.7.2
        "fzaninotto/faker": "^1.7", // v1.7.1
        "knplabs/knp-markdown-bundle": "^1.4", // 1.6.0
        "sensio/framework-extra-bundle": "^5.0", // v5.1.3
        "stof/doctrine-extensions-bundle": "dev-master", // dev-master
        "symfony/asset": "^4.0", // v4.0.1
        "symfony/console": "^4.0", // v4.0.1
        "symfony/flex": "^1.0", // v1.9.10
        "symfony/form": "^4.0", // v4.0.1
        "symfony/framework-bundle": "^4.0", // v4.0.1
        "symfony/lts": "^4@dev", // dev-master
        "symfony/maker-bundle": "^1.0", // v1.0.2
        "symfony/monolog-bundle": "^3.1", // v3.1.2
        "symfony/polyfill-apcu": "^1.0", // v1.6.0
        "symfony/profiler-pack": "^1.0", // v1.0.3
        "symfony/security-bundle": "^4.0", // v4.0.1
        "symfony/security-csrf": "^4.0",
        "symfony/swiftmailer-bundle": "^3.1", // v3.1.6
        "symfony/translation": "^4.0", // v4.0.1
        "symfony/twig-bundle": "^4.0", // v4.0.1
        "symfony/validator": "^4.0", // v4.0.1
        "symfony/web-server-bundle": "^4.0", // v4.0.1
        "symfony/yaml": "^4.0" // v4.0.1
    },
    "require-dev": {
        "symfony/dotenv": "^4.0", // v4.0.1
        "symfony/phpunit-bridge": "^4.0", // v4.0.1
        "doctrine/doctrine-fixtures-bundle": "^3.0" // 3.0.2
    }
}
userVoice