Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Switch an existing Drupal 8 project under composer

Composer has become a must for relatively ambitious Drupal 8 projects. Even if it is still possible to initialize a Drupal 8 project with drush or simply by downloading a zip archive, these two methods can become limiting over time. Or at least not to facilitate the installation of new modules with dependencies on third-party libraries.

Another of the reasons I have encountered, why some Drupal 8 projects have not been initiated by Composer, is the lack of Composer support on some shared hosting, even so-called professional ones.

If starting a project without Composer can give the impression of saving time at the beginning (by bypassing a necessary phase of appropriation of Composer), it can very quickly become time-consuming, and the initial time saving fades away.

There comes the inevitable moment when you have to rely on Composer to simply manage even the installed modules.

Switching an existing Drupal 8 project to a code base managed by Composer can be done relatively easily.

Create a new project based on Composer

First, initialize a new project with the recommended Composer template (and if necessary install Compose first).

composer create-project drupal-composer/drupal-project:8.x-dev NEW_PROJECT --stability dev --no-interaction

This command will create a new NEW_PROJECT directory, and download the latest version of Drupal, and its dependencies

The initialized directory will look like this.

├── config
├── drush
├── scripts
├── vendor
└── web

Install the active contributed modules and theme on the new project

This is the most daunting part of the procedure, especially if the number of activated modules is large. It is necessary to install the different modules or themes contributed, activated on the project, with Composer.

You can list the different modules from the Extensions configuration page, or list the modules with a drush command.

drush8 pml | grep "Enabled"

This allows you to obtain the list of enabled modules, as well as their version.

 Administration       Admin Toolbar (admin_toolbar)                                                       Module  Enabled        8.x-1.24    
 Administration       Admin Toolbar Extra Tools (admin_toolbar_tools)                                     Module  Enabled        8.x-1.24    
 Chaos tool suite     Chaos tools (ctools)                                                                Module  Enabled        8.x-3.0     
 Custom               Linkit (linkit)                                                                     Module  Enabled        8.x-4.3     
 Field types          Datetime (datetime)                                                                 Module  Enabled        8.6.3       
 Field types          File (file)                                                                         Module  Enabled        8.6.3       
 Field types          Image (image)                                                                       Module  Enabled        8.6.3       
 Field types          Link (link)                                                                         Module  Enabled        8.6.3       
 Field types          Options (options)                                                                   Module  Enabled        8.6.3       
 Field types          Text (text)                                                                         Module  Enabled        8.6.3       
 Multilingual         Interface Translation (locale)                                                      Module  Enabled        8.6.3       
 Multilingual         Language (language)                                                                 Module  Enabled        8.6.3       
 Other                Contact storage (contact_storage)                                                   Module  Enabled        8.x-1.0-bet 
 Other                Pathauto (pathauto)                                                                 Module  Enabled        8.x-1.3     
 Other                Redirect (redirect)                                                                 Module  Enabled        8.x-1.3     
 Other                Redirect 404 (redirect_404)                                                         Module  Enabled        8.x-1.3     
 Other                Token (token)                                                                       Module  Enabled        8.x-1.5     
 SEO                  Metatag (metatag)                                                                   Module  Enabled        8.x-1.7     
 SEO                  Metatag: Open Graph (metatag_open_graph)                                            Module  Enabled        8.x-1.7     
 SEO                  Simple XML Sitemap (simple_sitemap)                                                 Module  Enabled        8.x-2.12    
 Spam control         Antibot (antibot)                                                                   Module  Enabled        8.x-1.2     
 Spam control         Honeypot (honeypot)                                                                 Module  Enabled        8.x-1.29    
 Statistics           Matomo Analytics (matomo)                                                           Module  Enabled        8.x-1.7     
 Bootstrap            Bootstrap (bootstrap)                                                               Theme   Enabled        8.x-3.13    

And so for each module present on the existing project, you can install them with the command, for example for the redirect module.

composer require drupal/redirect ~1.3

and this for each module.

Another alternative, instead of launching this command module by module, is to complete the composer.json file with this list of modules, the minimum version to recover, then launch the command

composer update --with-dependencies

In order to update and download all the modules contained in the composer.json file.

Retrieve user files

Once all the active modules have been uploaded to the new Composer-based project, all that remains is to copy the user files (generally the sites/default/files directory), the custom modules if any, as well as the libraries, configure the settings.php file for connection to the database.

And that's it.

Remember to empty the caches before accessing your new project based on Composer, this time in order to rebuild the Module Registry, in case the modules have not been installed in the modules/contrib directory on the existing project.

Versioning the source code of a Drupal project

Depending on your hosting, constraints and deployment process, and if you use git (highly recommended) it may be interesting to version all the Drupal source code. Indeed, by default, the Drupal Composer template excludes the following directories.

# Ignore directories generated by Composer
/drush/contrib/
/vendor/
/web/core/
/web/modules/contrib/
/web/themes/contrib/
/web/profiles/contrib/
/web/libraries/

You can comment on these lines in order to be able to version the entire code base. However, some third-party modules or libraries may not be versioned because the download process will have used a git clone command, and as such will have created a .git directory in the project directory, excluding this directory (by the presence of a git submodule) from your versioned main code database.

In order to be able to version the entire code base, we can slightly modify the behavior of the project's Composer template.

We will modify the file below to add a command allowing us to delete the .git directories present in the 2 main vendor and web directories after each update command made with composer.

scripts/
└── composer
    └── ScriptHandler.php

We add these new methods to the ScriptHandler class

protected static function getDrupalRoot($project_root) {
  return $project_root .  '/web';
}

protected static function getVendorRoot($project_root) {
  return $project_root .  '/vendor';
}

public static function removeGitDirectories(Event $event) {
  $root = static::getDrupalRoot(getcwd());
  exec('find ' . $root . ' -name \'.git\' | xargs rm -rf');
  exec('find ' . $root . ' -name \'.gitignore\' | xargs rm -rf');
  
  $vendor = static::getVendorRoot(getcwd());
  exec('find ' . $vendor . ' -name \'.git\' | xargs rm -rf');
  exec('find ' . $vendor . ' -name \'.gitignore\' | xargs rm -rf');
}

Then in the composer.json file, we modify the scripts section to get

"scripts": {
    "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold",
    "pre-install-cmd": [
        "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
    ],
    "pre-update-cmd": [
        "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
    ],
    "post-install-cmd": [
        "DrupalProject\\composer\\ScriptHandler::createRequiredFiles",
        "DrupalProject\\composer\\ScriptHandler::removeGitDirectories"
    ],
    "post-update-cmd": [
        "DrupalProject\\composer\\ScriptHandler::createRequiredFiles",
        "DrupalProject\\composer\\ScriptHandler::removeGitDirectories"
    ]
},

Thus, with each installation or update command launched with composer, any git sub-modules created will then be deleted, allowing the entire source code to be versioned under the same project.

This strategy of whether or not to version the entire code base is not to be applied systematically. It must be evaluated project by project, according to your organization, your deployment processes and the nature of your projects, from a simple Drupal 8 site to a Drupal web factory. Advice from a Drupal expert, or from your DevOps teams if you have one, will certainly not be useless.

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web