Introduction

Complex websites and web applications can be created by combining configurations of Modules, Fields, Content Types, Menus, Blocks, Categories, Roles / Permissions, etc… This site setup and configuration process is a very time consuming and repetitive bottleneck.

The Patterns module is built to bypass this bottleneck by managing and automating site configuration. Site configuration is stored in YAML, XML, or PHP files called Patterns. These files have a structure which is easy to read, modify, manage, & share and can be executed manually or as a part of an automated web site deployment.

Installation

Patterns is installed as a Drupal module. Its dependencies are the Token and Libraries modules. It makes uses of external libraries which must be installed separately: Spyc and Codemirror.

  • Spyc is a native PHP library used to parse YAML files. It is necessary for the correct functioning of Patterns.

  • Codemirror is a Javascript library which considerably enhances the interface of the Patterns editor page. It is not necessary for the correct functioning of Patterns, but recommended.

Both libraries should be installed under sites/all/libraries/ under directory names of spyc and codemirror2.

What is a Pattern?

A Pattern is a file composed by an info section (generic metadata about the pattern) and a sequence of _action_s of the type create, modify, or delete grouped in categories (sections). The tag: expression tells Patterns which component to use. Every component defines a list of tags it can handle, see later. After choosing the tag, the pattern file has to supply every required data for the particular action. In this example: name, machine_name, description, hierarchy are some of the datakeys used, and all of them have values assigned. The data is passed to the pattern component as an associative array, most often referred to as $data. Some actions have alternative or optional parameter requirements.

Categories can be arbitrarily defined (excluding the reserved words) and are executed sequentially.

# This is a comment
# Example Pattern

info: # mandatory name
  title: New Vocabulary
  description: Adds a new vocabulary to the website
  author: QScience
  category: Examples
  version: 1.0
  core: 7.x
  author_email: sbalietti@ethz.ch
  author_website: http://qlectives.eu

actions: # any name is good for this category

  - create:
        tag: vocabulary
        name: Another Vocabulary
        machine_name: anothervoc
        description: Another interesting vocabulary
        hierarchy: 0

  - modify:
        tag: vocabulary
        machine_name: anothervoc
        description: It was not that interesting after all
        # vid: 2

  - delete:
        tag: vocabulary
        machine_name: anothervoc
        # vid: 2

Two other optional sections names are modules and include. modules explicitly defines a list of modules to enable during the execution of the pattern, while include loads the actions of another pattern into the current one. More explanation later TODO

Reserved Words

  • info

  • modules

  • include

How Patterns works

Pattern works by parsing the pattern file and then constructing a form which contains the values for specific elements. The form is then validated and submitted, just as if the submit button had been pressed from a browser window.

The processing can be done in two ways. The Batch mode uses Drupal’s Batch API to run the patterns in the background. This helps overcome the time limitations and the user gets feedback of the progress. The other method, which is called PHP, executes the tasks in a single PHP run. In this case, debugging can be easier.

How to implement Patterns for your own module

In order to have your custom module be able to benefit from patterns, you must create a component, much like a driver software. The main components reside in patterns/components/, although modules can use the hook_patterns_components hook to expand the set of supported components.

You need to implement at most 8 pattern hooks, as here explained in the same order as they are being called by Patterns module. For examples, see block.inc, system.inc, taxonomy.inc.

  • hook_patterns($data): declares that the module is able to handle pattern configurations, and specifies which tags and forms are supported. The form mappings might depend on the Pattern data.

  • hook_patterns_prepare($action, $tag, &$data): checks the input and adds default values. Eventually, it can raise errors which halt further execution of the pattern.

  • hook_patterns_validate($action, $tag, &$data): this hooks is similar to the previous one, however, you are working with the prepared data and you are checking against the database.

  • hook_patterns_callbacks($action, $tag, &$data): returns the array of form ID’s which will be run sequentially. If a value in this array is not present in the form id list returned by hook_patterns(), the value will be treated as a regular callback function and will be called with the ($action, $data) parameters. In this case, the next 3 functions are not called and the Pattern action result is provided by the callback function(s).

  • hook_patterns_build($action, $form_id, &$data, &$action_state): gets the form data for the action. This can either be just the form values, or it can be the full form_state object.

  • hook_patterns_params($action, $form_id, &$data &$action_state): returns extra parameters that the form may require.

  • hook_patterns_cleanup($action, $tag, &$data): performs optional additional operations, after the execution of the action has finished.

  • hook_patterns_get_arguments($action, $tag, $form_id, &$loop): returns arguments needed for the forms when using the automatic pattern import function. If arguments are given back for several executions, $loop needs to be set to true. Return arguments always in an array, if they’re for several executions, create an array of arrays. When you want to be able to extract all data, you will need to create an extra tag. When this tag is given to this function, it should then return all the arguments.

where $action is one of the actions create, modify, delete and $tag is the specific command to execute (e.g. vocabulary, field, etc.).

hook_patterns is called independently from the others hooks, which are invoked sequentially to perform an action. In particular, if calling hook_patterns_prepare and hook_patterns_validate does not raise error, moreover hook_patterns_prepare returns some form ID’s, the engine do the following for each form ID:

  1. execute hook_patterns_build, and hook_patterns_params while checking for errors;

  2. submit the form (call the Drupal function drupal_form_submit);

  3. execute hook_patterns_cleanup while checking for errors.

Return values

hook_patterns()

Returns the following array of actions:

  $actions['tag1'] = array(
    PATTERNS_INFO => t('Description of this tag'),
    PATTERNS_CREATE => array('form_to_create_tag1', 'form_to_create_tag2'),
    PATTERNS_MODIFY => array('form_to_modify_tag1', 'form_to_modify_tag2'),
    PATTERNS_DELETE => array('form_to_delete_tag1', 'form_to_delete_tag2'),
    PATTERNS_FILES  => $files = array('some file that needs to be included'),
  );
  $actions['tag2'] = ... ;

where $tag1, $tag2 etc. are specific commands to execute (e.g. vocabulary, field, etc.). The list of possible form ID’s is also provided for each of the three actions (create, modify, delete). Note that this array can be empty as well, see function hook_patterns_callbacks.

hook_patterns_build, hook_patterns_params, hook_patterns_cleanup

All the other hooks return the following special associative array:

  • status: One of [PATTERNS_SUCCESS, PATTERNS_WARN, PATTERNS_ERR]. Required.

  • msg: A message.

  • result: Any kind of additional data.

hook_patterns_get_arguments

Returns arguments needed for the forms when using the automatic pattern import function. If arguments are given back for several executions, $loop needs to be set to true. Return arguments always in an array, if they’re for several executions, create an array of arrays.

Pattern execution modes

Patterns execution can follow two distinct behaviors:

  1. Extend: adds the settings defined in the pattern file into the current instance, and leave untouched what not explicitly specified.

  2. Run-Over: re-configures the whole web site in order to create an instance with exactly the settings defined by the pattern, and removes everything not explicitly specified.

Differences between Extend and Run-Over

The action create changes according to the behavior selected for the execution.

  • create:

    1. extends : always create a new entity;

    2. run-over: always check if the target entity is existing, if not, create it.;

  • modify: check if the target entity exists and then modify it. Does nothing if the entity is not found;

  • delete: check if the target entity exists and then delete it. Does nothing if the entity is not found.

Entity Matching

Entities are matched on the base of their id, if provided, or more commonly on their machine name.

Current status of component implementations

TODO

Table 1. Table of components, tags, actions, and their statuses

Component

Tag

Action

Status

System

call_php_func

create

Works.

theme

create

Mostly works.

TODO: Only set a theme default if default is 1. TODO: Handle administration themes separately.

delete

module

create

TODO

delete

Patterns function names conventions

TODO

Besides standard Drupal coding conventions the Patterns module uses the following naming conventions :

  • Function names: functions declared in .inc files should contain the name of the .inc file in their name. E.g. patterns_io_save_pattern() is defined in includes/patterns.io.inc. Notice: does not apply for theme functions.

  • AJAX call: methods which are called during AJAX operations, and print directly their output instead of returning it should end with the suffix _service. E.g. : patterns_parser_validate_service();

How Patterns files are saved and loaded

By default, the Patterns module hierarchically looks for patterns files in the following locations:

  1. the Drupal public files folder (usually /sites/default/files/patterns/);

  2. a user defined folder (default: /sites/all/patterns/);

  3. the Patterns module patterns directory (usually /sites/all/modules/patterns/patterns/);

  4. any installation profile directory (e.g. /profiles/standard/patterns).

Patterns are files uniquely identified by the title in their info section. If two or more patterns have the same title, only the first one - according to the order defined above - is loaded.

When a file is modified through the web interface of Patterns, a new pattern file is saved in the directory at the topmost of the hierarchy defined above (1.) and the changes are stored in the database. The original file remain untouched.