How to Use Composer to Manage Dependencies in Drupal 8?
Even before I start, I would like to shed some light on what is Composer and how we can build a website using Drupal 8. Let’s start with point to point introduction and usage of each key component while managing/developing Drupal 8 Website:
- What is Composer?
- What is Packagist?
- Composer and Drupal 8
- Commit composer.json and composer.lock to versioning tool
- Should I use “composer install” OR “composer update” command?
- Apply Patch using Composer
- Composer.json in custom module
What is Composer?
Composer is a tool/program that downloads all described libraries/packages automatically which are needed while developing a website. These packages can be loaded for individual project or globally using “global” command. That’s why we also call it “Dependency Manager”. Composer works well with all major Operating systems like Windows, Linux and OSX but requires minimum PHP version 5.3.2+ to run.
What is Packagist?
It’s a Composer Repository from where Composer requests for the libraries/packages(code files). It can also be referred to as PHP Package Repository. We can add additional repositories like we are going to add Drupal Packagist. Drupal Packagist works in both Drupal 8 and Drupal 7 projects.
- Drupal Packagist: This Drupal Packagist is scheduled to be deprecated in January 2017 (or when the official Package Repository from Drupal.org is ready). But by that time we would either be able to use this for Drupal 7 or Drupal 8 projects.
In order to include repository for Drupal projects we need to add below code snippet in Default “composer.json” file.
{
“type”: “composer”,
“url”: “http://packagist.drupal-composer.org/”
},
Now the question is where is composer.json file? I will explain creation of “composer.json” later in next section.
Composer and Drupal 8
Let’s discuss the use of Composer with the Drupal 8. This article is about introducing you with composer and Drupal 8. You can check if the composer is already installed on your machine or not by using “composer” command.
$ composer
If above commands show composer along with version then you are good to go. Else, In order to install composer on your machine please read the Installation Guide: (https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx )
At the time of writing this blog I am using:
- Operating System: Ubuntu 14.04 LTS
- Drupal version: Drupal 8.2.2 (https://www.drupal.org/project/drupal/releases/8.2.2)
- Composer Version: 1.1.2
How to Manage Drupal site dependencies using Composer?
We have two options to build our new Drupal 8 websites using composer (in simple language),
- As we install Drupal from drupal.org (https://www.drupal.org/download)
- As a kickstart for managing site dependencies where “vendor” directory is not included in Drupal folder itself (preferred way).
- As we install Drupal from drupal.org
In first way, composer uses DRUPAL itself as a template and two main auto generated composer files “composer.json” and “composer.lock” resides in root folder.
$ mkdir d8drupal
$ composer create-project drupal/drupal d8drupal 8.2.*@dev –no-dev
Above command will download the latest Drupal release dev codebase for version “8.2.*-dev” in “d8drupal” directory.
If we chose this way, then we need to do some manual changes in “composer.json” file for:
- Drupal.org projects as a Composer Repository
By default, composer uses Packagist (https://packagist.org/). Packagist is a repository which manages PHP and PHP-related projects but lacks Drupal projects (modules,themes, libraries etc). So Drupal.org provides its own repository of Drupal projects for Composer. In order to include new repository, we need to edit composer.json file. Open “composer.json” in any editor and add below lines after “license”: “GPL-2.0+”:
“repositories”: {
“drupal”: {
“type”: “composer”,
“url”: “https://packages.drupal.org/8”
}
},
This will associate composer to download Drupal projects from Drupal.org.
If we are working on D7 websites, then URL for repository will be “https://packages.drupal.org/7”
OR we can achieve above requirement using terminal:
$ composer config repositories.drupal composer https://packages.drupal.org/8
- Download contributed projects like modules, themes, libraries or profiles in desired directories rather than default “vendor” directory.
When we build a website in Drupal 8, we need to download required contributed modules, themes, libraries and we want to maintain a directory structure for modules, themes and libraries separately. This means all contributes Modules must be downloaded into “modules/contrib/” directory and Themes in “themes/contrib”. Then below lines in “composer.json” file should be added.
“extra”: {
“installer-paths”: {
“modules/contrib/{$name}”: [“type:drupal-module”],
“modules/custom/{$name}”: [“type:drupal-custom-module”],
“profiles/contrib/{$name}”: [“type:drupal-profile”],
“themes/contrib/{$name}”: [“type:drupal-theme”],
“themes/custom/{$name}”: [“type:drupal-custom-theme”]
}
}
- No Drush and Drupal Console tools:
- This way of using composer doesn’t include Drush and Drupal-console by default.
- As a kickstart for managing site dependencies
$mkdir d8composer
$composer create-project drupal-composer/drupal-project:8.x-dev d8composer –stability dev –no-interaction
If we choose this way, then we have so many benefits which auto cover above mentioned manual changes and features along with updating the Drupal core with Scaffold files. (like .htaccess, robots.txt, index.php, update.php, etc).
Download Drupal Projects: Regardless the way we choose to use composer with Drupal 8. We can use below commands to download Drupal projects as we have configured Drupal projects repository and defined the path where we want to download modules, themes, libraries etc.
Let’s start with downloading a basic module “Google Analytics” using composer.
General Command: Composer requires drupal/<modulename>
- Go to:
- Search for the module/theme you want to include in your project. In our case its “Google Analytics”, so search for the same.
- You will be redirected to dedicated page of google analytic project. ()
- Go back to terminal and hit the below command:
$ composer require drupal/google_analytics
OR
There is better option to look for the projects you want to include using “Composer search DRUPAL_PROJECT” command.
$ composer search pathauto
This command will automatically rewrite your composer.json file with a require statement for this new project. In this case, it added “drupal/google_analytics”: “^2.1”.
Composer will automatically download all dependent projects as well. Try the same command for “Path Auto” module, it will automatically add dependent modules like “ctools” & “token” modules as well.
We can specify the version while downloading the Drupal packages:
$ composer require drupal/<modulename>:<version>
For example: If we want to include the 8.x-1.0-beta1 version of pathauto, then command will be:
$ composer require drupal/pathauto:1.0-beta1
Commit composer.json and composer.lock to Versioning Tool
“Composer.lock” is also an important file which maintains the exact version of project to download/use. This file helps in ensuring that all developers are using the same version. Some developers do not push this file to their versioning tool like GIT, SVN, but I will recommend to push this file too along with “composer.json” .
Should I use “composer install” OR “composer update” command?
If “composer.lock” file already exists and you want to download exact version of projects which are running on other developers systems or on servers then you should use “install” command.
$ composer install
Use “update” command If you have :
- Used the another version of project or
- Included the new project or
- Composer.lock does not exist
$ composer update
Apply Patch using Composer
If you want to apply patches to composer-built dependencies using composer, then you need to add “cweagans/composer-patches” package. In order to do so please add below mentioned code in “require” array of “composer.json” file:
“require”: {
“composer/installers”: “^1.2”,
“drupal-composer/drupal-scaffold”: “^2.2”,
“cweagans/composer-patches”: “~1.0”,
“drupal/core”: “~8.0”,
“drush/drush”: “~8.0”,
“drupal/console”: “~1.0”,
“drupal/pathauto”: “1.x-dev”,
“drupal/google_analytics”: “^2.1”
},
After adding this, you need to run “composer update” command which will create a directory called “cweagans” in “vendor” directory. That’s it. Now you can apply patches to all the composer-built packages. For this you need to modify the “composer.json” file again.
Suppose: We have downloaded the “pathauto” project using “composer require drupal/pathauto” command. Now we want to apply a patch
(https://www.drupal.org/files/issues/pathauto-2810531-2.patch ) to this module.
This time you need to add “patches” array in “extra”. Please find below sample code of “composer.json” file:
“extra”: {
“installer-paths”: {
“web/core”: [“type:drupal-core”],
“web/libraries/{$name}”: [“type:drupal-library”],
“web/modules/contrib/{$name}”: [“type:drupal-module”],
“web/profiles/contrib/{$name}”: [“type:drupal-profile”],
“web/themes/contrib/{$name}”: [“type:drupal-theme”],
“drush/contrib/{$name}”: [“type:drupal-drush”]
},
“patches”: {
“drupal/pathauto”: {
“Pathauto string parameter with default null”: “https://www.drupal.org/files/issues/pathauto-2810531-2.patch”
}
}
}
Here:
KEY — “Pathauto string parameter with default null” is the description to the patch. This can be anything.
Value — “https://www.drupal.org/files/issues/pathauto-2810531-2.patch” source path to the patch
To apply a patch, you need to hit the “composer update” command then patch will be automatically applied to our targeted project (which is “pathauto” in this case) and command prompt will show a message:
Gathering patches for root package.
Gathering patches for dependencies. This might take a minute.
– Installing drupal/pathauto (dev-1.x 13fe7a7)
Cloning 13fe7a78788d848dd78ed88b6305c53d8cdcd9b2
– Applying patches for drupal/pathauto
https://www.drupal.org/files/issues/pathauto-2810531-2.patch (Pathauto string parameter with default null)
Writing lock file
Similarly, you can define as many patches to any number of projects by adding a key-value pair in patches array.
Composer.json in custom module: We can add “composer.json” to our custom module and download all the required projects like libraries for it. Let’s start by a creating a custom module named “test_composer” in “web/modules/custom” directory which will simply download a “archwisp/php-encrypt-data” project from https://packagist.org/packages/archwisp/php-encrypt-data.
(This package simply encrypts the text).
- Create a “test_composer.info.yml” file:
name: Test Composer
type: module
description: ‘Will download a package using composer’
package: Custom
core: ‘8.x’
- Create “composer.json” file in this custom module which is “test_composer” directory and paste the below code:
{
“name”: “testing/composer”,
“description”: “custom composer json to play with string encryption”,
“type”: “drupal-module”,
“require”: {
“archwisp/php-encrypt-data” : “1.1.0”
}
}
- Create “test_composer.routing.yml” file in order to view the data.
test.hello:
path: ‘/test/composer’
defaults:
_controller: ‘\Drupal\test_composer\Controller\DefaultController::general’
_title: ‘Testing Composer with a sample package’
requirements:
_permission: ‘administer blocks’
- Create an “DefaultController.php” file under the “/web/modules/custom/test_composer/src/Controller” directory.
In order to generate our own “$encryptionKey” and “ $macKey”, open the terminal and hit the below mentioned commands:
*Generate your encryption key:
$ head -c 32 /dev/urandom | base64
pTUgV9Qx09EuJ+GcleRU5aD9i5ge2mdriCLkH8xTfV0= (my case)
*Generate your MAC key:
$ head -c 32 /dev/urandom | base64
uanShOJZ6YV7j0jD0iCZodrOmmaqMS+aPzi3BluhkM0= (my case)
<?php
namespace Drupal\test_composer\Controller;
use Drupal\Core\Controller\ControllerBase;
use Nayjest\StrCaseConverter\Str;
/**
* Controller for building the block instance add form.
*/
class DefaultController extends ControllerBase {
/**
* Build the block instance add form.
*
* @param string $plugin_id
* The plugin ID for the block instance.
* @param string $theme
* The name of the theme for the block instance.
*
* @return array
* The block instance edit form.
*/
public function general() {
// These keys won’t actually work… on purpose. Create your OWN!
$encryptionKey = ‘pTUgV9Qx09EuJ+GcleRU5aD9i5ge2mdriCLkH8xTfV0=’;
$macKey = ‘uanShOJZ6YV7j0jD0iCZodrOmmaqMS+aPzi3BluhkM0=’;
$phpcrypt = new \PHPEncryptData\Simple($encryptionKey, $macKey);
$ciphertext = $phpcrypt->encrypt(‘Testing Package using composer’);
$decrypted = $phpcrypt->decrypt($ciphertext);
return [
‘#markup’ => “Original Text: Testing Package using composer <br> Cipher text: $ciphertext <br> Decrypted text: $decrypted”,
];
}
}
Our custom module is ready to serve our purpose. But we need to manually add a ‘require statement’ in our root’s composer.json file. In this case, its:
“require”: {
…..
“archwisp/php-encrypt-data” : “1.1.0”
….
}
And that’s it, we need to run “$ composer update” command, this will download a project called “archwisp” in our vendor directory. Now we can see the output at “/d8composer/web/test/composer” page, which should be like this.
Note: In above described use case, we can’t use “composer_manager” contributed module because we are maintaining our whole website using composer. “Composer Manager” is already deprecated due to improvements in Drupal 8.1 onwards.
Let me conclude by saying, managing/developing any website using composer provides more control over website. We should start using this amazing feature as project build process. I hope you liked this blog and do not forget to like and share this.