This project is not covered by Drupal’s security advisory policy.

Important: This module is for developers only, it provides facilities developers can use in custom modules. It does not add anything to a website on its own. Only install it if another module asks for it.

The Controls module provides a plugin API similar in some respects to the CTools plugin architecture but far less versatile or configurable. Yes, you read right - it is less versatile and configurable and there's a reason for that: It's lightweight and designed specifically for developers rather than "configurers". It is easier to set up and use than CTools plugins.

What it does

Nothing on its own. It provides an API for the creation and access to "controls" and a system for callbacks to functions belonging to controls. It also helps to keep code out of the way until needed, this means it helps to keep the memory footprint of an application down.

Initialisation

The Controls module does nothing until it is asked by another module to deliver one or more controls using the controls_get() function. It's important to understand that the Controls module neither knows nor cares what controls and control groups are available, what modules are responding, or what is in a control; it just handles and caches controls as abstract arrays.

When asked to fetch controls, the Controls module looks at the cache to see if it's already found all the controls; if not it:

* Loads the [module_name].controls.inc for any module that has one;
* Performs a module_invoke_all('controls_info') to fetch all controls;
* Issues a drupal_alter() to allow changes to be made (see below for how controls are defined);
* Re-organises the returned controls, when first returned they are grouped by the responding modules, they are then reorganised so they are grouped by the control types (control groups);
* During this process it strips out the module grouping, but adds the module name to the control itself;
* It saves the final structure into the cache;
* Returns the data requested;

What is returned from the controls_get() call depends on its parameters: no parameters returns all controls; the first parameter is the control group and all the controls in that group will be returned; control_group and control_name will return just that control.

Defining Controls

In order to keep unnecessary code out of the .module files the Controls module checks to see if modules have a [module_name].controls.inc file and if so loads that when it is looking for controls. It keeps the controls in the cache once it's found them. These files are also loaded when Controls thinks it might have a function to execute.

function hook_controls_info() {
  return array(
    '[module-name]' => array(
      // repeatable for any number of different control groups
      '[controls-group]' => array(
        // repeatable for any number of controls in a control group
        '[control-name]' => array(
          // Any number and structure of data items for this control
          'name' => t('Control name'),
          'data' => array('a', '5'),
        ),
      ),
    ),
  );
}

function hook_controls_info_alter(&$controls) {
// code to modify the collected controls
}

Using Controls

The section above shows how to supply controls for any particular controls group. But what is a controls group and why?

Let's say, and the module for this exists, that we want to create a Drupal block that displays information for the user in the header for the page. If this information is just links then you could use a menu, but what if it isn't? What if it's login/logout/register links, the current date/time, and a user's points score? How do you do that? You can build a custom module that constructs the block and fetches the relevant data. But what if you then wanted to add a javascript scrolling news feed? It could get messy.

Instead you write a module which generates a block which contains anything it's told to put in. When this module, called controls_userbar, is asked to return its block, it calls the Controls module and requests all userbar controls. It then processes these in turn to generate the content of the block and returns the block. If you want to add something to the userbar block you just add another control in the appropriate module.

What do I mean by "appropriate module"? In this example a user support module could provide the control for login/register/logout links, maybe also the date/time. The point score management module provides the score information. Then you write a module that provides the newsfeed and add a control that provides the scrolling newsfeed. You put the control in the module that it belongs to - the appropriate module.

Another module, controls_nav, produces a perfectly ordinary HTML list of links to pages - just like a menu. Why is it better? Because its controls can define when and how to (a) display and (b) highlight the menu items, and it includes the ability to get a two level menu which can be CSSed to appear anyway you wish. The highlighting issues is important - normally Drupal menu items won't highlight properly if the page is a node, and you have to go through all sorts of tricks to make it work. This module bypasses the problem.

The Key Function

The key function is controls_get() it can take zero, one or two parameters. With none it returns ALL controls in all control groups (this is almost never used). The first parameter is a control group and if called you get back an array of all the controls in the control group. You can also add the control name to fetch just that named control in the control group. (Controls within control groups must be uniquely named, but two controls could have the same name if they are in different groups.)

Why is this module "better" than CTools plugins? It's a lot simpler to set up - you just put in a hook_controls_info() to define a control and that's all. Calling functions in a control is much simpler (see below) and you can call all the plugins in a control_group in a single call - like a module_invoke_all().

But I wouldn't say it's "better" I'd just say it's different and better suited to developers working on client projects and need specific tailored plugins rather than building highly generalised modules for drupal.org.

Single callbacks

A module that uses controls may just use the data within the control to perform it's functions - the controls are just data. But it's also possible to call a function related to that control using this:

$result = controls_callback('result', $control, $args);

This will call a function in the [module-name].controls.inc file, the function name is: {module-name}_{control-group}_{control-name}_{callback}. This is the same method of function name construction as used by CTools. The function itself should look like this:

function mymodule_userbar_datetime_result($control, $args) {
  // processing
  return $result;
}

The $args variable should be an array containing any arguments required for the function. For form processing you could use:

$args = array(
  'form' => $form,
  'form_state' => &$form_state,
);

Using the & operator allows you to modify the variable so it's changed when the function returns, but inside your function you must also do this:

$form_state = &$args['form_state'];

It is possible to specify the callback as having a different name and being in a different file but this is seldom required, it's simpler to let controls behave in the default way.

If the function does not exist, NULL is returned.

Multiple callbacks

It's also possible to call all the controls in a group (or an arbitrary set of controls) in one go:

$results = controls_callback_all('result', 'userbar', $args);

The second parameter is either a controls group-name, or it can be an array of controls (which could be from more than one group).

An array is returned which contains all the results indexed by the control name.

Final note

It can be tricky understanding Controls because it is such a general concept, a control of a given type can contain anything you want it to contain and have whatever functions associated with it that you want. The only thing that needs to be consistent is that controls within the same control group should have similar content and structure.

Modules that use Controls

http://drupal.org/project/deeplink

Controls sub-projects: controls_userbar, controls_nav, controls_toolbar and controls_crumbs.

Similar modules

http://drupal.org/project/ctools (plugins only)

Authors

Drupal 6 version of this project is sponsored by Red Bee Media (Adaddinsane)
Drupal 7 version of this project was originally written by Adaddinsane and current development is sponsored by AAT (kenorb) and Adaddinsane

The maintainers can be contacted for paid customizations of this module as well as Drupal consulting and development.

Project information

Releases