A detailed blog post by our Drupal developers about using Drupal Composer template and Phing. It is written from the point of view of the latest Drupal version — Drupal 8.
Every Drupal developer faces daily routine tasks, regardless of the development area, whether it is front-end, back-end, or QA. Most of us are used to optimize any workflow, and there exist plenty of technologies to help us do that. Even simple tasks like a fresh Drupal installation or a local database update with the database server may become a stimulus for creating a number of tools to optimize these tasks. In this regard, I would like to consider two simple tools that will solve the above-mentioned tasks (and many others).
Due to the fact that we are mostly interested in Drupal 8, we will consider these tools from the point of view of working with the latest Drupal version, although both can work with Drupal 7 (the Drupal version is not important for Phing).
Drupal Composer template for Drupal projects
As you can see from the title, we will discuss a tool created to work with Composer to optimize and speed up the installation and further upgrade of Drupal projects, whether it involves core upgrade or installation/updates of contributed modules.
The tool is available via this github link and most of the work is concluded in one command:
composer create-project drupal-composer/drupal-project:8.x-dev some-dir --stability dev --no-interaction
where some-dir is the name of the folder that will be created for the project, and 8.x is the branch and, respectively, the Drupal version to be installed.
It is worth noting that in order to work with this tool, you need to have Composer installed, and if it is installed, it may need to update to version 1.0.0 or higher (you will be notified about it in your terminal).
Having started your project, you can go and check out the tasks in your bug/issue tracker, as it will take some time.
When all the dependencies are loaded and the project is created, you can get to the folder from your browser and continue the standard Drupal installation process.
Let's consider the main benefits of using Drupal Composer template
The structure of the files:
As you can see on the image, Drupal itself, namely its core, modules, themes and profiles are in the folder that is a level below the root (the web folder), which makes the root files externally inaccessible. It is worth noting that your virtual host (apache) or server block (nginx) should be directed at the web folder. All contributed modules, themes and profiles should by default be installed in the contrib folder inside the appropriate folder (web/modules, web/themes, web/profiles), which separates them from the custom code. Note that if for some reason you place custom code in the contrib folder (and you shouldn’t do that), it will not fall under version control.
Version control: As you can see from the .gitignore file in the project root, folders such as vendor, core, contrib, files will not fall under version control. So the repository will include only the necessary files for the Composer, custom code, and additional configuration files, depending on your project requirements.
Additional components by default: After the installation, a developer has two very important tools: Drush and Drupal console, which means that they do not need to be installed in advance in the system. They can be started from the web folder using the following commands:
../vendor/bin/drush some-command ../vendor/bin/drupal some-command
Pre/post install/update scripts/commands/methods: The scripts/composer folder has a php file with a ScriptHandler class and standard methods. If your project requires additional checking/file creating, etc., you can add your method in this class and add a callback of this method in the scripts section of the composer.json file. In this section, there are examples of methods callback for running during the pre/post install/update events. Also, you can add a callback of your command or a start of shell scripts in the scripts section, which will help make some processes more automated.
These are the main advantages of using the Drupal Composer template. It’s hard to disagree that this approach optimizes the time deploying a pure project and supporting it. Trying to provide it all on your own would take much more time.
As for its future use, the installation of modules, core update, patch using is now the Composer’s task.
For example, the installation of the layout plugin contributed module looks like this:
composer require drupal/layout_plugin:8.1.0-alpha22
And Drupal core update looks like this:
composer update drupal/core
Please note that the that the modules will be installed from the package repository specified in composer.json file (at the moment it https://packagist.drupal-composer.org, but it is deprecated and will later be replaced by the official package repository on drupal.org). Note also that the module version specification will slightly differ from the version shown on drupal.org (the layout plugin module version with drupal.org of the 8.x-1.0-alpha22 type will not be accepted by the Composer, because it uses a more accurate versioning of the 8.1.0-alpha22 type).
Phing as a build tool for Drupal projects
Now it's time to talk about the tasks we face much more frequently than downloading and installing a fresh Drupal project.
Suppose that we have a Drupal 8 build which uses the Drupal Composer template mentioned above, and your project is currently under active development. What is the process of updating the local site instance to the repository state (version control), where the project is located? This is done with a set of special commands:
git pull origin master // let’s take the simplest option without inventing more repositories and branches composer install // perhaps someone has added a new module, and you need to install it drush config-import // new configs to be imported into your database came with the pull drush updb // run database updates drush entup // entities updates drush cr // keep calm and clear cache :)
We have described the simplest case, one that a Drupal developer faces several times a day during the active development, but even this includes a set of 6 commands that you may get tired of writing, and, in fact, you may also need to run bower, migrations, unit testing, or any other tool that is used on the project.
Your assistant here is PHING — a build tool based on Apache Ant.
Since we are already using the Drupal Composer template and presume that everyone will use Phing on the project, let’s install it using Composer specifically for our project (the choice between a local and a global installation is up to you, this case is just an example)
composer require-dev phing/phing:2.* //
at the time of your reading the article, the version may vary.
Next, the Phing folder will appear in the vendor folder of your project.
All we need to make our life easier (after all, it’s already complicated enough ;)) is an xml build file with 3 components:
- 1. Task — the code that calls a specific function (git pull, mkdir, etc.)
- 2. Target — the list of tasks, which may be dependent on another target
- 3. Project — the root element consisting of targets
Based on the available data, we write our first simple build file in order to optimize the 6 commands described above.
Let’s create a build.xml file in the project root and leave it under version control, so that other developers can also use it, too (since Phing installed locally for the project). It is advisable not to forget about the fact that the file should not go anywhere outside dev/stage environment, because it is unnecessary.
Let’s describe the file Project:
<?xml version="1.0" encoding="UTF-8"?> <project name="Awesome project" default="build" basedir="." description="Build site"> // here are targets will be (Target). </project>
The project element has several attributes whose mission is clear from their names, but I would like to draw your attention to the default attribute — the Target name which will be used by default, unless the target name is specified when running a Phing command.
Let’s describe the purpose and objectives for our case:
<target name="build"> <exec command="git pull" dir="." description="Fetch data from cvs repository." logoutput="true"/> <exec command="composer install --no-interaction" dir="." description="Install missing composer packages." logoutput="true"/> <exec command="../vendor/bin/drush -y config-import" dir="web" description="Import drupal configuration." logoutput="true"/> <exec command="../vendor/bin/drush -y updb" dir="web" description="Run drupal update database hooks." logoutput="true"/> <exec command="../vendor/bin/drush -y entup" dir="web" description="Run drupal entity update hooks." logoutput="true"/> <exec command="../vendor/bin/drush -y cr" dir="web" description="Rebuild the cache." logoutput="true"/>
</target>
As you can see, the target and task syntax is fairly simple. It is worth noting that the created target has a name specified in the default attribute of the root element, which means that the list of commands will be run by default.
For the most part, these are the basics of working with Phing. The final look of the build file will be like this:
<?xml version="1.0" encoding="UTF-8"?> <project name="Awesome project" default="build" basedir="." description="Build site"> <target name="build"> <exec command="git pull" dir="." description="Fetch data from cvs repository." logoutput="true"/> <exec command="composer install --no-interaction" dir="." description="Install missing composer packages." logoutput="true"/> <exec command="../vendor/bin/drush -y config-import" dir="web" description="Import drupal configuration." logoutput="true"/> <exec command="../vendor/bin/drush -y updb" dir="web" description="Run drupal update database hooks." logoutput="true"/> <exec command="../vendor/bin/drush -y entup" dir="web" description="Run drupal entity update hooks." logoutput="true"/> <exec command="../vendor/bin/drush -y cr" dir="web" description="Rebuild the cache." logoutput="true"/> </target> </project>
and the start of the command running:
phing // from the root of the project, where the build file is
Of course, these are not all the features of Phing. The tool has its own documentation, which will help you build much more complex build files.
As a bonus, I would like to share another target, which will be useful for getting a database from dev/stage with just one command:
<target name="sync"> <exec command="../vendor/bin/drush -y sql-drop" dir="web" description="Drop the database." logoutput="true"/> <exec command="../vendor/bin/drush -y sql-sync @stage @self" dir="web" description="Sync database from stage." logoutput="true"/> <exec command="../vendor/bin/drush -y cr" dir="web" description="Rebuild the cache." logoutput="true"/> <exec command="../vendor/bin/drush -y cim" dir="web" description="Import drupal configuration." logoutput="true"/> <exec command="../vendor/bin/drush -y updb" dir="web" description="Run drupal update database hooks." logoutput="true"/> <exec command="../vendor/bin/drush -y entup" dir="web" description="Run drupal entity update hooks." logoutput="true"/>
</target>
By placing this target in the project of your build file, you can easily synchronize with dev/stage with just one command:
phing sync // sync
— the name of the created target.
Also, running Phing builds can be combined with the Composer pre/post install/update hooks described in Drupal Composer section.
I hope this information was helpful and will reduce the time you spend on some common tasks.