field_tools.module in Field tools 7
Same filename and directory in other branches
field_tools.module Contains useful tools for working with fields.
File
field_tools.moduleView source
<?php
/**
* @file field_tools.module
* Contains useful tools for working with fields.
*/
/**
* Implements hook_help().
*/
function field_tools_help($path, $arg) {
// system_modules() form passes us in an array of nothing but empty strings
// which we don't want to get tripped up by.
$args_filtered = array_filter($arg);
if (!$args_filtered) {
return;
}
// WTF: the $arg array is 12 items long with empty cruft at the end!?!
$args_reverse = array_reverse($args_filtered);
// Provide help for any path that ends in 'fields/%/clone'.
if ($args_reverse[0] == 'clone' && $args_reverse[2] == 'fields') {
return t('Apply this existing field to the other bundles by copying the current field instance.');
}
// Provide help for the bundle tools page.
// Check the last path item first, so we don't perform all the bundle checking
// on every page.
if ($args_reverse[0] == 'tools') {
// Check that this in indeed on a bundle admin path, rather than just any
// old path ending in 'tools'.
$potential_bundle_path = implode('/', array_slice($args_filtered, 0, -1));
foreach (entity_get_info() as $entity_type => $entity_info) {
foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
if (isset($bundle_info['admin']['real path']) && $bundle_info['admin']['real path'] == $potential_bundle_path) {
// We're under the admin path for this bundle.
return t("Apply some or all fields of the %bundle bundle to other bundles by copying the field instances.", array(
'%bundle' => $bundle_info['label'],
));
}
}
}
}
// Provide help any path that ends in 'tools/clone-to'.
if (count($args_reverse) > 1 && $args_reverse[1] == 'tools' && $args_reverse[0] == 'clone-to') {
return t("Select the fields you want to copy to this bundle. You can only select one instance of a particular field.");
}
}
/**
* Implements hook_menu().
*/
function field_tools_menu() {
// Create tabs for all possible bundles.
foreach (entity_get_info() as $entity_type => $entity_info) {
if ($entity_info['fieldable']) {
foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
if (isset($bundle_info['admin'])) {
// Extract path information from the bundle.
$path = $bundle_info['admin']['path'];
// Determine whether this path caters for several bundles (usually all)
// of one entity type, or just one.
if (isset($bundle_info['admin']['bundle argument'])) {
// Different bundles can appear on the same path (e.g. %node_type and
// %comment_node_type). To allow field_ui_menu_load() to extract the
// actual bundle object from the translated menu router path
// arguments, we need to identify the argument position of the bundle
// name string ('bundle argument') and pass that position to the menu
// loader. The position needs to be casted into a string; otherwise it
// would be replaced with the bundle name string.
$bundle_arg = $bundle_info['admin']['bundle argument'];
$bundle_pos = (string) $bundle_arg;
}
else {
// Otherwise, this path is for a single bundle. Things are much simpler!
$bundle_arg = $bundle_name;
$bundle_pos = '0';
}
// This is the position of the %field_ui_menu placeholder in the
// items below.
$field_position = count(explode('/', $path)) + 1;
// Extract access information, providing defaults.
$access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array(
'access callback',
'access arguments',
)));
$access += array(
'access callback' => 'user_access',
'access arguments' => array(
'administer site configuration',
),
);
// Menu item for cloning a bundle's fields en masse.
// In some cases, $path is the same for every bundle, eg nodes, and
// hence doing this here is redundant.
$items["{$path}/tools"] = array(
'title' => 'Tools',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_bundle_fields_clone_from_form',
$entity_type,
$bundle_arg,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 10,
) + $access;
// Tweak comment tools to differentiate them from node tools as they
// sit in the same sets of tabs.
if ($entity_type == 'comment') {
$items["{$path}/tools"]['title'] = 'Comment tools';
$items["{$path}/tools"]['weight'] = 11;
}
$items["{$path}/tools/clone-from"] = array(
'title' => 'Clone fields from this bundle',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_bundle_fields_clone_from_form',
$entity_type,
$bundle_arg,
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 10,
) + $access;
$items["{$path}/tools/clone-to"] = array(
'title' => 'Clone fields to this bundle',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_bundle_fields_clone_to_form',
$entity_type,
$bundle_arg,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 20,
) + $access;
// Menu item for cloning a single field.
$items["{$path}/fields/%field_ui_menu/clone"] = array(
'load arguments' => array(
$entity_type,
$bundle_arg,
$bundle_pos,
'%map',
),
'title' => 'Clone',
'page callback' => 'drupal_get_form',
// The numeric $field_position gets us the field instance from the
// %field_ui_menu menu loader.
'page arguments' => array(
'field_tools_field_clone_form',
$field_position,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 10,
) + $access;
// Menu items for import and export of fields.
$items["{$path}/tools/export"] = array(
'title' => 'Export fields',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_bundle_export_form',
$entity_type,
$bundle_arg,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 30,
) + $access;
$items["{$path}/tools/import"] = array(
'title' => 'Import fields',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_bundle_import_form',
$entity_type,
$bundle_arg,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 40,
) + $access;
// Menu item for exporting a single field.
$items["{$path}/fields/%field_ui_menu/export"] = array(
'load arguments' => array(
$entity_type,
$bundle_arg,
$bundle_pos,
'%map',
),
'title' => 'Export',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_field_export_form',
$field_position,
),
'type' => MENU_LOCAL_TASK,
'file' => 'field_tools.admin.inc',
'weight' => 1,
) + $access;
if (module_exists('field_group')) {
$items["{$path}/groups/%field_group_menu/export"] = array(
'load arguments' => array(
$entity_type,
$bundle_arg,
$bundle_pos,
'%map',
),
'title' => 'Export',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_group_export_form',
$field_position,
),
'type' => MENU_CALLBACK,
'file' => 'field_tools.admin.inc',
'weight' => 1,
) + $access;
}
}
}
}
}
// Field tools overview.
$items["admin/reports/fields/tools"] = array(
'title' => 'Tools',
'page callback' => 'field_tools_field_overview',
'type' => MENU_LOCAL_TASK,
'weight' => -1,
'file' => 'field_tools.admin.inc',
) + $access;
$items["admin/reports/fields/references"] = array(
'title' => 'References',
'page callback' => 'field_tools_field_references_overview',
'type' => MENU_LOCAL_TASK,
'weight' => 5,
'file' => 'field_tools.admin.inc',
) + $access;
if (module_exists('graphapi')) {
$items["admin/reports/fields/graph"] = array(
'title' => 'Graph',
'page callback' => 'field_tools_field_references_graph',
'type' => MENU_LOCAL_TASK,
'weight' => 6,
'file' => 'field_tools.admin.inc',
) + $access;
}
$items["admin/reports/fields/field/%"] = array(
'title' => 'Field instances',
'page callback' => 'field_tools_field_page',
'page arguments' => array(
4,
),
'file' => 'field_tools.admin.inc',
) + $access;
$items["admin/reports/fields/field/%field_tools_field_menu/edit"] = array(
'title' => 'Edit instance',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_field_edit_form',
4,
),
'file' => 'field_tools.admin.inc',
) + $access;
$items["admin/reports/fields/field/%field_tools_field_menu/delete"] = array(
'title' => 'Delete instances',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'field_tools_field_delete_form',
4,
),
'file' => 'field_tools.admin.inc',
) + $access;
return $items;
}
/**
* Menu loader for a field.
*
* @param $field_name
* The machine name of a field.
*/
function field_tools_field_menu_load($field_name) {
if ($field = field_info_field($field_name)) {
return $field;
}
return FALSE;
}
/**
* Helper to get a list of all instances of a field.
*
* @param $field_name
* The name of a field.
*
* @return
* An array of entity types and bundles this field has instances on. Keys are
* entity types, values are arrays of bundle names.
*/
function field_tools_info_instances($field_name) {
$instances = field_info_instances();
$field_bundles = array();
foreach ($instances as $entity_type => $bundles) {
foreach ($bundles as $bundle => $bundle_instances) {
if (isset($bundle_instances[$field_name])) {
$field_bundles[$entity_type][] = $bundle;
}
}
}
return $field_bundles;
}
/**
* Helper function to determine whether a field can be attached an entity type.
*
* Certain fields like comment_body are restricted to certain entity types.
*
* @param string $entity_type
* The entity type to check.
* @param array $field_info
* The field info to check.
*
* @return boolean
* Whether the field can be attached to the entity type.
*/
function _field_tools_entity_can_attach_field($entity_type, $field_info) {
return !(!empty($field_info['entity_types']) && !in_array($entity_type, $field_info['entity_types']));
}
/**
* Helper function to tell if a field is already attached to a bundle.
*
* @param string $entity_type
* The entity type to check.
* @param string $bundle_type
* The bundle type to check.
* @param array $field_info
* The field info array for the field to check.
*
* @return boolean
* Whether the field is already attached to this bundle.
*/
function _field_tools_field_already_attached($entity_type, $bundle_type, $field_info) {
return array_key_exists($entity_type, $field_info['bundles']) && in_array($bundle_type, $field_info['bundles'][$entity_type]);
}
/**
* Implements hook_form_FORM_ID_alter(): field_ui_field_overview_form
*/
function field_tools_form_field_ui_field_overview_form_alter(&$form, $form_state) {
// make sure we have an array to add our after_build callback function to
if (!isset($form['#after_build']) || !is_array($form['#after_build'])) {
$form['#after_build'] = array();
}
$form['#after_build'][] = 'field_tools_alter_fields_ui_table';
}
/**
* Form after_build callback to add an export link to a fields table.
*/
function field_tools_alter_fields_ui_table($form, $form_state) {
// Figure out the key for the operations column in the table header, as other
// modules may be adding more columns too.
$header = $form['fields']['#header'];
foreach ($header as $key => $header_cell) {
if (is_array($header_cell) && $header_cell['data'] == t('Operations')) {
break;
}
}
// Increate the colspan of the 'operations' column.
$form['fields']['#header'][$key]['colspan']++;
// For each field, add an 'export' operation link after the 'delete' link.
foreach (element_children($form['fields']) as $field_name) {
if (!in_array($form['fields'][$field_name]['#row_type'], array(
'field',
'group',
))) {
$export_cell = array(
'#markup' => NULL,
);
$insert_array = array(
'export' => $export_cell,
);
field_tools_array_insert($form['fields'][$field_name], 'delete', $insert_array);
continue;
}
$bundle = $form['#bundle'];
$entity_type = $form['#entity_type'];
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
switch ($form['fields'][$field_name]['#row_type']) {
case 'field':
if (!isset($form['fields'][$field_name]['edit']) || isset($form['fields'][$field_name]['edit']['#value']) && $form['fields'][$field_name]['edit']['#value'] == t('Locked')) {
$export_cell = array(
'#markup' => NULL,
);
$insert_array = array(
'export' => $export_cell,
);
field_tools_array_insert($form['fields'][$field_name], 'delete', $insert_array);
continue 2;
}
$instance = field_info_instance($entity_type, $field_name, $bundle);
$admin_field_path = $admin_path . '/fields/' . $instance['field_name'];
$export_cell = array(
'#type' => 'link',
'#title' => t('export'),
'#href' => $admin_field_path . '/export',
'#options' => array(
'attributes' => array(
'title' => t('Export instance'),
),
),
);
$insert_array = array(
'export' => $export_cell,
);
field_tools_array_insert($form['fields'][$field_name], 'delete', $insert_array);
break;
case 'group':
$admin_field_path = $admin_path . '/groups/' . $field_name;
$export_cell = array(
'#type' => 'link',
'#title' => t('export'),
'#href' => $admin_field_path . '/export/form',
'#options' => array(
'attributes' => array(
'title' => t('Export group'),
),
),
);
$insert_array = array(
'export' => $export_cell,
);
field_tools_array_insert($form['fields'][$field_name], 'delete', $insert_array);
break;
}
}
return $form;
}
/**
* Inserts values into an array after a given key.
*
* Values from $insert_array are inserted after (or before) $key in $array. If
* $key is not found, $insert_array is appended to $array using array_merge().
*
* From https://drupal.org/node/66183.
*
* @param $array
* The array to insert into. Passed by reference and altered in place.
* @param $key
* The key of $array to insert after
* @param $insert_array
* An array whose values should be inserted.
* @param $before
* If TRUE, insert before the given key, rather than after it.
* Defaults to inserting after.
*/
function field_tools_array_insert(&$array, $key, $insert_array, $before = FALSE) {
$done = FALSE;
foreach ($array as $array_key => $array_val) {
if (!$before) {
$new_array[$array_key] = $array_val;
}
if ($array_key == $key && !$done) {
foreach ($insert_array as $insert_array_key => $insert_array_val) {
$new_array[$insert_array_key] = $insert_array_val;
}
$done = TRUE;
}
if ($before) {
$new_array[$array_key] = $array_val;
}
}
if (!$done) {
$new_array = array_merge($array, $insert_array);
}
// Put the new array in the place of the original.
$array = $new_array;
}
Functions
Name | Description |
---|---|
field_tools_alter_fields_ui_table | Form after_build callback to add an export link to a fields table. |
field_tools_array_insert | Inserts values into an array after a given key. |
field_tools_field_menu_load | Menu loader for a field. |
field_tools_form_field_ui_field_overview_form_alter | Implements hook_form_FORM_ID_alter(): field_ui_field_overview_form |
field_tools_help | Implements hook_help(). |
field_tools_info_instances | Helper to get a list of all instances of a field. |
field_tools_menu | Implements hook_menu(). |
_field_tools_entity_can_attach_field | Helper function to determine whether a field can be attached an entity type. |
_field_tools_field_already_attached | Helper function to tell if a field is already attached to a bundle. |