There will be a situation, you want to benefit from the new Flex-Plugin for composer when using Symfony 4 and there is an internal Library which should not be published to public.
Good News: There is a possibility for a private Recipe Server which is still in BETA but works already very well.
What are Recipes?
Recipes are basically JSON files with a prescribed format. The files are downloaded and parsed on installation of the bundle with composer. Symfony 4 comes with the composer-extension „Flex“ preinstalled so you will be able to use Recipes there out of the box. I’ve tried to install flex-extension into an empty project and you would be also able to use flex without Symfony. At the moment, this would not make much sense, but there is the possibility for integration into other frameworks – so lets stay excited.
How does Symfony Flex work?
Symfony Flex is a basic composer plugin, if you want to know how composer-plugins work you can find further informations in the documentation. Flex itself is responsible to connect to the symfony.sh registry for recipes (which is similar to packagist.org for composer), it resolves if there are some offical – contrib or private recipes for the requested bundle.
Different types of recipes
There are three different types of recipes:
- Offical – Recipes created and approved by Symfony Core Team
Because of Flex can change your existing code and inject code into, this is done for security-reason. Recipes from this repository is automatically available after creating a Symfony 4 project.
- Contrib – User contributed recipes
This repository contains public recipes contributed by users. You will need to activate the contrib-repository before you are able to use recipes from here. There are some requirements to get your recipes merged, you can find them in the documentation.
- Private Recipes – Private Repository for your own recipes
This repository currently needs to rest on GitHub, connecting the flex-extension with symfony.sh to get recipes found is done using a GitHub Integration Application. I will explain this later on. The repository is not needed to be private to get this working, you will have to unlock each project by adding the symfony.id located in the composer.json by adding it to another configuration-file in the repository so at the end if the repository is public visible everyone can unlock his installation for your private recipes.
Afterwards the recipe on the lowest level (private > contrib > offical) will be downloaded and actions are performed like configured.
What is a Recipe?
A recipe is a JSON-File with a predefined structure it have to match to. Let’s have a look at an example:
This is an example how a recipe with some basic tasks like using an package-alias so you do not have to write „composer require sebtm/inwx-api-bundle“ instead you can write „composer require inwx-api“. At second Flex registers the Bundle to all environments. At the end it will append my new environment-variables into a new block which Flex also can automatically process in case of upgrade or uninstallation.
You can find further informations about recipes in the README file.
Setting up a Private Recipes Server
You will need an empty and (best case) private Repository on GitHub. Please use this link and active Symfony Recipe Server for your repository – please be careful and only active it on this single repository, otherwise this could lead to some problems with your non flex-recipe repositories.
Howto: Create a Recipe
For creating a recipe you will have to create the following folder-structure inside your recipe-repository:
<Vendor>/<BundleName>/<Version> e.g. for my InwxApiBundle it would be „SebTM/inwx-api-bundle/0.1“ where my tagged version originally was „v0.1.0“ but flex can match „0.1“ so this is fine. You could also make a recipe very specific like only for „0.1.0“ but you would need to update every time you publish a new bugfix release which normally should not require a new recipe. I made the decision if I change something which really has new requirements for the recipe I will bump up the minor-version of the recipe.
Inside the previously created folder, you will need to create a manifest.json – the file will contain the recipe-actions/configuration like shown in the third part of this post.
If you are finished, it’s important to commit/push the changes to a branch and make a pull-request for it. The Symfony Recipe Server Application we installed inn step four will automatically check the provided recipe and show you if there are any issues or not. This looks like here:
You can that I had an issue after the first commit and the bot automatically detected it – after I fixed it the state of the pull-request got updated and I merged it.
After installing the bundle using a recipe it’s possible to use it like a normal Symfony bundle as you already know it. In my case (the inwx-api) there will be a service announced by the bundle available for usage. I personally like the new Recipe system Symfony introduced, as it saves time and automates recurring tasks. It also helps to automize cleanup on uninstallation (the delta is resolved automatically from recipe so flex knows what to remove/change back) so if you switch to another dependency and uninstall one, you will be happy with a still clean project.