An introduction to Drupal 8 development tools

Posted on 7 July 2015 in Web development

Warning

This Drupal 8 article is obsolete. It was published in July 2015, four months before Drupal 8 was released.

The use of third party components in Drupal 8 has inspired two new tools for Drupal 8 developers: the Drupal Console and the Drupal Web Profiler. Based on the Symfony 2 Console component, the Drupal Console is a scaffolding generator which allows developers to reduce development time by automating the generation of boilerplate code. The Drupal Web Profiler is a port of the Symfony 2 WebProfiler bundle as a Drupal 8 module providing a toolbar with convenient access to performance and profile information.

Drupal Console

The Drupal Console (hechoendrupal/DrupalConsole on GitHub) is a Symfony 2 console application which provides a number of generators to assist developers in creating boilerplate code. Drupal Console is a valuable learning tool which allows developers to get up and running with best practice code by kick-starting a PSR-4 compliant directory structure.

Commands are namespaced, the top-level namespaces currently being:

  • cache
  • config
  • container
  • generate
  • migrate
  • module
  • rest
  • router
  • site
  • test

Commands in the generate namespace

Drupal Console currently has thirteen commands in the generate namespace:

generate:authentication:provider
Generate an authentication provider.
generate:command
Generate commands for the console.
generate:controller
Generate & register a controller.
generate:entity
  • generate:entity:config Generate a new EntityConfig.
  • generate:entity:content Generate a new EntityContent.
generate:form:config
Generate a new ConfigFormBase.
generate:module
Generate a module.
generate:permissions
Generate module permissions.
generate:plugin
  • generate:plugin:block Generate a plugin block.
  • generate:plugin:imageeffect Generate image effect plugin.
  • generate:plugin:rest:resource Generate plugin rest resource.
  • generate:plugin:rulesaction Generate a plugin rule action.
generate:service
Generate a service.

Example: Generating a module

The examples below demonstrate how a module is generated with generate:module All other commands follow a similar pattern.

$ drupal generate:module

 Welcome to the Drupal module generator

Enter the new module name: awesome
Enter the module machine name [awesome]:
Enter the module Path [/modules/custom]:
Enter module description [My Awesome Module]:
Enter package name [Other]:
Enter Drupal Core version [8.x]:
Do you want to generate a default Controller [no]? yes
Would you like to add module dependencies [yes]? no
Do you want to generate a unit test class [yes]? yes
Do you confirm generation [yes]? yes

 Generated or updated files

Site path: /var/www/drupal8
1 - /modules/custom/awesome/awesome.info.yml
2 - /modules/custom/awesome/awesome.module
3 - /modules/custom/awesome/src/Controller/DefaultController.php
4 - /modules/custom/awesome/awesome.routing.yml
5 - /modules/custom/awesome/Tests/Controller/DefaultControllerTest.php

Rather than using the default interactive prompt, options can be passed to the command.

$ drupal generate:module \
--module="awesome" \
--machine-name="awesome" \
--module-path="modules/custom" \
--description="My Awesome Module" \
--core="8.x" \
--package="Other" \
--controller \
--dependencies

Additional commands

In addition to commands in the generate namespace Drupal Console has many other commands. Run drupal list to list available commands. Modules can define their own commands so the available commands may vary according to the modules installed.

Site status information may be viewed with the command site:status, optionally passing the --format=json option.

$ drupal site:status --format=json

Output of preceding command:

{
    "system": {
        "Drupal": "8.0.0-dev",
        "Access to update.php": "Protected",
        "Configuration files": "Protected",
        "Cron maintenance tasks": "Last run 44 min 45 sec ago",
        "D3.js library": "Enabled",
        "Database system": "MySQL, MariaDB, Percona Server, or equivalent",
        "Database system version": "5.5.43-0+deb7u1",
        "Database updates": "Out of date",
        "Drupal core update status": "<a href=\"\/admin\/reports\/updates\">Unknown release date (version 8.0.0-beta11 available)<\/a>",
        "File system": "Writable (<em>public<\/em> download method)",
        "GD library": "2.0.36",
        "GD library PNG support": "2.0.36",
        "Image toolkit": "gd",
        "Module and theme update status": "<a href=\"\/admin\/reports\/updates\">Out of date<\/a>",
        "Node Access Permissions": "Disabled",
        "PHP": "5.4.41-0+deb7u1 (<a href=\"\/admin\/reports\/status\/php\">more information<\/a>)",
        "PHP extensions": "Enabled",
        "PHP memory limit": "-1 (Unlimited)",
        "Search index progress": "100% (0 remaining)",
        "Trusted Host Settings": "Not enabled",
        "Unicode library": "PHP Mbstring Extension",
        "Update notifications": "Enabled",
        "Upload progress": "Not enabled",
        "Web server": null,
        "highlight.js library": "Enabled"
    },
    "database": {
        "Driver": "mysql",
        "Host": "localhost",
        "Database connection": "drupal8",
        "Port": "",
        "Username": "drupal8",
        "Password": "redacted",
        "Connection": "mysql\/\/drupal8:redacted@localhost\/drupal8"
    },
    "theme": {
        "theme_default": "bartik",
        "theme_admin": "seven"
    },
    "directory": {
        "Site root directory": "\/var\/www\/drupal8\/",
        "Site temporary directory": "\/tmp",
        "Default theme directory": "\/core\/themes\/bartik",
        "Admin theme directory": "\/core\/themes\/seven"
    }
}

Custom commands

Modules may define commands by extending Symfony\Component\Console\Command\Command. Drupal Console can create scaffolding for a custom command with the command generate:command. Refer to the Symfony 2 Console Component documentation for additional information. For an example implementation refer to the source code of Web Profiler git clone http://git.drupal.org/project/webprofiler.git.

Chain command execution

Commands may be recorded in YAML and executed with the chain command:

$ drupal chain --file=~/d8-project-init.yml

In the example below a module is created, followed by a controller for that module.

# d8-project-init.yml
commands:
    - command: generate:module
      options:
        module: awesome
        machine-name: awesome
        module-path: /modules/custom/
        description: My Awesome module
        core: 8.x
        package: Test
        controller: false
        dependencies:
        test: false
    - command: generate:controller
      options:
        module: awesome
        class-name: AwesomeController
        method-name: index
        route: /awesome/index
        services: twig

Web Profiler

The Drupal Web Profiler provides convenient access to a selection of performance and profile information on a per request basis.

Data collectors

The Web Profiler provides a number of data collectors which include:

  • PHP configuration
  • route and controller name
  • page load timeline and memory use
  • front-end statistics (timings for: DNS lookup time; TCP handshake; TTFB; data download; and DOM build)
  • database query time and number of queries
  • authentication details
  • number of views
  • number of blocks loaded and rendered
  • number of modules and themes available
  • cache statistics
  • asset statistics

A summary of the data collected is displayed in the Web Profiler toolbar which is displayed along the lower edge of the viewport.

Drupal 8 Web Profiler toolbar
The Drupal 8 Web Profiler toolbar.

Additional detail for each data collector may be viewed by clicking the relevant icon in the toolbar overlay. Below is the detailed report for the page load timeline.

Drupal 8 Web Profiler toolbar
Example of a Drupal 8 Web Profiler report timeline.

Profiling decoupled requests

The included HTTP routing framework and REST API modules in Drupal 8 make it easier to develop decoupled, or headless, applications using a client-side framework such as ember.js.

When profiling an API or headless request the Web Profiler toolbar is not available. However the profile data remains available for each request via a token and link provided in the HTTP response headers X-Debug-Token and X-Debug-Token-Link.

HTTP/1.1 200 OK
Date: Fri, 26 Jun 2015 23:53:36 GMT
Server: Apache/2.2.22 (Debian)
X-Generator: Drupal 8 (https://www.drupal.org)
X-Debug-Token: 0ac668
X-Debug-Token-Link: /admin/reports/profiler/view/0ac668

Visiting the X-Debug-Token-Link (in this case /admin/reports/profiler/view/0ac668) provides access to the report for the relevant request.

Web Profiler console commands

Web profiler provides three console commands:

webprofiler:benchmark
Benchmark a URL.
webprofiler:export
Export Web Profiler profiles to file.
webprofiler:list
List Web Profiler profiles.

Benchmark a URL

$ drupal webprofiler:benchmark http://drupal8/
 105/105 [============================] 100% Done.
date: 'Sun, 06/28/2015 - 21:00:43'
git_commit: "e39a32842072bfbaa2b15c5284625ff63ebc4a08\n"
number_of_runs: 100
url: 'http://drupal8/'
results:
    average: { time: '340 ms', memory: '38.8 MB' }
    median: { time: '336 ms', memory: '38.8 MB' }
    95_percentile: { time: '326 ms', memory: '38.8 MB' }

Export profile data to a file for later analysis

$ drupal webprofiler:export --directory=/tmp/
 266/266 [============================] 100% Done.
Exported 264 profiles

List and filter profiles

$ drupal webprofiler:list --url=http://drupal8/ --method=GET --limit=5
+--------+-----------+--------+-----------------+----------------------------+
| Token  | IP        | Method | URL             | Time                       |
+--------+-----------+--------+-----------------+----------------------------+
| 6f6333 | 127.0.0.1 | GET    | http://drupal8/ | Sun, 06/28/2015 - 20:57:01 |
| 429e2e | 127.0.0.1 | GET    | http://drupal8/ | Sun, 06/28/2015 - 20:57:00 |
| dc1461 | 127.0.0.1 | GET    | http://drupal8/ | Sun, 06/28/2015 - 20:57:00 |
| d00a91 | 127.0.0.1 | GET    | http://drupal8/ | Sun, 06/28/2015 - 20:56:59 |
| ef359a | 127.0.0.1 | GET    | http://drupal8/ | Sun, 06/28/2015 - 20:56:59 |
+--------+-----------+--------+-----------------+----------------------------+