DEV Community

Andrew Markhai
Andrew Markhai

Posted on

4 1

How Symfony Flex Works

What is it?

Symfony Flex is a Composer plugin from Symfony that handles the configuration of installed packages. It adds configuration files, updates .gitignore and .env, registers bundles, and more.

For example, when installing PHPUnit, Flex will:

  • Add a default configuration file phpunit.dist.xml
  • Create tests/bootstrap.php
  • Add /phpunit.xml and /.phpunit.cache/ to .gitignore
  • Create .env.test with environment variables for tests

Where does Flex get its instructions?

In Flex terminology, these instructions are called recipes. They are stored in a GitHub repository. You can check out the recipes for the current version of PHPUnit here.

Is this a complete list of recipes?

No. The symfony/recipes repository is maintained by Symfony itself, while community-contributed recipes are stored in a separate repository. Anyone can contribute there.

To allow Flex to apply community recipes, you need to add the following to composer.json:

"extra": {
    "symfony": {
        "allow-contrib": true
    }
}
Enter fullscreen mode Exit fullscreen mode

How does it work under the hood?

When initialized, Flex loads links to all current recipes in Downloader::index. By default, it fetches them from two repositories described above:

private const DEFAULT_ENDPOINTS = [
'https://raw.githubusercontent.com/symfony/recipes/flex/main/index.json',
'https://raw.githubusercontent.com/symfony/recipes-contrib/flex/main/index.json',
];
Enter fullscreen mode Exit fullscreen mode

However, you can add your own repositories by specifying them in composer.json under extra.symfony.endpoint.

Since Flex is a Composer plugin, it listens for various events:

$events = [
    PackageEvents::POST_PACKAGE_UPDATE => 'enableThanksReminder',
    PackageEvents::POST_PACKAGE_INSTALL => 'recordFlexInstall',
    PackageEvents::POST_PACKAGE_UNINSTALL => 'record',
    InstallerEvents::PRE_OPERATIONS_EXEC => 'recordOperations',
    PluginEvents::PRE_POOL_CREATE => 'truncatePackages',
    ScriptEvents::POST_CREATE_PROJECT_CMD => 'configureProject',
    ScriptEvents::POST_INSTALL_CMD => 'install',
    ScriptEvents::PRE_UPDATE_CMD => 'configureInstaller',
    ScriptEvents::POST_UPDATE_CMD => 'update',
    'auto-scripts' => 'executeAutoScripts',
];
Enter fullscreen mode Exit fullscreen mode

During install and update commands, the Flex::install() method runs. It checks whether there are recipes for the current package by looking at both the package name and its version.

Recipe versioning is handled using subdirectories inside the package directory. For example, looking at PHPUnit’s recipes, you’ll see folders for versions 10.0, 9.6, 9.3, and 4.7. Flex selects the highest available recipe version that is less than or equal to the installed package version.

For example:

  • PHPUnit 12 will use the 10.0 recipe
  • PHPUnit 9.9 will use the 9.6 recipe

If a recipe is found, the instructions in its manifest are executed using various configurators. The console will display a message like:

Symfony operations: 1 recipe (13c8b05b36f03f13c596b688cb97d0da)
  - Configuring phpunit/phpunit (>=10.0): From github.com/symfony/recipes:main

Some files have been created and/or updated to configure your new packages.
Enter fullscreen mode Exit fullscreen mode

Useful commands

To check the current state of recipes:

composer symfony:recipes
Enter fullscreen mode Exit fullscreen mode

If a package has an updated recipe (marked as update available), you can update it with:

composer recipes:update vendor/package
Enter fullscreen mode Exit fullscreen mode

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay