gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Fun fact time! When you start a brand new Symfony project, behind the scenes, what you're actually doing is cloning this repository: symfony/skeleton
. Yep, your app literally starts as a single composer.json
file. But as soon as Composer installs your dependencies, the app is suddenly filled with a few directories and about 15 files.
All of those things are added by different recipes. So even the most "core" files - for example, public/index.php
, the file that our web server executes, is added by a recipe!
... lines 1 - 2 | |
use App\Kernel; | |
use Symfony\Component\Debug\Debug; | |
use Symfony\Component\HttpFoundation\Request; | |
require dirname(__DIR__).'/config/bootstrap.php'; | |
if ($_SERVER['APP_DEBUG']) { | |
umask(0000); | |
Debug::enable(); | |
} | |
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? $_ENV['TRUSTED_PROXIES'] ?? false) { | |
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST); | |
} | |
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? $_ENV['TRUSTED_HOSTS'] ?? false) { | |
Request::setTrustedHosts([$trustedHosts]); | |
} | |
$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); | |
$request = Request::createFromGlobals(); | |
$response = $kernel->handle($request); | |
$response->send(); | |
$kernel->terminate($request, $response); |
We pretty much never need to look inside here or do anything, even though it's critical to our app working.
Another example is config/bootstrap.php
:
... lines 1 - 2 | |
use Symfony\Component\Dotenv\Dotenv; | |
require dirname(__DIR__).'/vendor/autoload.php'; | |
// Load cached env vars if the .env.local.php file exists | |
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2) | |
if (is_array($env = @include dirname(__DIR__).'/.env.local.php')) { | |
$_SERVER += $env; | |
$_ENV += $env; | |
} elseif (!class_exists(Dotenv::class)) { | |
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); | |
} else { | |
$path = dirname(__DIR__).'/.env'; | |
$dotenv = new Dotenv(); | |
// load all the .env files | |
if (method_exists($dotenv, 'loadEnv')) { | |
$dotenv->loadEnv($path); | |
} else { | |
// fallback code in case your Dotenv component is not 4.2 or higher (when loadEnv() was added) | |
if (file_exists($path) || !file_exists($p = "$path.dist")) { | |
$dotenv->load($path); | |
} else { | |
$dotenv->load($p); | |
} | |
if (null === $env = $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) { | |
$dotenv->populate(array('APP_ENV' => $env = 'dev')); | |
} | |
if ('test' !== $env && file_exists($p = "$path.local")) { | |
$dotenv->load($p); | |
$env = $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env; | |
} | |
if (file_exists($p = "$path.$env")) { | |
$dotenv->load($p); | |
} | |
if (file_exists($p = "$path.$env.local")) { | |
$dotenv->load($p); | |
} | |
} | |
} | |
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev'; | |
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; | |
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; |
the boring, low-level file that initializes and normalizes environment variables. It's important that all Symfony projects have the same version of this file. If they didn't, some apps might work different than others... even if they have the same version of Symfony. Think of trying to write documentation for thousands of projects that all work a little bit differently. It's literally my nightmare.
All of the configuration files were also originally added by recipes. For example, cache.yaml
comes from the recipe for symfony/framework-bundle
:
framework: | |
cache: | |
... lines 3 - 13 | |
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) | |
app: '%cache_adapter%' | |
# Namespaced pools use the above "app" backend by default | |
pools: | |
cache.flysystem.psr6: | |
adapter: cache.app |
Over time, the recipes themselves tend to change. If we installed the symfony/framework-bundle
today, it might give us a slightly different cache.yaml
file.
There are three reasons that a recipe might change. First, someone might update a recipe just because they want to add more examples or add some documentation comments to a config file. Those changes... aren't super important.
Or, second, someone might update a configuration file inside a recipe to activate a new feature that's probably from a new version of that library. These changes aren't critical to know about... but it is nice to know if a great new feature is suddenly available. We saw that a few minutes ago when the updated MonologBundle recipe told us about a cool option for filtering logs by status code.
The third reason a recipe might update is because something needs to be fixed, or we decide that we want to change some significant behavior. These changes are important.
Let me give you an example: during the first year after Symfony 4.0, several small but meaningful tweaks were made to the bootstrap.php
file to make sure that environment variables have just the right behavior. If you started your project on Symfony 4.0 and never "updated" the bootstrap.php
file, your app will be handling environment variables in a different way than other apps. That's... not great: we want our bootstrap.php
file to look exactly like it should.
A few minutes ago, when we did all the composer updating stuff, one of the packages that we upgraded was symfony/flex
itself: we upgraded it to 1.6.0
:
{ | |
... lines 2 - 3 | |
"require": { | |
... lines 5 - 24 | |
"symfony/flex": "^1.0", | |
... lines 26 - 43 | |
}, | |
... lines 45 - 102 | |
} |
Well guess what?! Starting in Flex 1.6.0
, there are some brand new fancy, amazing, incredible commands inside Composer to help inspect & upgrade recipes. It still takes a little bit of work and care, but the process is now very possible. A big thanks to community member and friend maxhelias who really helped to get this done.
Let's go check them out! Move over to your terminal and run:
composer recipes
Cool! This lists every recipe that we have installed and whether or not there is an update available. Heck, it will even show you if a package that's installed has a recipe that you're missing - maybe because it was added later.
Because my project was originally created on Symfony 4.0, it's fairly old and a lot of recipes have updates. The recipe system is also relatively new, so I think there were more updates during the first 2 years of that system than there will be in the next two years. We've got some work to do. Of course, we could just ignore these recipe updates... but we're risking our app not working quite right or missing info about new features.
Let's look at one of these more closely. How about twig/extensions
. This is not a particularly important library, but it's a nice one to start with. Run:
composer recipes twig/extensions
to see more details. Interesting: it has a link to the installed version of the recipe. Let's go check that out in the browser. Paste and... this is what the recipe looked like the moment we installed it. We can also go grab the URL to see what the latest version of the recipe looks like.
Check out the commit history. The version of the recipe we have installed has a commit hash starting with c986
. Back on the history, hey! That commit is right here! So this recipe is out of date, but the only change that's been made is this one commit. Inside it... search for twig/extensions
to find its changes. Ha! It's totally superficial: we changed from using tilde (~
) to null
... but just for clarity: those are equivalent in YAML.
Yep! The update to twig/extension
is not important at all. We could still update it - and I'll show you how next. But I'm going to skip it for now. Because... this is a tutorial about upgrading Symfony! So I want to focus on upgrading the recipes for everything that starts with symfony/
.
Let's start that process next by focusing on, surprisingly, one of the most important recipes: symfony/console
.
Hey Dave,
I'm sorry you confused about it. Nope, Flex was introduced long time ago in Symfony 3.4. So, it should work in Symfony 4 and 5. If you do not see '(Update Available)' next to your recipe list - probably you really don't have any updates? It makes sense if you create your project from scratch to follow the course instead of downloading course code and start from "start/" directory with us. When you do "composer recipe:install symfony/console --force -v" - --force ignores the "symfony.lock" file and overwrite existing files. Basically, it just reinstall the recipes you already have installed and override your custom changes with default ones. So, if you have some diff after running this command with --force - it might not mean you have some new changes, you just might reset file content to defaults one.
My guess is that you have started a new Symfony 4.4 project from scratch to follow the tutorial and of course it installs all the fresh recipes during the project creation, so no updates for you (yet). You can "wait" for some updates :) or you can download course code instead and start from start/ directory if you want to practice recipe updates right now and don't want to wait for available updates for your new project.
I hope this helps!
Cheers!
Cheers!
Hi,
Thank you for this symfony upgrade series, really interesting. But when I do execute composer recipes I got this error message:
https://ibb.co/KLKq1Xb
Here if you can't see the image:
[Symfony\Component\Console\Exception\CommandNotFoundException]
Command "recipes" is not defined.
Did you mean one of these?
sync-recipes
fix-recipes
symfony:sync-recipes
My Symfony version is 4.3
Hey Rakodev!
Try updating symfony/flex
:
composer update symfony/flex
We added the new commands used in this course in version 1.6.0. Let me know if that helps!
Cheers!
// composer.json
{
"require": {
"php": "^7.3.0",
"ext-iconv": "*",
"antishov/doctrine-extensions-bundle": "^1.4", // v1.4.2
"aws/aws-sdk-php": "^3.87", // 3.110.11
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^2.0", // 2.0.6
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // 2.1.2
"doctrine/orm": "^2.5.11", // v2.7.2
"doctrine/persistence": "^1.3.7", // 1.3.8
"easycorp/easy-log-handler": "^1.0", // v1.0.9
"http-interop/http-factory-guzzle": "^1.0", // 1.0.0
"knplabs/knp-markdown-bundle": "^1.7", // 1.8.1
"knplabs/knp-paginator-bundle": "^5.0", // v5.0.0
"knplabs/knp-snappy-bundle": "^1.6", // v1.7.0
"knplabs/knp-time-bundle": "^1.8", // v1.11.0
"league/flysystem-aws-s3-v3": "^1.0", // 1.0.23
"league/flysystem-cached-adapter": "^1.0", // 1.0.9
"league/html-to-markdown": "^4.8", // 4.8.2
"liip/imagine-bundle": "^2.1", // 2.3.0
"nexylan/slack-bundle": "^2.1", // v2.2.1
"oneup/flysystem-bundle": "^3.0", // 3.3.0
"php-http/guzzle6-adapter": "^2.0", // v2.0.1
"sensio/framework-extra-bundle": "^5.1", // v5.5.3
"symfony/asset": "5.0.*", // v5.0.2
"symfony/console": "5.0.*", // v5.0.2
"symfony/dotenv": "5.0.*", // v5.0.2
"symfony/flex": "^1.0", // v1.17.6
"symfony/form": "5.0.*", // v5.0.2
"symfony/framework-bundle": "5.0.*", // v5.0.2
"symfony/mailer": "5.0.*", // v5.0.2
"symfony/messenger": "5.0.*", // v5.0.2
"symfony/monolog-bundle": "^3.5", // v3.5.0
"symfony/security-bundle": "5.0.*", // v5.0.2
"symfony/sendgrid-mailer": "5.0.*", // v5.0.2
"symfony/serializer-pack": "^1.0", // v1.0.2
"symfony/twig-bundle": "5.0.*", // v5.0.2
"symfony/twig-pack": "^1.0", // v1.0.0
"symfony/validator": "5.0.*", // v5.0.2
"symfony/webpack-encore-bundle": "^1.4", // v1.7.2
"symfony/yaml": "5.0.*", // v5.0.2
"twig/cssinliner-extra": "^2.12", // v2.12.0
"twig/extensions": "^1.5", // v1.5.4
"twig/inky-extra": "^2.12" // v2.12.0
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.3.0
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/browser-kit": "5.0.*", // v5.0.2
"symfony/debug-bundle": "5.0.*", // v5.0.2
"symfony/maker-bundle": "^1.0", // v1.14.3
"symfony/phpunit-bridge": "5.0.*", // v5.0.2
"symfony/profiler-pack": "^1.0", // v1.0.4
"symfony/var-dumper": "5.0.*" // v5.0.2
}
}
So I'm confused. Will 'composer recipes' only work properly if you have upgraded to 5.0?
I do not see '(Update Available)' next to any recipe in my Symfony 4.4 project, but if I run
composer recipe:install symfony/console --force -v
, bootstrap.php and console files update. symfony.lock indicates change from version 4.3.9 to 4.4.4.When I run
composer recipes symfony/console
I see:name : symfony/console
version : 4.4.4
status : auto-generated recipe
files :
├──bin
│ └──console
└──config
└──bootstrap.php
No indication of installed or current. All of the installed recipes provide similar results. All status = 'auto-generated recipe'.
Composer version 1.9.3 2020-02-04 12:58:49
Symfony Version 4.4