Home » Php » php – How write a Symfony Flex recipe for a new bundle?

php – How write a Symfony Flex recipe for a new bundle?

Posted by: admin July 12, 2020 Leave a comment

Questions:

I tried to find any documentation about using Symfony Flex but so far no luck.

Almost all docs point to installing a bundle that uses symfony Flex, not how to create a bundle that is using it.

I even tried to reverse engineer some of the packages but again, no luck.

My goal is to generate a default configuration file for my bundle in config/packages/my_bundle.yaml.

What I need to know is where do I need to put it and what env variables (if any) will I have available?

How to&Answers:

What is a Flex Recipe?

Keep in mind that the flex recipe is a separate repository from your package repository, that needs to be hosted on a Flex server. The process make recipes much less useful for third party bundles, IMO. It’s very neat for “official” Symfony recipes, but not so much for other users.

Most likely, you’ll have to submit your recipe to the contrib repository, get it approved and merged so it’s available as a community recipe. (The other option would be to have a self-hosted Flex server, but that’s only useful while testing the recipe, if necessary).

Additionally, it’s important to remember that most users will not have the contrib repository enabled by default. So if this is important for installing this bundle, you should tell your users how to do so before they install your recipe (e.g. in your bundle’s readme file).

With that out of the way: Basically, a Flex recipe is a repository with a manifest.json file with specific keys to enable certain “configurators”.

The available manifest.json configurators are:

Bundles

Which bundles should be enabled on bundles.php. These are added when the recipe is installed, and removed when the recipe is uninstalled.

{
    "bundles": {
        "Symfony\Bundle\DebugBundle\DebugBundle": ["dev", "test"],
        "Symfony\Bundle\MonologBundle\MonologBundle": ["all"]
    }
}

Configuration

The “configuration” configurator deals with two keys: copy-from-recipe and copy-from-package. The first one can copy files from the recipe repository, the second one copies files from the package repository.

{
    "copy-from-package": {
        "bin/check.php": "%BIN_DIR%/check.php"
    },
    "copy-from-recipe": {
        "config/": "%CONFIG_DIR%/",
        "src/": "%SRC_DIR%/"
    }
}

In this example, a file bin/check.php in the package will be copied to the projects %BIN_DIR%, and the contents of config and src on the recipe package will be copied the corresponding directory.

This is the typical use case to provide default configuration files, for example. From what you ask, this is your stated purpose for wanting to create a flex recipe.

Env Vars

This configurator simply adds the appropriate environment variable values to the project’s .env and .env.dist. (Again, these would be removed if you uninstalled the recipe)

{
    "env": {
        "APP_ENV": "dev",
        "APP_DEBUG": "1"
    }
}

Composer Scripts

This configurator adds tasks to the scripts:auto-scripts array from the project’s composer.json. The auto-scripts are tasks that are executed every time composer update or composer install are executed in the project.

{
    "composer-scripts": {
        "vendor/bin/security-checker security:check": "php-script",
        "make cache-warmup": "script",
        "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
    }
}

The second part on each line specifies what kind of command it is: a regular PHP script (php-script), a shell script (script), or a Symfony command (symfony-cmd, executed via bin/console).

Gitignore

This will add entries to the project’s .gitignore file.

{
    "gitignore": [
        "/phpunit.xml"
    ]
}

A complete example of a manifest.json (lifted from here, as most other examples on this post):

{
    "bundles": {
        "Symfony\Bundle\FrameworkBundle\FrameworkBundle": ["all"]
    },
    "copy-from-recipe": {
        "config/": "%CONFIG_DIR%/",
        "public/": "%PUBLIC_DIR%/",
        "src/": "%SRC_DIR%/"
    },
    "composer-scripts": {
        "make cache-warmup": "script",
        "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd"
    },
    "env": {
        "APP_ENV": "dev",
        "APP_DEBUG": "1",
        "APP_SECRET": "%generate(secret)%"
    },
    "gitignore": [
        ".env",
        "/public/bundles/",
        "/var/",
        "/vendor/"
    ]
}

Additional configurators

There are two configurators which do not rely on the manifest.json file:

Post-install output.

If a file named post-install.txt exists in the recipe’s package, its content is displayed when installation is complete. You can even use styles as defined here, for additional prettiness/obnoxiousness.

Example:

<bg=green;fg=white>                </>
<bg=green;fg=white> Much success!! </>
<bg=green;fg=white>                </>

  * <fg=yellow>Next steps:</>
    1. Foo
    2. <comment>bar</>;
    3. Baz <comment>https://example.com/</>.

This will be presented to the user after the installation is complete.

Makefile

If a file named Makefile exists in the recipe’s repository, the tasks defined here would be added to the project’s Makefile (creating the Makefile if it didn’t exist).

cache-clear:
    @test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*
.PHONY: cache-clear

Simple as that. I guess than most packages would not need a makefile command, so this would have much less use than other configurators.

You can read the full documentation here.