|
| 1 | +Symfony Flex Recipes |
| 2 | +==================== |
| 3 | + |
| 4 | +`Symfony Flex`_ is the new way to manage dependencies in Symfony applications. |
| 5 | +One of its main features is the automatic installation, configuration and |
| 6 | +removal of dependencies. This automation is possible thanks to the **Symfony Flex |
| 7 | +Recipes**. |
| 8 | + |
| 9 | +Creating Flex Recipes |
| 10 | +--------------------- |
| 11 | + |
| 12 | +Symfony Flex recipes consist of a ``manifest.json`` config file and, optionally, |
| 13 | +any number of files and directories. Recipes must be stored on their own |
| 14 | +repositories, outside of your Composer package repository. They must follow the |
| 15 | +``vendor/package/version/`` directory structure, where ``version`` is the |
| 16 | +minimum version supported by the recipe. |
| 17 | + |
| 18 | +The following example shows the real directory structure of some Symfony recipes: |
| 19 | + |
| 20 | +:: |
| 21 | + |
| 22 | + symfony/ |
| 23 | + console/ |
| 24 | + 3.3/ |
| 25 | + bin/ |
| 26 | + manifest.json |
| 27 | + framework-bundle/ |
| 28 | + 3.3/ |
| 29 | + etc/ |
| 30 | + src/ |
| 31 | + web/ |
| 32 | + manifest.json |
| 33 | + requirements-checker/ |
| 34 | + 1.0/ |
| 35 | + manifest.json |
| 36 | + |
| 37 | +All the ``manifest.json`` file contents are optional and they are divided into |
| 38 | +options and configurators. |
| 39 | + |
| 40 | +Options |
| 41 | +------- |
| 42 | + |
| 43 | +``aliases`` option |
| 44 | +~~~~~~~~~~~~~~~~~~ |
| 45 | + |
| 46 | +This option defines one or more alternative names that can be used to install |
| 47 | +the dependency. Its value is an array of strings. For example, if a dependency |
| 48 | +is published as ``acme-inc/acme-log-monolog-handler``, it can define one or |
| 49 | +more aliases to make it easier to install: |
| 50 | + |
| 51 | +.. code-block:: json |
| 52 | +
|
| 53 | + { |
| 54 | + "aliases": ["acme-log", "acmelog"] |
| 55 | + } |
| 56 | +
|
| 57 | +Developers can now install this dependency with ``composer require acme-log``. |
| 58 | + |
| 59 | +``version_aliases`` option |
| 60 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 61 | + |
| 62 | +This option lists all the additional dependency versions (using the ``x.y`` |
| 63 | +format) that work with this very same recipe. This avoids duplicating recipes |
| 64 | +when a new version of the package is released: |
| 65 | + |
| 66 | +.. code-block:: json |
| 67 | +
|
| 68 | + // vendor/package-name/3.2/manifest.json |
| 69 | + { |
| 70 | + "version_aliases": ["3.3", "3.4", "4.0"] |
| 71 | + } |
| 72 | +
|
| 73 | +.. note:: |
| 74 | + |
| 75 | + When using ``version_aliases``, the directory where the recipe is defined |
| 76 | + must be the oldest supported version (``3.2`` in the previous example). |
| 77 | + |
| 78 | +Configurators |
| 79 | +------------- |
| 80 | + |
| 81 | +Recipes define the different tasks executed when installing a dependency, such |
| 82 | +as running commands, copying files or adding new environment variables. Recipes |
| 83 | +only contain the tasks needed to install and configure the dependency because |
| 84 | +Symfony Flex is smart enough to reverse those tasks when uninstalling and |
| 85 | +unconfiguring the dependencies. |
| 86 | + |
| 87 | +Symfony Flex provides eight types of tasks, which are called **configurators**: |
| 88 | +``copy-from-recipe``, ``copy-from-package``, ``bundles``, ``env``, ``makefile``, |
| 89 | +``composer-scripts``, ``gitignore``, and ``post-install-output``. |
| 90 | + |
| 91 | +``bundles`` Configurator |
| 92 | +~~~~~~~~~~~~~~~~~~~~~~~~ |
| 93 | + |
| 94 | +Enables one or more bundles in the Symfony application by appending them to the |
| 95 | +``bundles.php`` file. Its value is an associative array where the key is the |
| 96 | +bundle class name and the value is an array of environments where it must be |
| 97 | +enabled. The supported environments are ``dev``, ``prod``, ``test`` and ``all`` |
| 98 | +(which enables the bundle in all environments): |
| 99 | + |
| 100 | +.. code-block:: json |
| 101 | +
|
| 102 | + { |
| 103 | + "bundles": { |
| 104 | + "Symfony\\Bundle\\DebugBundle\\DebugBundle": ["dev", "test"], |
| 105 | + "Symfony\\Bundle\\MonologBundle\\MonologBundle": ["all"] |
| 106 | + } |
| 107 | + } |
| 108 | +
|
| 109 | +The previous recipe is transformed by Symfony Flex into the following PHP code: |
| 110 | + |
| 111 | +.. code-block:: php |
| 112 | +
|
| 113 | + // etc/bundles.php |
| 114 | + return [ |
| 115 | + 'Symfony\Bundle\DebugBundle\DebugBundle' => ['dev' => true, 'test' => true], |
| 116 | + 'Symfony\Bundle\MonologBundle\MonologBundle' => ['all' => true], |
| 117 | + ]; |
| 118 | +
|
| 119 | +``copy-from-package`` Configurator |
| 120 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 121 | + |
| 122 | +Copies files or directories from the Composer package contents to the Symfony |
| 123 | +application. It's defined as an associative array where the key is the original |
| 124 | +file/directory and the value is the target file/directory. |
| 125 | + |
| 126 | +This example copies the ``bin/check.php`` script of the package into the binary |
| 127 | +directory of the application: |
| 128 | + |
| 129 | +.. code-block:: json |
| 130 | +
|
| 131 | + { |
| 132 | + "copy-from-package": { |
| 133 | + "bin/check.php": "%BIN_DIR%/check.php" |
| 134 | + } |
| 135 | + } |
| 136 | +
|
| 137 | +The ``%BIN_DIR%`` string is a special value that it's turned into the absolute |
| 138 | +path of the binaries directory of the Symfony application. These are the special |
| 139 | +variables available: ``%BIN_DIR%``, ``%CONF_DIR%``, ``%ETC_DIR%``, ``%SRC_DIR%`` |
| 140 | +and ``%WEB_DIR%``. You can also access to any variable defined in the ``extra`` |
| 141 | +section of your ``composer.json`` file: |
| 142 | + |
| 143 | +.. code-block:: json |
| 144 | +
|
| 145 | + // composer.json |
| 146 | + { |
| 147 | + "...": "...", |
| 148 | +
|
| 149 | + "extra": { |
| 150 | + "my-special-dir": "..." |
| 151 | + } |
| 152 | + } |
| 153 | +
|
| 154 | +Now you can use ``%MY_SPECIAL_DIR%`` in your Symfony Flex recipes. |
| 155 | + |
| 156 | +``copy-from-recipe`` Configurator |
| 157 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 158 | + |
| 159 | +It's identical to ``copy-from-package`` but contents are copied from the recipe |
| 160 | +itself instead of from the Composer package contents. It's useful to copy the |
| 161 | +initial configuration of the dependency and even a simple initial structure of |
| 162 | +files and directories: |
| 163 | + |
| 164 | +.. code-block:: json |
| 165 | +
|
| 166 | + "copy-from-recipe": { |
| 167 | + "etc/": "%ETC_DIR%/", |
| 168 | + "src/": "%SRC_DIR%/" |
| 169 | + } |
| 170 | +
|
| 171 | +``env`` Configurator |
| 172 | +~~~~~~~~~~~~~~~~~~~~ |
| 173 | + |
| 174 | +Adds the given list of environment variables to the ``.env`` and ``.env.dist`` |
| 175 | +files stored in the root of the Symfony project: |
| 176 | + |
| 177 | +.. code-block:: json |
| 178 | +
|
| 179 | + { |
| 180 | + "env": { |
| 181 | + "APP_ENV": "dev", |
| 182 | + "APP_DEBUG": "1" |
| 183 | + } |
| 184 | + } |
| 185 | +
|
| 186 | +Symfony Flex turns that recipe into the following content appended to the ``.env`` |
| 187 | +and ``.env.dist`` files: |
| 188 | + |
| 189 | +.. code-block:: bash |
| 190 | +
|
| 191 | + ###> your-recipe-name-here ### |
| 192 | + APP_ENV=dev |
| 193 | + APP_DEBUG=1 |
| 194 | + ###< your-recipe-name-here ### |
| 195 | +
|
| 196 | +The ``###> your-recipe-name-here ###`` section separators are needed by |
| 197 | +Symfony Flex to detect the contents added by this dependency in case you |
| 198 | +uninstall it later. Don't remove or modify these separators. |
| 199 | + |
| 200 | +``makefile`` Configurator |
| 201 | +~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 202 | + |
| 203 | +Adds new tasks to the ``Makefile`` file stored in the root of the Symfony project. |
| 204 | +The value is a simple array where each element is a new line (Symfony Flex adds |
| 205 | +a ``PHP_EOL`` character after each line): |
| 206 | + |
| 207 | +.. code-block:: json |
| 208 | +
|
| 209 | + { |
| 210 | + "makefile": [ |
| 211 | + "cache-clear:", |
| 212 | + "\t@test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*", |
| 213 | + ".PHONY: cache-clear", |
| 214 | + ] |
| 215 | + } |
| 216 | +
|
| 217 | +Similar to the ``env`` configurator, the contents are copied into the ``Makefile`` |
| 218 | +file and wrapped with section separators (``###> your-recipe-name-here ###``) |
| 219 | +that must not be removed or modified. |
| 220 | + |
| 221 | +``composer-scripts`` Configurator |
| 222 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 223 | + |
| 224 | +Registers scripts in the ``auto-scripts`` section of the ``composer.json`` file |
| 225 | +to execute them automatically when running ``composer install`` and ``composer |
| 226 | +update``. The value is an associative array where the key is the script to |
| 227 | +execute (including all its arguments and options) and the value is the type of |
| 228 | +script (``php-script`` for PHP scripts, ``script`` for any shell script and |
| 229 | +``symfony-cmd`` for Symfony commands): |
| 230 | + |
| 231 | +.. code-block:: json |
| 232 | +
|
| 233 | + { |
| 234 | + "composer-scripts": { |
| 235 | + "vendor/bin/security-checker security:check": "php-script", |
| 236 | + "make cache-warmup": "script", |
| 237 | + "assets:install --symlink --relative %WEB_DIR%": "symfony-cmd" |
| 238 | + } |
| 239 | + } |
| 240 | +
|
| 241 | +``gitignore`` Configurator |
| 242 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 243 | + |
| 244 | +Adds patterns to the ``.gitignore`` file of the Symfony project. Define those |
| 245 | +patterns as a simple array of strings (Symfony Flex adds a ``PHP_EOL`` character |
| 246 | +after each line): |
| 247 | + |
| 248 | +.. code-block:: json |
| 249 | +
|
| 250 | + { |
| 251 | + "gitignore": [ |
| 252 | + ".env", |
| 253 | + "/var/", |
| 254 | + "/vendor/", |
| 255 | + "/web/bundles/" |
| 256 | + ] |
| 257 | + } |
| 258 | +
|
| 259 | +Similar to other configurators, the contents are copied into the ``.gitignore`` |
| 260 | +file and wrapped with section separators (``###> your-recipe-name-here ###``) |
| 261 | +that must not be removed or modified. |
| 262 | + |
| 263 | +``post-install-output`` Configurator |
| 264 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 265 | + |
| 266 | +Displays contents in the command console after the package has been installed. |
| 267 | +Avoid outputting meaningless information and use it only when you need to show |
| 268 | +help messages or the next step actions. |
| 269 | + |
| 270 | +The contents are defined as a simple array of strings (Symfony Flex adds a |
| 271 | +``PHP_EOL`` character after each line). `Symfony Console styles and colors`_ |
| 272 | +are supported too: |
| 273 | + |
| 274 | +.. code-block:: json |
| 275 | +
|
| 276 | + { |
| 277 | + "post-install-output": [ |
| 278 | + "<fg=blue> What's next? </>", |
| 279 | + "", |
| 280 | + " * <fg=blue>Run</> your application:", |
| 281 | + " 1. Execute the <comment>make serve</comment> command;", |
| 282 | + " 2. Browse to the <comment>http://localhost:8000/</comment> URL.", |
| 283 | + "", |
| 284 | + " * <fg=blue>Read</> the documentation at <comment>https://symfony.com/doc</comment>" |
| 285 | + ] |
| 286 | + } |
| 287 | +
|
| 288 | +Full Example |
| 289 | +------------ |
| 290 | + |
| 291 | +Combining all the above configurators you can define powerful recipes, like the |
| 292 | +one used by ``symfony/framework-bundle``: |
| 293 | + |
| 294 | +.. code-block:: json |
| 295 | +
|
| 296 | + { |
| 297 | + "bundles": { |
| 298 | + "Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle": ["all"] |
| 299 | + }, |
| 300 | + "copy-from-recipe": { |
| 301 | + "etc/": "%ETC_DIR%/", |
| 302 | + "src/": "%SRC_DIR%/", |
| 303 | + "web/": "%WEB_DIR%/" |
| 304 | + }, |
| 305 | + "composer-scripts": { |
| 306 | + "make cache-warmup": "script", |
| 307 | + "assets:install --symlink --relative %WEB_DIR%": "symfony-cmd" |
| 308 | + }, |
| 309 | + "env": { |
| 310 | + "APP_ENV": "dev", |
| 311 | + "APP_DEBUG": "1", |
| 312 | + "APP_SECRET": "Ju$tChang3it!" |
| 313 | + }, |
| 314 | + "makefile": [ |
| 315 | + "cache-clear:", |
| 316 | + "\t@test -f bin/console && bin/console cache:clear --no-warmup || rm -rf var/cache/*", |
| 317 | + ".PHONY: cache-clear", |
| 318 | + "", |
| 319 | + "cache-warmup: cache-clear", |
| 320 | + "\t@test -f bin/console && bin/console cache:warmup || echo \"cannot warmup the cache (needs symfony/console)\"", |
| 321 | + ".PHONY: cache-warmup", |
| 322 | + "", |
| 323 | + "serve:", |
| 324 | + "\t@echo \"\\033[32;49mServer listening on http://127.0.0.1:8000\\033[39m\"", |
| 325 | + "\t@echo \"Quit the server with CTRL-C.\"", |
| 326 | + "\t@echo \"Run \\033[32mcomposer require symfony/web-server-bundle\\033[39m for a better web server\"", |
| 327 | + "\tphp -S 127.0.0.1:8000 -t web", |
| 328 | + ".PHONY: serve" |
| 329 | + ], |
| 330 | + "gitignore": [ |
| 331 | + ".env", |
| 332 | + "/var/", |
| 333 | + "/vendor/", |
| 334 | + "/web/bundles/" |
| 335 | + ], |
| 336 | + "post-install-output": [ |
| 337 | + "<bg=blue;fg=white> </>", |
| 338 | + "<bg=blue;fg=white> What's next? </>", |
| 339 | + "<bg=blue;fg=white> </>", |
| 340 | + "", |
| 341 | + " * <fg=blue>Run</> your application:", |
| 342 | + " 1. Execute the <comment>make serve</comment> command;", |
| 343 | + " 2. Browse to the <comment>http://localhost:8000/</comment> URL.", |
| 344 | + "", |
| 345 | + " * <fg=blue>Read</> the documentation at <comment>https://symfony.com/doc</comment>" |
| 346 | + ] |
| 347 | + } |
| 348 | +
|
| 349 | +.. _`Symfony Flex`: https://github.com/symfony/flex |
| 350 | +.. _`Symfony Console styles and colors`: https://symfony.com/doc/current/console/coloring.html |
0 commit comments