using the features api

20
The Features API Making your modules Feature friendly.

Upload: cgmonroe

Post on 05-Dec-2014

264 views

Category:

Technology


0 download

DESCRIPTION

A presentation on the Features API which shows how to use this to make your application Features friendly.

TRANSCRIPT

Page 1: Using the Features API

The Features API

Making your modules Feature friendly.

Page 2: Using the Features API

What is the API thing?

Features is designed to capture module “state” information and allows it to be reproduced on any server.

The features API allows module coders to add functions that allow this “State” to be transferred.

Reference: API.txt file in Features module

Page 3: Using the Features API

Some TerminologyFeature module – A special module that captures the “state” of module components needed for the function it defines. E.g. profiles

Component Type – A grouping of configuration objects

Component – A configuration object that can be exported, e.g. a view, content type, or CCK field. Components are listed in the “edit component” field of the create feature page.

Machine Name – An identifier that is unique in and across sites (as opposed to an DB id field which unique only on a site).

Exportable component – An exportable setting that can exist only in code. E.g. a view.

Faux-Exportable component – a exportable setting that needs to be in the db. Settings of this type are used to synchronize entries in the DB using machine names

Page 4: Using the Features API

Feature Component Hashes

The Feature module code maintains various md5 hashes that are use to compare states. Basically these hashes are for:

The state defined by the site settings

The state defined by the current feature module code

The last known state set by feature module code

These are used to generate the component status shown in the Features management page.

Page 5: Using the Features API

Feature States

The status of the Feature component as displayed on the Manage Features pages.

Default – All three component hashes match

Overridden – Site settings do not match

Needs Review – All three hashes are different. E.g., local overrides with new feature code.

Rebuildable – Site settings match previous settings but the feature code is new.

Rebuilding – A rarely “seen” transient state that is set when a component is being synced with DB.

Page 6: Using the Features API

The API Hooks- `hook_features_api()` defines the component types

- `hook_features_export()` processes a list of components, detecting any dependencies or further components

- `hook_features_export_options()` provides an array of components that can be exported for a given type.

- `hook_features_export_render()` renders a set of components to code as a defaults hook.

- `hook_features_revert()` reverts components of a feature back to their default (as defined in code) state.

- `hook_features_rebuild()` updates faux-exportable components back to their default state.

Reference: features.api.php in Features module code

Page 7: Using the Features API

A Case StudyNeed:

The ldapauth module (part of LDAP Integration suite) has some complex settings that often need to be duplicate across a lot of server. Features support is a great way to do this.

Requirements:

Transfer the module settings that fall into two types:

- Global settings stored as persistent variables

- LDAP server definitions (can be more than one) are stored in the ldapauth table.

Page 8: Using the Features API

A Case Study

Strategy:

Create two Features component types to support the two kinds of settings.

Utilize Strongarm and Ctools API/Code to simplify coding

Issues:

The LDAP Server settings use DB generated id fields that do not map across server.

Page 9: Using the Features API

Adding Machine Name Support

In order to make the LDAP server configuration entries exportable, they needed to support a cross site machine name. This was done by:

• Adding a Machine name field to the ldapauth DB

• Adding code to retrieve/update ldapauth table entries by machine name ( ldapauth_server_load() )

• Modifying the admin screen to allow for autogeneration / editing of machine names. ( ldapauth_admin_form() )

• Modifying the initial install process to include this new field. ( ldapauth_schema() )

• Modifying the update process to add field and populate it. ( ldapauth_update_6005() )

Page 10: Using the Features API

Define the Component Types

The part of the Features API to implement is hook_features_api(). Here’s the one for ldapauth:

function ldapauth_features_api() { $info = array( 'ldap_servers' => array( 'name' => 'LDAP Integration', 'default_hook' => 'default_ldap_servers', 'default_file' => FEATURES_DEFAULTS_INCLUDED_COMMON, 'feature_source' => TRUE, 'file' => drupal_get_path('module‘,'ldapauth‘).'/ldapauth.features.inc', ) ); if ( module_exists('strongarm') ) { $info['ldap_settings'] = array( 'name' => 'LDAP Integration', 'default_hook' => 'default_ldap_settings', 'default_file' => FEATURES_DEFAULTS_INCLUDED_COMMON, 'feature_source' => TRUE, 'file' => drupal_get_path('module‘,'ldapauth‘).'/ldapauth.features.inc', ); } return $info;}

Page 11: Using the Features API

Component Type OptionsFor each component type, the <component>_features_export_options() hook needs to be implements. This tells the Features management GUIwhat components to display under each type.

function ldap_servers_features_export_options() { module_load_include('inc', 'ldapauth', 'includes/ldap.core'); $options = array(); $servers = ldapauth_server_load_all(); foreach ( $servers as $server ) { $options[$server->machine_name] = $server->name; } return $options;}function ldap_settings_features_export_options() { $info = array( 'ldapauth_login_process’=>t('Authentication‘).': ‘.t('Authentication mode'), 'ldapauth_login_conflict’=>t('Authentication‘).': ‘.t('User conflict resolve process'), 'ldapauth_forget_passwords’=>t('Authentication‘).': ‘.t('Store user passwords'), 'ldapauth_sync_passwords’=>t('Authentication‘).': ‘.t('Sync passwords'), 'ldapauth_create_users’=>t('Authentication‘).': ‘.t('Create new users'), 'ldapauth_alter_username_field’ =>t('Authentication‘).': ‘.t('Alter user name field'), 'ldapauth_disable_pass_change’=>t('Authentication‘).': ‘.t('Remove password fields'), 'ldapauth_alter_email_field’=>t('Authentication‘).': ‘.t('Alter email field'), ); ldapauth_submodules("ldap_settings", $info); return $info;}

Page 12: Using the Features API

Features Export List

The features_export hook generates the information that goes into the features module .info file at build time. Each component type needs one.

For the LDAP Global settings, we just define the module dependenciesand them make use of Strongarm’s variable_features_export() function.

function ldap_settings_features_export($data, &$export, $module_name = "") { $export['dependencies']['ldapauth'] = 'ldapauth'; $submodules = ldapauth_submodules('ldap_settings'); foreach ( $submodules as $submodule ) { if ( module_exists($submodule ) ) { $export['dependencies'][$submodule] = $submodule; } } return variable_features_export($data, $export, $module_name);}

Page 13: Using the Features API

Features Export ListFor the LDAP Server setting, we define the module dependenciesand return a list of server definition machine names that the user has selected in the GUI.

function ldap_servers_features_export($data, &$export, $module_name = "") { module_load_include('inc', 'ldapauth', 'includes/ldap.core'); $export['dependencies']['ldapauth'] = 'ldapauth'; $submodules = ldapauth_submodules('ldap_servers'); foreach ( $submodules as $submodule ) { if ( module_exists($submodule ) ) { $export['dependencies'][$submodule] = $submodule; } } foreach ( $data as $component ) { $export['features']['ldap_servers'][$component] = $component; } return array();}

Page 14: Using the Features API

Features Export Render

The features_export_render hook generates the information that goesinto the features module code file(s) at build time. Each component type needs one.

This feature is also used to generate the md5 hash tag to check for override and other status.

For the LDAP Global settings, we just make use of Strongarm’s variable_features_export_render() function.

function ldap_settings_features_export_render($module, $data) { return variable_features_export_render($module, $data);}

Page 15: Using the Features API

Features Export RenderFor the LDAP Server settings, we need to generate the code to create aservers array with the machine name as a key and it’s settings as a value.

function ldap_servers_features_export_render($module, $data, $export) { module_load_include('inc', 'ldapauth', 'includes/ldap.core'); $code = array(); $code[] = ' $servers = array();'; if ( is_null($export) ) {// If this is an override check, export all current servers $servers = ldapauth_server_load_all(TRUE); foreach ($servers as $server) { unset($server->sid); $server = (array) $server; ksort($server); // Sort because updated tables don't match, new tables $code[] =" \$servers['{$server['machine_name']}'] = “.features_var_export($server, ‘ ‘).";"; } } else { foreach ($data as $name) { $server = ldapauth_server_load($name); unset($server->sid); $server = (array) $server; ksort($server); $code[] = " \$servers['{$name}'] = " . features_var_export($server, ' ') . ";"; } } $code[] = ' return $servers;'; $code = implode("\n", $code); return array('default_ldap_servers' => $code );}The check for import or override check is because if there is a new server entry,it should be flagged as an override condition.

Page 16: Using the Features API

Features RebuildThe features_rebuild hook is called when a feature is first installed. Each component type needs one.

For the LDAP Global settings, we just make use of Strongarm’s variable_features_rebuild () function.

function ldap_settings_features_rebuild($module) { variable_features_rebuild($module);}

For the LDAP server settings, we need to get the settings in code and add any NON-existent server.

function ldap_servers_features_rebuild($module) { module_load_include('inc', 'ldapauth', 'includes/ldap.core'); $servers = module_invoke($module, 'default_ldap_servers'); foreach ($servers as $server) { $existing_server = ldapauth_server_load($server['machine_name']); if ( empty($existing_server) ) { ldapauth_server_save($server); } }}

Page 17: Using the Features API

Features Revert

The features_revert hook is called when a feature is “reverted” to the settings defined in the feature code via the admin GUI.

For the LDAP Global settings, we just make use of Strongarm’s function.

function ldap_settings_features_rebuild($module) { variable_features_revert($module);}

Page 18: Using the Features API

Features Revert For the LDAP server settings, any server entry not defined in the code needs to be deleted. Any existing server entry that is defined in code definition needs to have it settings update to match the code. Finally, any server entry defined in the code but not in the DB need to be created.

function ldap_servers_features_revert($module) { module_load_include('inc', 'ldapauth', 'includes/ldap.core'); $default_servers = module_invoke($module, 'default_ldap_servers'); $servers = ldapauth_server_load_all(TRUE); $existing_servers = array(); // Update any existing servers in feature and delete those not in the feature. foreach ( $servers as $server ) { $machine_name = $server->machine_name; $existing_servers[$machine_name] = $machine_name; if ( isset($default_servers[$machine_name]) ) { // Update servers $default_servers[$machine_name]['sid'] = $server->sid; ldapauth_server_save($default_servers[$machine_name], TRUE); } else { // Delete server ldapauth_server_delete($server, TRUE); } } // Add any servers in the feature that don't exist. foreach ( $default_servers as $server ) { if ( ! isset($existing_servers[$server['machine_name']]) ) { // Add in default server not in DB unset($server['sid']); ldapauth_server_save($server, TRUE); } }}

Page 19: Using the Features API

The End Product

Page 20: Using the Features API

Questions?