Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Recipe Upgrades: Part 2!

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

Run:

composer recipes:update

Next up is doctrine-extensions-bundle. This one... when we look... just modified a comment! Easy!. So commit that... and then move onto debug-bundle.

symfony/debug-bundle Recipe

composer recipes:update

I'll clear the screen and run that. This made two changes. Run:

git status

The first change was that it deleted an environment-specific file... and moved it into the main file. The second change, which isn't very common in recipe updates, is that in config/bundles.php, it previously loaded DebugBundle in the dev environment and test environment. We now recommend only loading it in the dev environment. You can load it in test environment, but it tends to slow things down, so it's been removed by default.

... lines 1 - 2
return [
... lines 4 - 9
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
... lines 11 - 24
];

Easy! Commit those changes... and keep going!

symfony/monolog-bundle Recipe

composer recipes:update

Next up is symfony/monolog-bundle. This one does have a conflict, but it's fairly simple. Previously, we had environment-specific files in the dev/, prod/, and test/ directories. These have all been moved into the central config/packages/monolog.yaml file. The only reason it conflicted on my project is because I had previously created this file in a tutorial to add a new markdown channel. I'll move my markdown channel down here... and keep the new stuff.

monolog:
channels:
- markdown
... lines 4 - 63

Below this, you can see the dev configuration for logging, the test config, and prod config. Again, if you had custom config in your old files, make sure you bring that over to the new file so it doesn't get lost.

... lines 1 - 5
when@dev:
monolog:
handlers:
main:
type: stream
... lines 11 - 26
when@test:
monolog:
handlers:
main:
type: fingers_crossed
... lines 32 - 40
when@prod:
monolog:
handlers:
main:
type: fingers_crossed
... lines 46 - 63

Add these changes... and... commit.

symfony/routing Recipe

Then right back to:

composer recipes:update

We're getting closer! Update symfony/routing. Let's see. This deleted another environment-specific config file. Yay! Less files! It also highlights a new default_uri config that you set if you ever need to generate absolute URLs from inside a command.

Previously, you accomplished this by setting router.request_context parameters. It's easier now, and this advertises that.

framework:
router:
utf8: true
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
#default_uri: http://localhost
when@prod:
framework:
router:
strict_requirements: null

Commit this stuff... and let's keep going!

symfony/security-bundle Recipe

composer recipes:update

We've made it to symfony/security-bundle. This one has a conflict... and it's inside config/packages/security.yaml. There are a few important things happening. The recipe update added enable_authenticator_manager: true. This enables the new security system. We're going to talk about that later. For now, set this to false so that we're still using the old security system.

security:
... lines 2 - 9
enable_authenticator_manager: false
... lines 11 - 64

It also added something called password_hashers, which replaces encoders. We're also going to talk about that later. For right now, I want you to keep both things.

security:
encoders:
App\Entity\User:
algorithm: auto
... lines 5 - 11
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
... lines 14 - 64

There's also a conflict down on the firewall. The important change is that the new recipe has lazy: true. That replaces anonymous: lazy, so we can go ahead and keep that change... but use the rest of our firewall.

security:
... lines 2 - 20
firewalls:
... lines 22 - 24
main:
lazy: true
provider: app_user_provider
guard:
authenticators:
- App\Security\LoginFormAuthenticator
logout:
path: app_logout
... lines 33 - 64

Oh, and at the bottom, we get one shiny new when@test section, which sets a custom password hasher. You can read the comment. This accelerates your tests by making it much faster to hash passwords in the test environment, where we don't care how secure our hashing algorithm is.

... lines 1 - 51
when@test:
security:
password_hashers:
# By default, password hashers are resource intensive and take time. This is
# important to generate secure password hashes. In tests however, secure hashes
# are not important, waste resources and increase test times. The following
# reduces the work factor to the lowest possible values.
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
algorithm: auto
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon

Let's add the files... then keep going.

symfony/translation Recipe

Next up is symfony/translation. This isn't important... it just shows off some new config options. Those are all commented out, so... they're cool to see, but not important.

framework:
... line 2
translator:
... lines 4 - 6
# providers:
# crowdin:
# dsn: '%env(CROWDIN_DSN)%'
# loco:
# dsn: '%env(LOCO_DSN)%'
# lokalise:
# dsn: '%env(LOKALISE_DSN)%'

Commit and... keep going!

symfony/validator Recipe

Next is symfony/validator. Simple! This moved the config from config/test/validator.yaml into the main validator.yaml.

Commit that!

symfony/web-profiler-bundle Recipe

Let's update one more recipe right now: web-profiler-bundle. Can you guess what it did? It added more environment-specific config. So the config from dev/web_profiler.yaml and test/web_profiler.yaml was moved into the main web_profiler.yaml. The same thing happened for routes. The config from dev was moved into a new config/routes/web_profiler.yaml. Let's commit that and... phew! We've almost done it! Just two recipes left!

Let's update those next. The WebpackEncoreBundle recipe will also give us a chance to upgrade our JavaScript to the new Stimulus 3 version.

Leave a comment!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^8.0.2",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.6", // v3.6.1
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.5
        "doctrine/annotations": "^1.13", // 1.13.2
        "doctrine/dbal": "^3.3", // 3.3.5
        "doctrine/doctrine-bundle": "^2.0", // 2.6.2
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.0", // 2.11.2
        "knplabs/knp-markdown-bundle": "^1.8", // 1.10.0
        "knplabs/knp-time-bundle": "^1.18", // v1.18.0
        "pagerfanta/doctrine-orm-adapter": "^3.6", // v3.6.1
        "pagerfanta/twig": "^3.6", // v3.6.1
        "sensio/framework-extra-bundle": "^6.0", // v6.2.6
        "sentry/sentry-symfony": "^4.0", // 4.2.8
        "stof/doctrine-extensions-bundle": "^1.5", // v1.7.0
        "symfony/asset": "6.0.*", // v6.0.7
        "symfony/console": "6.0.*", // v6.0.7
        "symfony/dotenv": "6.0.*", // v6.0.5
        "symfony/flex": "^2.1", // v2.1.7
        "symfony/form": "6.0.*", // v6.0.7
        "symfony/framework-bundle": "6.0.*", // v6.0.7
        "symfony/mailer": "6.0.*", // v6.0.5
        "symfony/monolog-bundle": "^3.0", // v3.7.1
        "symfony/property-access": "6.0.*", // v6.0.7
        "symfony/property-info": "6.0.*", // v6.0.7
        "symfony/proxy-manager-bridge": "6.0.*", // v6.0.6
        "symfony/routing": "6.0.*", // v6.0.5
        "symfony/runtime": "6.0.*", // v6.0.7
        "symfony/security-bundle": "6.0.*", // v6.0.5
        "symfony/serializer": "6.0.*", // v6.0.7
        "symfony/stopwatch": "6.0.*", // v6.0.5
        "symfony/twig-bundle": "6.0.*", // v6.0.3
        "symfony/ux-chartjs": "^2.0", // v2.1.0
        "symfony/validator": "6.0.*", // v6.0.7
        "symfony/webpack-encore-bundle": "^1.7", // v1.14.0
        "symfony/yaml": "6.0.*", // v6.0.3
        "symfonycasts/verify-email-bundle": "^1.7", // v1.10.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.8
        "twig/string-extra": "^3.3", // v3.3.5
        "twig/twig": "^2.12|^3.0" // v3.3.10
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.1
        "phpunit/phpunit": "^9.5", // 9.5.20
        "rector/rector": "^0.12.17", // 0.12.20
        "symfony/debug-bundle": "6.0.*", // v6.0.3
        "symfony/maker-bundle": "^1.15", // v1.38.0
        "symfony/var-dumper": "6.0.*", // v6.0.6
        "symfony/web-profiler-bundle": "6.0.*", // v6.0.6
        "zenstruck/foundry": "^1.16" // v1.18.0
    }
}