Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Updating the TwigBundle Recipe

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 updated framework-bundle recipe gave us this new routing file: config/routes/dev/framework.yaml:

resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /_error

Which loads a /_error/{statusCode} route where we can test what our production error pages look like.

This feature used to live in TwigBundle... which is why twig.yaml has basically the exact same import:

resource: '@TwigBundle/Resources/config/routing/errors.xml'
prefix: /_error

This is a minor problem. In your terminal, run:

php bin/console debug:router

and scroll up to the top. Yep! We have two routes for the exact same URL. The first one - which by chance is the one from FrameworkBundle - would win, but we still don't want the old one sitting there. Plus, it's deprecated and will disappear in Symfony 5.

We need to delete this twig.yaml file. But... we probably also need to update the TwigBundle recipe... which will probably delete it for us. Run:

composer recipes

Yep! The recipe for symfony/twig-bundle has an update.

Updating symfony/twig-bundle Recipe

Get some info about it:

composer recipes symfony/twig-bundle

Then copy the recipes:install command and run it:

composer recipes:install symfony/twig-bundle --force -v

Perfect! It looks like it modified three files. Let's start walking through them:

git add -p

The first change is inside the twig.yaml config file. If you ignore the stuff that it's removing - that's all our custom code - it looks like the updated recipe added a line: exception_controller: null.

Ok, so we definitely want to keep our custom changes... and we probably want to keep this new line... except that we don't really know why it was added.


Let's go do some digging! But this time, instead of checking the recipe commit history, let's try something different. Because this is a config change for TwigBundle, let's go see if they mention this in a CHANGELOG.

Google for "GitHub TwigBundle" to find its GitHub page. Scroll down and... yea! It has a CHANGELOG.md file.

Open it up and look at the 4.4.0 changes. Actually, this exception_controller change could even be from an earlier version - but we'll start here. And... yea, it does talk about it:

deprecated twig.exception_controller configuration option, set it to "null" and use framework.error_controller configuration instead.

The deprecated twig exception_controller Option

This is another feature that was deprecated inside TwigBundle and moved to FrameworkBundle. The exception, or "error", controller is the controller that's responsible for rendering an error page.

To disable - basically "stop using" the deprecated old code - we need to set exception_controller to null. That is why the recipe added this change. This is a good change. Of course, if your config file already has an exception_controller option... because you're using a custom exception controller, you'll need to move that value to framework.error_controller and do some reading to see if your controller code needs any other updates.

So we do want this change... but we can't accept this patch without killing our custom code. Copy the new config, hit "q" to quit this mode, and then... let's see - undo those changes by running:

git checkout config/packages/twig.yaml

Oh, and I guess I should spell "checkout" right.

Now, spin back over, open that file - config/packages/twig.yaml - and add exception_controller: null:

... lines 2 - 9
exception_controller: null

Nice! Let's... keep going: start the git add -p system again:

git add -p

This time we do want to accept the change to twig.yaml - "y" - and the next change is inside symfony.lock. Accept that too.

base.html.twig and the new test/twig.yaml

The last updated file is templates/base.html.twig and we definitely do not want to accept this change and kill our custom layout. Looking at the new code... I don't see anything super important that we might want to add. In fact, if you checked the recipe history, there haven't been any updates to this file in years. Hit "n" to ignore this.


git status

to see how things look. Oh! A new file: config/packages/test/twig.yaml - a config file that's only loaded in the test environment. Before we see what's inside it, let's revert the changes we don't want:

git checkout templates/base.html.twig

Go open the new file: config/packages/test/twig.yaml:

strict_variables: true

Ah, super minor: it sets strict_variables to true for our tests. This settings tells Twig to throw an exception if we try to use an undefined variable in a template. If we ever did that, we probably would want Twig to explode in our tests so we know about it. That's a good change. Add that file:

git add config/packages/test/twig.yaml

Manually Deleting config/routes/dev/twig.yaml

We're done! But... wait a second. We expected that the updated recipe would delete the extra config/routes/dev/twig.yaml file... but it didn't. Hmm... is it still in the recipe for some reason? Run:

composer recipes symfony/twig-bundle

Copy the URL to the recipe... and paste it in your browser. Huh. No - there is no config/routes directory at all in here. The file is gone! Why wasn't it deleted?

This is a shortcoming of the recipe update system: it's not smart enough. In a perfect world, it would realize that there used to be a config/routes/dev/twig.yaml file in the old version of the recipe... and since it is not there in the new version, it would delete it. But, that does not happen, at least not yet.

So, we need to delete it manually. This doesn't happen very often, but it is something you should be aware of.

Back at the terminal, run:

git status

one more time - things look good - and let's commit:

git commit -m "updating symfony/twig-bundle"

Nice! Now run:

composer recipes

We're getting close! Let's do any easy one next: let's upgrade symfony/mailer and symfony/sendgrid-mailer.

Leave a comment!

Login or Register to join the conversation
Tatiana D. Avatar
Tatiana D. Avatar Tatiana D. | posted 1 year ago

Hello, I'm trying to update some of the recipes and similar to the comment below I have an error when I try to execute composer recipes:update symfony/console: [Symfony\Component\Console\Exception\RuntimeException] Cannot run "sync-recipes --force": git not found.

I'm working on a Symfony 4.4 project, with docker wsl2 local setup using Ubuntu 20.04, the git it's initialized on my project, but in the php container seems it's missing, but I'm not sure how to fix this, any ideas?

symfony/flex -> "version": "v1.18.5"


Hey Tatiana,

Looks like there's no "git" command in the terminal when you run that command, do you have Git installed in your system? Behind the scene, recipes:update command leverages Git power to apply the change in your project. If you don't have Git - please, install it first, it's required for that command. If you do have Git installed - most probably you don't have "git" command available in the terminal where you run that command. E.g. on windows you probably have Git bash, try to run that recipe:update command from that Git bash terminal where "git" command should be available.

For the Docker container - it depends on what OS it's based on. Try to find the Dockerfile of that image on hub.docker.com and then search over the internet how to install Git in that OS. Otherwise, you can try to run that command upstream in case you have PHP installed in your Ubuntu you mentioned, or in case you have it's installed locally - run that command locally then.


hanen Avatar

Hello !! ..While trying to upgrade my project from symfony 4.2 to symfony 5 I couldn't update recipes for exple
when I run composer recipes:install "symfony/twig-bundle" --force -v
I got the error:
Cannot run "sync-recipes --force": git not found.
Exception trace:
() at D:\doc\test\quick_tour\vendor\symfony\flex\src\Command\InstallRecipesCommand.php:54
Symfony\Flex\Command\InstallRecipesCommand->execute() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/vendor/symfony/console/Command/Command.php:245
Symfony\Component\Console\Command\Command->run() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/vendor/symfony/console/Application.php:835
Symfony\Component\Console\Application->doRunCommand() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/vendor/symfony/console/Application.php:185
Symfony\Component\Console\Application->doRun() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/Console/Application.php:258
Composer\Console\Application->doRun() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/vendor/symfony/console/Application.php:117
Symfony\Component\Console\Application->run() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/Console/Application.php:104
Composer\Console\Application->run() at phar://C:/ProgramData/ComposerSetup/bin/composer.phar/bin/composer:61
require() at C:\ProgramData\ComposerSetup\bin\composer.phar:24

I googled a little and tried execute this command composer sync-recipes --force
but still getting the same error [Symfony\Component\Console\Exception\RuntimeException]
Cannot run "sync-recipes --force": git not found.


Hey hanen

I'm wondering it's telling you that git was not found. My first guess is that you haven't initialized git in your project. Let me know if that's not the case so we can figure this out


hanen Avatar

I run
git init
git satus
modified: composer.json
modified: composer.lock
modified: config/bundles.php
modified: symfony.lock

git add .

>composer recipes:install "symfony/twig-bundle" --force -v
Could not open input file: D:\doc\test\quick_tour\composer.phar


Hello hanen

I think it might be related with your environment. Probably not all paths are registered in Windows environment. It's quite difficult to advice something. Which shell and Windows version do you use?

BTW for best work behavior I would recommend to use WSL shell with Windows 10


hanen Avatar

I use cmder terminal on wind 7


Ok, lets try another way, try to upgrade flex package with composer upgrade symfony/flex

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

Hi, SymfonyCasts team !

I <i>dockerized</i> my own app which works great, but the Symfony code lies in the /app/ directory of my Git project. I think that's why I got the annoying confirmation messages according to <a href="https://github.com/symfony/flex/blob/master/src/Options.php#L68-L72&quot;&gt;this source code</a>.

But using the wonderful process of git add -p and git checkout I surely wanted to overwrite and then check which changes to commit. I used the --no-interaction option but it did not modify the files as I expected, only created new ones. Is this normal ? I don't know if it worths opening an issue on GitHub.
Here is the complete command I executed (docker exec -it app tells docker to execute a command in the container) and its output:
$> docker exec -it app composer recipes:install --no-interaction symfony/twig-bundle --force -v

Symfony operations: 1 recipe (a163a92832df72d8c7b4f86bf8da9837)

  • Configuring symfony/twig-bundle (>=4.4): From github.com/symfony/recipes:master
    Enabling the package as a Symfony bundle
    Copying files from recipe
       Created "./config/packages/test/twig.yaml"


<b>EDIT:</b> I don't think that's a file permission issue as it correctly modifies file when I answer the interactive overwrite questions using the same command without the --no-interaction option.

Cheers !


Hey AymDev,

Well, it depends on changes :) Why do you think the command works incorrectly? From the output, I see it does work properly, its output is totally valid. Well, IIRC it always says "Created ..." but technically it may create a new file or *modify* existent :)


AymDev Avatar
AymDev Avatar AymDev | Victor | posted 3 years ago | edited

Hi Victor,

I updated the Twig recipe, and saw that id did not modify ./templates/base.html.twig or ./config/packages/twig.yaml as shown on this video at <b>1:25</b>, it only created the ./config/packages/test/twig.yaml.
I understood by following this tutorial (for the 2nd time, by the way) that it modifies file even if it says "Created", but my base template was not modified, and my twig.yaml neither, that's why I think it is working incorrectly.

Maybe it is normal to not overwrite existing files in non-interactive mode when no git repository has been found but I found it counter-intuitive. Maybe I should dig more in the source code, haha !


Hey AymDev,

Hm, difficult to day more about it. You could try to do the same but locally (not in your Docker container). It should behave the same. I don't think it should be any different behavior in for interactive and non-interactive mode, but I'm not 100% sure.

The only possible reason I see is that your project just does not have any changes in those existent files.


AymDev Avatar
AymDev Avatar AymDev | Victor | posted 3 years ago | edited

Hi Victor,

I re-updated the recipe in Git <i>detached HEAD state</i> by executing the command locally and you were right, it works nice :-)
The issue must come from the container, sad I can't use the --no-interaction option but hopefully that's not for an everyday command !

Sorry for your time and thanks again for your answers !


Hey AymDev,

Hm, probably there's a reason that it works slightly different with --no-interaction option. But as I understand, you can kind of "jump" into container and execute that some command but without --no-interaction option now. Probably it would help.

Anyway, glad you found a workaround!



You should've tried 'e' (edit) option in [y,n,q,a,d,s,e,?] set when accepting git patch. You can selectively accept changes.
And another handy thing for new git files. You can just add file to git stage but not its contents with git add -N /path/to/file. And after that you can add its contents via git add -p /path/to/file.


Hey Xiro!

You're right! I've never really "gotten into" some of the other options inside "git patch" :). I do use the split "s" when possible - but not edit. I'll have to try that!

Thanks for the tip - and cheers :)


weaverryan No problem, love your tuts. Save me tons of time in real projects. Thank you and your team for your work! :)
And one more thing about git commits. Standartisation for...
* Capitalized
* In imperative present tense
Naming convention git commit messages
It should be read like "If applied it will"... 'Update symfony/twig-bundle'

Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": "^7.3.0",
        "ext-iconv": "*",
        "antishov/doctrine-extensions-bundle": "^1.4", // v1.4.2
        "aws/aws-sdk-php": "^3.87", // 3.110.11
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "doctrine/doctrine-bundle": "^2.0", // 2.0.6
        "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // 2.1.2
        "doctrine/orm": "^2.5.11", // v2.7.2
        "doctrine/persistence": "^1.3.7", // 1.3.8
        "easycorp/easy-log-handler": "^1.0", // v1.0.9
        "http-interop/http-factory-guzzle": "^1.0", // 1.0.0
        "knplabs/knp-markdown-bundle": "^1.7", // 1.8.1
        "knplabs/knp-paginator-bundle": "^5.0", // v5.0.0
        "knplabs/knp-snappy-bundle": "^1.6", // v1.7.0
        "knplabs/knp-time-bundle": "^1.8", // v1.11.0
        "league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
        "league/flysystem-cached-adapter": "^1.0", // 1.0.9
        "league/html-to-markdown": "^4.8", // 4.8.2
        "liip/imagine-bundle": "^2.1", // 2.3.0
        "nexylan/slack-bundle": "^2.1", // v2.2.1
        "oneup/flysystem-bundle": "^3.0", // 3.3.0
        "php-http/guzzle6-adapter": "^2.0", // v2.0.1
        "sensio/framework-extra-bundle": "^5.1", // v5.5.3
        "symfony/asset": "5.0.*", // v5.0.2
        "symfony/console": "5.0.*", // v5.0.2
        "symfony/dotenv": "5.0.*", // v5.0.2
        "symfony/flex": "^1.0", // v1.17.6
        "symfony/form": "5.0.*", // v5.0.2
        "symfony/framework-bundle": "5.0.*", // v5.0.2
        "symfony/mailer": "5.0.*", // v5.0.2
        "symfony/messenger": "5.0.*", // v5.0.2
        "symfony/monolog-bundle": "^3.5", // v3.5.0
        "symfony/security-bundle": "5.0.*", // v5.0.2
        "symfony/sendgrid-mailer": "5.0.*", // v5.0.2
        "symfony/serializer-pack": "^1.0", // v1.0.2
        "symfony/twig-bundle": "5.0.*", // v5.0.2
        "symfony/twig-pack": "^1.0", // v1.0.0
        "symfony/validator": "5.0.*", // v5.0.2
        "symfony/webpack-encore-bundle": "^1.4", // v1.7.2
        "symfony/yaml": "5.0.*", // v5.0.2
        "twig/cssinliner-extra": "^2.12", // v2.12.0
        "twig/extensions": "^1.5", // v1.5.4
        "twig/inky-extra": "^2.12" // v2.12.0
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.0", // 3.3.0
        "fzaninotto/faker": "^1.7", // v1.8.0
        "symfony/browser-kit": "5.0.*", // v5.0.2
        "symfony/debug-bundle": "5.0.*", // v5.0.2
        "symfony/maker-bundle": "^1.0", // v1.14.3
        "symfony/phpunit-bridge": "5.0.*", // v5.0.2
        "symfony/profiler-pack": "^1.0", // v1.0.4
        "symfony/var-dumper": "5.0.*" // v5.0.2