using install profiles and Composer to build a distribution

the problem

This article starts with a problem, a problem that doesn't especially entail the negative connotations that might hit home when you read a section titled "The problem".

The problem is simply the following; we had developed a demo site to show-case what we, miggle can provide to a range of organisations providing a similar service. This was using Drupal 7 as a foundation. The developer who took ownership of this project got to a certain limit and it simply remained a demo site.

The initial idea was that it would be a distribution that anyone working for one of these organisations would take, follow some instructions and setup the beginnings of a new website.

Since the site was fairly small we decided to re-create it with Drupal 8. With the plan for it to be a distribution, where else would be a better place to start than with an install profile?

the install profile

An install profile is used to package up modules and themes to be setup as a part of the installation when someone chooses to install a Drupal site with a certain install profile.

This would usually look something like this:

Installation profile

This is pretty standard and generally fine. If you were going to package up your installation profile as drupal.org hosted distribution you would have to setup drush make files for contrib dependencies according to the specification. In that case it wouldn't quite look like this, more specifically it would be missing the contrib folder.

So what's wrong with this?

It's not so much what is wrong with packaging up all your contrib modules with the custom modules and themes associated with the profile but a question of how it could be done better ...

enter composer

Enter composer

Composer is a pretty awesome PHP package manager which is widely used and drupal.org provides documentation on how to use it to manage Drupal 8 projects. The benefit of using such a package manager is the semantic versioning when defining dependencies making it easy to keep all your dependencies to the version level you need. By this I mean if you had a dependency on a module but only ever wanted it to upgrade to non-breaking changes you could define the version as follows:

{
  "require": {
    "drupal/features": "^8.1.0"
  }
}

This will only ever get the latest minimum version change so it would update to 8.1.12 but not 8.2.0.

For a Drupal 8 distribution Composer works quite well if you follow something like the composer install approach of the Acquia Lightning distribution. There are a whole host of benefits to using Composer including the following:

  • You can manage patches for core, contrib modules and general packages using the cweagans Composer extension.
  • You can use the DrupalScaffolding extension to manage all the Drupal site assets outside of the core directory. These being the .htaccess, index.php and others. 
  • You can write your own post-install and post-update scripts to move files around, remove a project template's git data or pretty much anything else you can think of.
  • You could even extend other Composer-managed distributions as a starting point for your own distribution.

In using Composer both the distribution maintainer and users creating new projects from the distribution could both have repositories that simply consist of very few files. It could consist of the composer.json file, the scripts for handling post-update and post-install tasks and anything else needed in order to run the composer install command.

This isn't always ideal and for someone who may not be a developer but just a site-builder having to use composer might just create more problems than it solves. One approach you could take to tackle this would be to simply have a separate repository for a download-ready distribution. You could also create a local shell script to handle running composer install and pushing all the latest changes to the download-ready repository.

a configuration nightmare

The configuration management introduced in Drupal 8 seems to solve a lot of problems and simplify the process of packaging configuration up with your code-base. For sites that you install once it works wonders but when you start writing an installation profile that should be packaged up with site features out of the box it can become something of a real pain.

Initially what I had done was to export the configuration including all the initial content types, block config, views and other settings and throw it all into the install directory of the install profile. At the very end of the install process it would always crap out moaning about (well in my mind it moans) about missing dependencies. The most annoying thing was to test this you would have to install the site from scratch which would take up a lot of time. Days of tweaking the configuration, trying to ensure all dependencies are available and installing the site over and over again was getting rather frustrating.

can features save the day?

After talking through the process with a colleague he mentioned that the features module had been developed for Drupal 8 as a developer tool for packaging up configuration.

In the same talk he suggested that it would also be a good thing to make these configurable in a custom install step so the user can determine which features they wanted to be installed.

In the result of moving all the configuration into logical feature packages from the install profile there arose a new problem. Some of the configuration defined would override existing configuration that had been created as part of the standard Drupal install. This was mostly around global site settings. So to answer the question Can features save the day? No, well not alone.

To resolve this particular issue brantwynn created this nifty little module:

https://www.drupal.org/project/config_rewrite

You could argue also that you could just move all the rewrite config to the installation profile but I tried that and it just seemed to create more problems.

In terms of the install process this lead to an implementation where all core, custom and contributed modules required would be installed as a part of the standard Drupal site install process.

After this the user would enter all their main site config details.

After this there would be a step where they would select all the features they want to install on the site to start with.

Then the profile will deal with installing the chosen features.

After this comes the default content.

providing default content in non-programmatic fashion

The decision was made that this distribution would come with default content in the case all features remained selected. In the past we have usually produced default content using the Migrate tools creating migration classes for each batch of content that would need to be created. The problem with this is that it is more development work and another thing to debug, test and get frustrated with.

This gem of a module by larowlan was the way to go for us:

https://www.drupal.org/project/default_content

The approach to take with this module is to create content as usual on a local environment and use drush to export specific content to certain module or profile. An example command would be:

drush dcer node 32 --folder=profiles/my_profile/modules/custom/my_default_content/content

The dcer here is the alias for default-content-export-references which handles exporting any entity references such as references to files, other content, taxonomy term or any other type of entity.

You can also use the default-content-export (dce) command if you wanted to export just the specified content and not the related entities. You can export any entity type you like whether that be block content, menu links, nodes, taxonomy terms or custom entity types. See here for some more in-depth documentation on this tool.

The main downside to utilising this module to create your default content is that you have to export each piece of content one at a time but usually when you're writing a distribution you wouldn't expect to provide hundreds of pieces of content to start with.

time to conclude

"Composing" a Drupal 8 distribution is no easy job but tools like Composer, the default content module, the new developer-orientated  features module and any other mentioned tools help get the job done effectively. Though using all these tools takes some learning (especially composer), you'll be thankful in the long run helping you to easily maintain your distribution in the future.

If you want to take back control of your web sites and applications then get in touch with miggle to see how we can deliver operational freedom for you in Drupal.