Resolving Composer dependency issues with Drupal updates
Part of Drupal’s effort to be more in line with the greater PHP community was the move to use Composer to manage PHP dependencies. The idea is that instead of having to commit all of the Drupal code to your version control system, you simply check in the code specific to your site (mostly the ‘sites’ directory), along with your composer.json and composer.lock files, which then declare the PHP dependencies (including all of your contrib modules and themes). Then you are simply able to run 'composer install' to install all dependencies at once.
Most of the time, the composer update process will run without any issues. Once in a while, you will end up running into conflicts - and may get an error like this:
Your requirements could not be resolved to an installable set of packages.
This line would then be followed by a long list of package dependencies that clashed with one another. One package might require a different version of another package than what is required by another package, or does not match what you have spcified through version constraints in your composer.json file. This state of conflict is sometimes referred to as "dependency hell". Here's an example:
- drupal/core 8.4.x-dev requires symfony/class-loader ~3.2.8 -> satisfiable by symfony/class-loader[3.2.x-dev, v3.2.10, v3.2.11, v3.2.12, v3.2.13, v3.2.8, v3.2.9].
- Can only install one of: symfony/class-loader[3.2.x-dev, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.10, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.11, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.12, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.13, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.8, v2.8.28].
- Can only install one of: symfony/class-loader[v3.2.9, v2.8.28].
- Installation request for symfony/class-loader (locked at v2.8.28) -> satisfiable by symfony/class-loader[v2.8.28].
Installation failed, reverting ./composer.json to its original content.
There can often be many issues that are preventing you from performing an update - I'll run through the most common issues here.
PHP version platform constraint
I originally ran into the "dependency hell" issue early on in Drupal 8's history, when updating a client’s website from 8.3.7 to 8.4. I spent some time on Drupal.org reserching the issue, and found this issue thread, which gives some suggestions for switching up your Composer dependencies to get around this mess. After a few hours I was able to get it working on my local dev environment (a PHP 7 based Vagrant virtual machine).
To throw an extra wrench into the spokes, I remembered that the production web server was running PHP 5.6. The server could not be immediately updated to PHP 7 due to the fact that other sites are also running on the server that would require compatibility testing before upgrading PHP. This meant that I could not have any PHP dependencies on the site that required PHP 7 or higher.
So after talking with some excellent folks on the Drupal Support group on Facebook, and consulting the Composer documentation, I found a way to declare a constraint for the PHP version, adding a platform setting to the config section of composer.json:
"config": {
"platform": {
"php": "5.6"
}
}
That solved the first problem of ensuring only packages compatible with PHP 5.6 were used.
Using the right packages for Drupal core
In the early days of Drupal 8, sites were installed using the drupal-composer/drupal-project
template, which in turn used drupal/core as the main dependency for Drupal core. This caused some issues with updating core, where Drupal and its dependencies were not using the verified package versions from drupal.org's automated tests for core.
At the time, the community came up with a solution for this: the webflo/drupal-core-strict
package. However this was highly tied to Drupal 8.4 requirements, and was not maintained beyond that version.
Luckily, the Drupal core maintainers created a new set of meta-packages, and a new project template, in order to deal with this issue going forward.
The new drupal/recommended-project template is now the reccommended way to crete a Drupal project using Composer. It in turn splits the core requirements into 3 meta-packages:
- drupal/core-composer-scaffold - a Composer plugin for placing scaffold files (like
index.php
,update.php
, …) from thedrupal/core
project into their desired location inside the web root. - drupal/core-project-message - a Composer plugin that displays a configurable message after Composer installation processes have finished.
- drupal/core-recommended - require this project instead of drupal/core in order to guarantee that all of the dependencies from
drupal/core
will be included in your Drupal site at exactly the same version that was tested with the version of Drupal you are currently using.
If your project's composer.json has drupal/core in its dependencies, you will want to remove that and replace it with these new metapackages.
composer remove drupal/core
composer require drupal/core-recommended
composer require drupal/core-composer-scaffold
The 'drupal/core-project-message' package is not strictly required, but can be useful if you want it to print out messages when installing.
composer require drupal/core-project-message
Changing the minimum package stability requirement
Sometimes one of the packahges you need may have a compatible update, but only in a dev branch. If your composer.json has the minimum-stability config set to "stable", you will only get stable releases. You can change this value to one of these options (in order of stability): dev
, alpha
, beta
, RC
, and stable
.
I hope this helps everyone out there trying to perform Drupal updates via Composer.