Composer & Drupal for Beginners
Most software projects in the PHP ecosystem, including Drupal, can be installed and managed by using Composer, the PHP dependency manager.
A dependency manager is a software tool that reads a configuration file for a project. Then it determines all of the underlying software that the project needs in order to work, along with what versions of those applications are compatible with all parts of the project. This sort of work would be difficult to do manually for a project with more than a handful of dependencies.
Why Drupal 8 Needs Composer?
Since adopting this idea of “Proudly Built Elsewhere”, the Drupal project has incorporated many Symfony components and other libraries as dependencies for the project. Doing this allows Drupal to focus more energy on things that make Drupal unique. All of the basic things that all CMS’s do like Routing, Http Requests, and Validation can be handled by Symfony components. Composer simplifies the process of determining what the dependencies are, what version should be used, downloading the dependencies, and placing them in the project where they are expected.
The most obvious “con” of using Composer is needing to learn a new thing. For developers, this is not so much a “con” because learning new technologies is what we do for a living. But for someone who usually downloads Wordpress and FTPs it into a hosting account, the hurdle of Composer is significant.
Before any of this will work you will need to:
- Install Composer: https://getcomposer.org/download/, and
- Get your Drupal project setup: https://www.drupal.org/docs/develop/using-composer/using-composer-to-install-drupal-and-manage-dependencies
If you’ve never installed Drupal using drupal-composer/drupal-project, it’s important to know that the folder structure is different. The folder that you create your project within is the project root or repo root (I’m assuming that you will be using version control like Git). This is not your Drupal root (webroot), so any files and folders at this level are not directly addressable with a URL. The exception is the “web” folder which IS the Drupal root. You’ll need to configure your hosting environment to use the ‘web’ folder as the webroot.
- Composer & Git commands need to be run from the top project folder.
- Drush, however, may need to be run from within /web.
Additionally, this Drupal-project scaffolding creates two folders (‘contrib’ & ‘custom’) under each of the following folders (web/profiles, web/modules, & web/themes).
- Any profiles, modules, or themes installed via Composer will be placed inside the respective ‘contrib’ folders which are ignored by Git version control. These don’t need to be committed to version control because they can be easily attained by Composer anytime you clone the repo (see ‘composer install’ command).
- Your custom code should be placed inside a ‘custom’ folder which will be included in your repository when you make a commit.
Adding Modules and Other Drupal Dependencies
composer require drupal/<module>:<version>
- Then enable the module in Drupal or with Drush
- ~ : will only increase the last part of the version number (after the rightmost ‘.’
- ^ : increases based on semver (semantic versioning) rules
- 1.x-dev or dev-1.x : latest dev release for 1.x branch
Instead of setting specific version numbers, I prefer to let my versions update within limits.
- For Drupal Core, I use the tilde(~) with all three version places (~8.7.0) so Composer will update core automatically but not move to a new minor version without intervention.
- For Drupal modules, I use the tilde(~) with only two version places (~2.0) so Composer will update with minor releases but not move to a new version of the module that could contain breaking updates like 2.x to 3.x.
- For non-Drupal packages, I still tend to use tilde(~) but you’ll need to look at the history of the project and see how updates are handled to see where breaking changes are allowed in order to best prevent them without intervention.
Removing Modules and Other Dependencies
- ALWAYS UNINSTALL THE MODULE IN DRUPAL FIRST.
- “Extend” page in the backend, or
drush pmu <module>
- If you forget this step: https://www.drupal.org/project/module_missing_message_fixer. But seriously don't forget this step.
- To remove the code from the project, run
composer remove drupal/<module>Non-drupal use the full package name as it appears in packagist.org or another packagist that you may have added (see Bonus Tip).
Checking for Packages That Need to Be Updated
This command will output a list of dependencies that you’ve added that aren’t up to date. It won’t display dependencies of dependencies but that’s useful here because we can’t fix those directly. The package maintainer of the project calling the outdated dependency will need to update their project first. If you want to contribute to those projects then run the command without --direct and then report the issues.
composer outdated --direct
Composer will update the code base, but be sure to run the database updates. Also, I always run Steps 1-4 in a local or development environment:
- To update the code base, run
composer update --with-dependencies
- To update any database schema, run
drush updbOR go to https://<yoursite>/update.php from your Drupal backend
- Commit to the repository
- Switch to the Live environment and get the latest code from the repo. This is usually a 'git pull' command but may be more complex depending on your environment and DevOps setup.
- To get all of the same package updates on the Live site that were added through step #1, run
composer installon the Live environment.
- To update the database schema on the Live site as in step #2, run
drush updbon the Live Environment
Note: ‘--with-dependencies’ tells Composer to update everything, not just your dependencies, but also the dependencies or dependencies, ad Infinitum.
Note 2: While ‘composer update’ checks for new versions and resolves all the dependencies, ‘composer install’ will only download and deploy the previously resolved dependencies. That’s what the composer.lock file is for. Composer.lock is created on every update. Many times it will be the only changed file in your git commit.
Composer can use a lot of memory, so sometimes you need to let it use all the memory. This can be achieved on a per-command basis like:
php -d memory_limit=-1 composer update --with-dependencies
Or permanently in your environment:
- Create/Edit the /etc/php-cli.ini file
- Modify the line:
- memory_limit = -1
Bonus Tip: Install NPM and Bower Packages With Composer
When a Drupal module needs you to install a library, especially a js or CSS library, you can do it with Composer by setting up Asset Packagist. My suggestion here is only using this for libraries that are used when rendering a page for your end-user. This is not a good way to install your SASS or JS build system that you may use during development.
Follow the instructions at https://asset-packagist.org/