Drupal: Using the Features API in Your Module

Although, I have not written many posts about Drupal, I have actually worked more with Drupal over the last 4-5 year than any other web technology (except for jQuery). I recently created a module to control the display of a content type’s fields based upon roles (node add/edit). I created an import/export of the modules settings so that each environment (development, test, production) could be easily updated. The problem is that import/export is such a manual process that it was often overlooked during a deployment. So I decided to use the Features API to featurize my module’s settings.

hook_features_api

The first step in using the Features API is adding the hook_features_api to your .module file:

/**
 * Implementation of hook_features_api
 *
 * Here we define the components that we want to make exportable.  For this
 * particular module, we want to make the configurations exportable.
*/
function node_edit_display_features_api() {
  return array(
    'node_edit_display_config' => array(
      'name' => 'Node Edit Display Configs',
      'file' => drupal_get_path('module', 'node_edit_display') .'/inc/node_edit_display.features.inc',
      'default_hook' => 'node_edit_display_config_features_default_settings',
      'feature_source' => TRUE,
    ),
  );
}

The name of my module is node_edit_display (I need to create a better name), so I named my component: node_edit_display_config. You can name the component anything you like – just remember that it will be used for all component hooks. All of the feature code will be placed in node_edit_display/inc/node_edit_display.features.inc. The default_hook is the function that will get called when the feature is enabled. The feature_source option tells Features to make this component available when first creating a feature from scratch.

hook_features_export_options

Next, I created the function that tells Features what will be exported. This is a component hook, so I name it accordingly. In this case, I’m using a variable_get to retrieve my module’s settings. If my settings were stored in the database, then I would create a query to retrieve the information.

/**
* Implementation of hook_features_export_options(). [component_hook]
*/
function node_edit_display_config_features_export_options() {
  $options = array();
  $options['node_edit_display_settings'] = variable_get('node_edit_display_settings', array());
 
  return $options;
}

hook_features_export

Next, I tell Features what else is required when the settings are exported. This includes any dependencies. In the example below, the only dependency I’m including is the module itself.

/**
* Implementation of hook_features_export(). [component_hook]
*/
function node_edit_display_config_features_export($data, &$export, $module_name) {
  //we have module dependencies in order for this module to function properly
  //so we'll add them here
  $export['dependencies']['node_edit_display'] = 'node_edit_display';
  // The following is the simplest implementation of a straight object export
  // with no further export processors called.
  foreach ($data as $component) {
    $export['features']['node_edit_display_config'][$component] = $component;
  }
  return array();
}

The $data parameter is an array of items that you made available in hook_features_export_options.
The $export parameter is also an array. It is a log of information Features will use to keep track of what is to be exported.
The $module_name parameter is the name of the feature that the user will create.

hook_features_export_render

This next component hook is used to tell Features how to export the data.

/**
* Implementation of hook_features_export_render(). [component_hook]
*/
function node_edit_display_config_features_export_render($module_name, $data, $export = NULL) {
  $code = array();
  foreach ($data as $component) {
    $code[$component] = variable_get($component);
  }
  $code = "  return " . features_var_export($code, ' '). ";";
  return array('node_edit_display_config_features_default_settings' => $code);
}

hook_features_rebuild

Next, we have to tell Features how to recreate the items from the features_export_render hook.

/**
* Implementation of hook_features_rebuild(). [component_hook]
*/
function node_edit_display_config_features_rebuild($module) {
  $items = module_invoke($module, 'node_edit_display_feature_features_default_settings');
  //loop over the items we need to recreate
  foreach ($items as $id => $item) {
       variable_set($id, $item);
  }//end - loop
}

hook_features_revert

And finally, we have to tell features what to do when the feature is reverted. Reverting is essentially the same as rebuilding the feature.

/**
* Implementation of hook_features_revert(). [component_hook]
*/
function node_edit_display_config_features_revert($module) {
  node_edit_display_config_features_rebuild($module);
}

After the code is complete, we must clear the cache (using drush)

drush cc all

I should now see my features component (I’m using drush because the Features UI is extremely slow):

drush fc
 
# Result [32]    :   node_edit_display_config
…

Now to create my feature (again, using Drush)

drush fe –y –version-set=”7.x-1.0” node_edit_display_feature node_edit_display_config –destination=”sites/all/modules/custom/node_edit_display_feature”

And that’s it. Now the development team can easily deploy my Drupal module’s settings between environments. Enjoy.

Be Sociable, Share!

Checkout My New Site - T-shirts For Geeks