field_tools.admin.inc in Field tools 7
Same filename and directory in other branches
Contains admin callbacks for the Field tools module.
File
field_tools.admin.incView source
<?php
/**
* @file
* Contains admin callbacks for the Field tools module.
*/
/**
* Page callback for the field overview list.
*/
function field_tools_field_overview() {
$output = '';
$entity_info = entity_get_info();
$field_types = field_info_field_types();
$fields = field_info_fields();
// Sort the fields, defaulting to field name.
$query = drupal_get_query_parameters();
$sort = isset($query['sort']) ? check_plain($query['sort']) : 'field_name';
uasort($fields, function ($a, $b) use ($sort, $field_types) {
switch ($sort) {
case 'type':
// Sort by the field type label.
return strcmp($field_types[$a[$sort]]['label'], $field_types[$b[$sort]]['label']);
default:
return strcmp($a[$sort], $b[$sort]);
}
});
$rows = array();
foreach ($fields as $field_name => $field) {
$row = array();
// Column: field name.
$row[] = l($field_name, 'admin/reports/fields/field/' . $field_name);
// Column: field type.
$row[] = $field_types[$field['type']]['label'];
// Column: field instances.
$row[] = field_tools_field_instances_list($field);
// Column : operations.
$items_ops = array();
$items_ops[] = l('edit instances', "admin/reports/fields/field/{$field_name}/edit");
$items_ops[] = l('delete instances', "admin/reports/fields/field/{$field_name}/delete");
$row[] = theme('item_list', array(
'items' => $items_ops,
));
$rows[] = $row;
}
$header = array(
l(t('Field name'), current_path(), array(
'query' => array(
'sort' => 'field_name',
),
)),
l(t('Type'), current_path(), array(
'query' => array(
'sort' => 'type',
),
)),
t('Instances'),
t('Operations'),
);
$output .= theme('table', array(
'rows' => $rows,
'header' => $header,
));
drupal_add_css(drupal_get_path('module', 'field_tools') . '/field_tools.css');
return $output;
}
/**
* Page callback for the field references overview list.
*
* @todo Make this all singing and dancing with some sort of visual
* representation of the relationships.
*/
function field_tools_field_references_overview() {
$output = '';
$entity_info = entity_get_info();
$field_types = field_info_field_types();
$fields = field_info_fields();
$rows = array();
foreach ($fields as $field_name => $field) {
// TODO: also deal with taxonomy term ref, product ref.
if (!in_array($field['type'], array(
'entityreference',
'taxonomy_term_reference',
))) {
continue;
}
$row = array();
// Column: field name.
$row[] = l($field_name, 'admin/reports/fields/field/' . $field_name);
// Column: field type.
$row[] = $field_types[$field['type']]['label'];
// Column: field instances.
$row[] = field_tools_field_instances_list($field);
// Column: target entity type.
switch ($field['type']) {
case 'taxonomy_term_reference':
$target_type = 'taxonomy_term';
break;
case 'entityreference':
$target_type = $field['settings']['target_type'];
}
// switch
$row[] = $entity_info[$target_type]['label'];
// Column: target bundles.
switch ($field['type']) {
case 'taxonomy_term_reference':
$vocabulary = $field['settings']['allowed_values'][0]['vocabulary'];
$row[] = l($entity_info['taxonomy_term']['bundles'][$vocabulary]['label'], _field_ui_bundle_admin_path('taxonomy_term', $vocabulary));
break;
case 'entityreference':
switch ($field['settings']['handler']) {
case 'base':
// Base handler: select bundles.
if (empty($field['settings']['handler_settings']['target_bundles'])) {
// Nothing means all bundles.
$row[] = t("All bundles");
}
else {
$target_bundles = $field['settings']['handler_settings']['target_bundles'];
$items = array();
foreach ($target_bundles as $target_bundle) {
$bundle_label = $entity_info[$target_type]['bundles'][$target_bundle]['label'];
$items[$bundle_label] = l($bundle_label, _field_ui_bundle_admin_path($target_type, $target_bundle));
}
ksort($items);
$row[] = theme('item_list', array(
'items' => $items,
));
}
break;
default:
$row[] = "**other handler**";
}
// switch entref handler
break;
}
// switch field type
$rows[] = $row;
}
$header = array(
t('Field name'),
t('Type'),
t('Instances'),
t('Target entity type'),
t('Target bundles'),
);
$output .= theme('table', array(
'rows' => $rows,
'header' => $header,
));
return $output;
}
/**
* Output a graph of references between entity types.
*
* Requires GraphAPI module.
*
* @param $graph_engine
* (optional) The name of a GraphAPI engine to use. Defaults to the first
* engine returned by graphapi_get_engines().
*/
function field_tools_field_references_graph($graph_engine = NULL) {
$graph = graphapi_new_graph();
$entity_info = entity_get_info();
$field_types = field_info_field_types();
$fields = field_info_fields();
$field_map = field_info_field_map();
$instances = field_info_instances();
// Step 1: Create graph nodes for reference fields.
foreach ($fields as $field_name => $field) {
$target_type = NULL;
switch ($field['type']) {
case 'entityreference':
$target_type = $field['settings']['target_type'];
$link_color = 'red';
break;
case 'taxonomy_term_reference':
$target_type = 'taxonomy_term';
$link_color = 'green';
break;
}
// If no target type was set, then we don't know about this sort of field.
if (empty($target_type)) {
continue;
}
// First pass: only entity types in graph, no bundles.
foreach ($field_map[$field_name]['bundles'] as $instance_entity_type => $instance_bundles) {
//dsm("FROM $instance_entity_type TO $target_type");
$link_data = array(
'title' => $field_name,
'type' => 'field-' . $field['type'],
'color' => $link_color,
);
graphapi_set_link_data($graph, $instance_entity_type, $target_type, $link_data);
}
}
// Step 2: Create graph nodes for schema properties that point to other entity tables.
// First we need a lookup of all the entity tables.
$entity_tables = array();
foreach ($entity_info as $entity_type => $entity_type_info) {
$entity_tables[$entity_type_info['base table']] = $entity_type;
}
// Now work through each entity's table schema
foreach ($entity_info as $entity_type => $entity_type_info) {
$entity_table_schema = drupal_get_schema($entity_type_info['base table']);
if (!isset($entity_table_schema['foreign keys'])) {
continue;
}
foreach ($entity_table_schema['foreign keys'] as $relation_name => $relation_info) {
if (isset($entity_tables[$relation_info['table']])) {
// The relation goes to another entity type's table, so add a link to
// our graph.
$link_data = array(
'title' => $relation_name,
'type' => 'schema',
'color' => 'blue',
);
graphapi_set_link_data($graph, $entity_type, $entity_tables[$relation_info['table']], $link_data);
}
}
}
//dsm($graph);
$config = array(
'width' => 800,
'height' => 400,
);
$graph_api_engines = graphapi_get_engines();
if (empty($graph_engine)) {
// Take the first engine if none was given in the URL.
$graph_api_engine_names = array_keys($graph_api_engines);
$graph_engine = array_shift($graph_api_engine_names);
}
$config['engine'] = $graph_engine;
$build = array();
$vars = array(
'graph' => $graph,
'config' => $config,
);
$build['graph'] = array(
'#markup' => theme('graphapi_dispatch', $vars),
);
$engine_links_items = array();
foreach ($graph_api_engines as $name => $label) {
if ($graph_engine == $name) {
$label .= ' ' . t("(current)");
}
$engine_links_items[] = l($label, "admin/reports/fields/graph/{$name}");
}
$build['engine_links'] = array(
'#theme' => 'item_list',
'#items' => $engine_links_items,
'#title' => t("Select graph rendering engine"),
);
return $build;
}
/**
* Form to edit all instances of a field.
*
* @param $field
* A field definition array.
*
* @see field_tools_field_edit_form_validate()
* @see field_tools_field_edit_form_submit()
*/
function field_tools_field_edit_form($form, &$form_state, $field) {
// Take the first instance in the list as the one to populate the form with.
$bundles = array_keys($field['bundles']);
$entity_type = array_shift($bundles);
$bundle = $field['bundles'][$entity_type][0];
$form['warning'] = array(
'#markup' => t('WARNING: Editing these values will change ALL INSTANCES of this field:') . '<br />' . field_tools_field_instances_list($field),
);
$instance = field_info_instance($entity_type, $field['field_name'], $bundle);
form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin');
// Remainder cribbed from field_ui_field_edit_form().
$form['#field'] = $field;
$form['#instance'] = $instance;
if (!empty($field['locked'])) {
$form['locked'] = array(
'#markup' => t('The field %field is locked and cannot be edited.', array(
'%field' => $instance['label'],
)),
);
return $form;
}
$field_type = field_info_field_types($field['type']);
$widget_type = field_info_widget_types($instance['widget']['type']);
$bundles = field_info_bundles();
// Create a form structure for the instance values.
$form['instance'] = array(
'#tree' => TRUE,
'#type' => 'fieldset',
'#title' => t('%type settings', array(
'%type' => $bundles[$entity_type][$bundle]['label'],
)),
'#description' => t('These settings will be applied the ALL INSTANCES OF THE %field field.', array(
'%field' => $instance['label'],
'%type' => $bundles[$entity_type][$bundle]['label'],
)),
// Ensure field_ui_field_edit_instance_pre_render() gets called in addition
// to, not instead of, the #pre_render function(s) needed by all fieldsets.
'#pre_render' => array_merge(array(
'field_ui_field_edit_instance_pre_render',
), element_info_property('fieldset', '#pre_render', array())),
);
// Build the non-configurable instance values.
$form['instance']['field_name'] = array(
'#type' => 'value',
'#value' => $instance['field_name'],
);
$form['instance']['entity_type'] = array(
'#type' => 'value',
'#value' => $entity_type,
);
$form['instance']['bundle'] = array(
'#type' => 'value',
'#value' => $bundle,
);
$form['instance']['widget']['weight'] = array(
'#type' => 'value',
'#value' => !empty($instance['widget']['weight']) ? $instance['widget']['weight'] : 0,
);
// Build the configurable instance values.
$form['instance']['label'] = array(
'#type' => 'textfield',
'#title' => t('Label'),
'#default_value' => !empty($instance['label']) ? $instance['label'] : $field['field_name'],
'#required' => TRUE,
'#weight' => -20,
);
$form['instance']['required'] = array(
'#type' => 'checkbox',
'#title' => t('Required field'),
'#default_value' => !empty($instance['required']),
'#weight' => -10,
);
$form['instance']['description'] = array(
'#type' => 'textarea',
'#title' => t('Help text'),
'#default_value' => !empty($instance['description']) ? $instance['description'] : '',
'#rows' => 5,
'#description' => t('Instructions to present to the user below this field on the editing form.<br />Allowed HTML tags: @tags', array(
'@tags' => _field_filter_xss_display_allowed_tags(),
)),
'#weight' => -5,
);
// Build the widget component of the instance.
$form['instance']['widget']['type'] = array(
'#type' => 'value',
'#value' => $instance['widget']['type'],
);
$form['instance']['widget']['module'] = array(
'#type' => 'value',
'#value' => $widget_type['module'],
);
$form['instance']['widget']['active'] = array(
'#type' => 'value',
'#value' => !empty($field['instance']['widget']['active']) ? 1 : 0,
);
// Add additional field instance settings from the field module.
$additions = module_invoke($field['module'], 'field_instance_settings_form', $field, $instance);
if (is_array($additions)) {
$form['instance']['settings'] = $additions;
}
// Add additional widget settings from the widget module.
$additions = module_invoke($widget_type['module'], 'field_widget_settings_form', $field, $instance);
if (is_array($additions)) {
$form['instance']['widget']['settings'] = $additions;
$form['instance']['widget']['active']['#value'] = 1;
}
// Add handling for default value if not provided by any other module.
if (field_behaviors_widget('default value', $instance) == FIELD_BEHAVIOR_DEFAULT && empty($instance['default_value_function'])) {
$form['instance']['default_value_widget'] = field_ui_default_value_widget($field, $instance, $form, $form_state);
}
// End crib.
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save settings'),
);
return $form;
}
/**
* Validate handler for the form for all instances of a field.
*
* @see field_tools_field_edit_form()
* @see field_tools_field_edit_form_submit()
* @see field_ui_field_edit_form_validate()
*/
function field_tools_field_edit_form_validate($form, &$form_state) {
field_ui_field_edit_form_validate($form, $form_state);
}
/**
* Submit handler for the form for all instances of a field.
*
* @see field_tools_field_edit_form()
* @see field_tools_field_edit_form_validate()
* @see field_ui_field_edit_form_submit()
*/
function field_tools_field_edit_form_submit($form, &$form_state) {
$instance = $form_state['values']['instance'];
$field = $form['#field'];
// Handle the default value.
if (isset($form['instance']['default_value_widget'])) {
$element = $form['instance']['default_value_widget'];
// Extract field values.
$items = array();
field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
$instance['default_value'] = $items ? $items : NULL;
}
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle) {
// Fake the entity type and bundle into the instance data to save.
$instance['entity_type'] = $entity_type;
$instance['bundle'] = $bundle;
$instance_source = field_read_instance($entity_type, $field['field_name'], $bundle);
$instance = array_merge($instance_source, $instance);
field_update_instance($instance);
drupal_set_message(t('Saved %label instance on entity %entity, bundle %bundle', array(
'%label' => $instance['label'],
// TODO: labels.
'%entity' => $entity_type,
'%bundle' => $bundle,
)));
}
}
// Redirect the user to the overview page.
$form_state['redirect'] = 'admin/reports/fields/tools';
}
/**
* Form for deleting multiple instances of a field.
*/
function field_tools_field_delete_form($form, &$form_state, $field) {
drupal_set_title(t('Delete instances from field %fieldname', array(
'%fieldname' => $field['field_name'],
)), PASS_THROUGH);
$form['info'] = array(
'#markup' => $field['field_name'],
);
$entity_info = entity_get_info();
$options = array();
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle) {
$options["{$entity_type}:{$bundle}"] = $entity_info[$entity_type]['label'] . ': ' . $entity_info[$entity_type]['bundles'][$bundle]['label'];
}
}
$form['instances'] = array(
'#type' => 'checkboxes',
'#title' => t('Instances to delete'),
'#description' => t("WARNING: deleting an instance will delete ALL THE DATA in that instance."),
'#options' => $options,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Delete field instances'),
);
// @todo: use confirm_form()!
return $form;
}
/**
* Submit handler for deleting multiple instances.
*/
function field_tools_field_delete_form_submit($form, &$form_state) {
$field = $form_state['build_info']['args'][0];
foreach (array_filter($form_state['values']['instances']) as $instance_key) {
list($entity_type, $bundle_name) = explode(':', $instance_key);
$instance = field_info_instance($entity_type, $field['field_name'], $bundle_name);
field_delete_instance($instance);
drupal_set_message(t('Deleted instance of %fieldname from %entity bundle %bundle', array(
'%fieldname' => $field['field_name'],
'%entity' => $entity_type,
'%bundle' => $bundle_name,
)));
}
// Redirect the user to the overview page.
$form_state['redirect'] = 'admin/reports/fields/tools';
}
/**
* Form builder for the cloning multiple fields from a bundle.
*
* @param $entity_type
* The machine name of the entity.
* @param $bundle_name
* The machine name of the bundle, or a bundle object if the particular
* entity type has a menu loader for bundles.
*/
function field_tools_bundle_fields_clone_from_form($form, &$form_state, $entity_type, $bundle_name) {
// Get the bundle name if the bundle name is really a bundle object.
$bundle_name = field_extract_bundle($entity_type, $bundle_name);
$field_instances = field_info_instances($entity_type, $bundle_name);
//dsm($field_instances);
// Order the instances by weight.
uasort($field_instances, function ($a, $b) {
if ($a['widget']['weight'] == $b['widget']['weight']) {
return 0;
}
return $a['widget']['weight'] < $b['widget']['weight'] ? -1 : 1;
});
$options_fields = array();
foreach ($field_instances as $field_name => $field) {
$options_fields[$field_name] = t("@field-label (machine name: @field-name)", array(
'@field-label' => $field['label'],
'@field-name' => $field_name,
));
}
asort($options_fields);
$form['fields'] = array(
'#title' => t('Fields to clone'),
'#type' => 'checkboxes',
'#options' => $options_fields,
'#description' => t("Select fields to clone onto one or more bundles."),
);
$form['bundles'] = array(
'#title' => t('Bundle(s) to clone onto'),
'#type' => 'checkboxes',
'#options' => field_tools_options_entity_bundle($entity_type, $bundle_name),
//'#default_value' => $default_bundles,
'#description' => t("Select bundles on which to apply the selected fields."),
);
// Disable the checkbox for the current bundle.
$form['bundles']["{$entity_type}:{$bundle_name}"] = array(
'#disabled' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add field instances'),
);
return $form;
}
/**
* Submit handler for the mass clone form.
*/
function field_tools_bundle_fields_clone_from_form_submit($form, &$form_state) {
// Get details from the original form builder parameters.
list($source_entity_type, $source_bundle_name) = $form_state['build_info']['args'];
// Get the bundle name if the bundle name is really a bundle object.
$source_bundle_name = field_extract_bundle($source_entity_type, $source_bundle_name);
// Get names of fields to clone.
$field_names = array_filter($form_state['values']['fields']);
foreach ($field_names as $field_name) {
$field = field_info_field($field_name);
$instance = field_info_instance($source_entity_type, $field_name, $source_bundle_name);
$new_instances = array();
foreach (array_filter($form_state['values']['bundles']) as $option_key) {
list($entity_type, $bundle_type) = explode(':', $option_key);
$new_instances[$entity_type][] = $bundle_type;
}
if (!empty($new_instances)) {
_field_tools_add_instance_to_bundles($instance, $new_instances);
}
}
}
/**
* Form builder for cloning a single field..
*
* @param $instance
* A FieldAPI field instance definition array.
*/
function field_tools_field_clone_form($form, &$form_state, $instance) {
//dsm($instance);
$form['#instance'] = $instance;
$field_name = $instance['field_name'];
// TODO: is there a way to turn most of what follows into a form element?
$field = field_info_field($field_name);
$field_exists = isset($field);
$field_type = field_info_field_types('taxonomy_term_reference');
// Field settings fieldset.
// @todo restore this when we add a field apply-type UI.
/*
$form['settings'] = array(
'#type' => 'fieldset',
);
$form['settings']['multiple'] = array('#type' => 'checkbox',
'#title' => t('Multiple select'),
'#description' => t('Allows reference fields to hold more than one term from this vocabulary.'),
);
// Lock this if the field exists.
if ($field_exists) {
$form['settings']['multiple'] += array(
'#disabled' => TRUE,
'#default_value' => ($field['cardinality'] == 1 ? FALSE : TRUE),
);
$form['settings']['multiple']['#description'] .= ' ' . t('This setting may not be changed here because this field already has instances.');
}
$form['settings']['required'] = array('#type' => 'checkbox',
'#title' => t('Required'),
'#description' => t('At least one term in this vocabulary must be selected when submitting data with this field.'),
);
form_load_include($form_state, 'inc', 'field_ui', 'field_ui.admin');
$widget_options = field_ui_widget_type_options($field['type']);
$form['settings']['widget_type'] = array(
'#type' => 'select',
'#title' => t('Widget type'),
'#required' => TRUE,
'#options' => $widget_options,
'#default_value' => $field_type['default_widget'],
'#description' => t('The type of form element you would like to present to the user when creating this field in the types below.'),
);
*/
$options = field_tools_options_entity_bundle($instance['entity_type'], $instance['bundle'], FALSE);
//dsm($options);
$default_bundles = array();
if ($field_exists) {
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle_type) {
$default_bundles[] = $entity_type . ':' . $bundle_type;
}
}
}
$form['bundles'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $default_bundles,
'#description' => t("Select bundles on which to apply this field."),
);
// Very neat but undocumented trick: see http://drupal.org/node/1349432
foreach ($default_bundles as $option_key) {
$form['bundles'][$option_key] = array(
'#disabled' => TRUE,
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add field instances'),
);
return $form;
}
/**
* Submit handler for the field clone form.
*/
function field_tools_field_clone_form_submit($form, &$form_state) {
$instance = $form['#instance'];
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
$new_instances = array();
foreach (array_filter($form_state['values']['bundles']) as $option_key) {
list($entity_type, $bundle_type) = explode(':', $option_key);
$new_instances[$entity_type][] = $bundle_type;
}
if (!empty($new_instances)) {
_field_tools_add_instance_to_bundles($instance, $new_instances);
}
}
/**
* Form to export all fields of a bundle.
*
* @param $entity_type
* The machine name of the entity.
* @param $bundle
* The machine name of the bundle, or a bundle object if the particular
* entity type has a menu loader for bundles.
*/
function field_tools_bundle_export_form($form, $form_state, $entity_type, $bundle) {
// Get the bundle name if the bundle name is really a bundle object.
$bundle_name = field_extract_bundle($entity_type, $bundle);
$instances = field_info_instances($entity_type, $bundle_name);
$options_fields = array();
foreach ($instances as $field_name => $field) {
$options_fields[$field_name] = $field['label'];
}
asort($options_fields);
$form['fields'] = array(
'#title' => t('Fields to export'),
'#type' => 'checkboxes',
'#options' => $options_fields,
'#description' => t("Select fields that you want to export."),
);
if (module_exists('field_group')) {
$groups = field_group_info_groups($entity_type, $bundle_name, 'form');
$options_groups = array();
foreach ($groups as $group_name => $group) {
$options_groups[$group_name] = $group->label;
}
asort($options_groups);
$form['groups'] = array(
'#title' => t('Groups to export'),
'#type' => 'checkboxes',
'#options' => $options_groups,
'#description' => t("Select groups that you want to export."),
);
}
// Check if the form has already been submitted, if so, storage will be
// filled and the export code can be built and put into a textarea.
if (isset($form_state['storage']['fields'])) {
$export_fields = array_filter($form_state['storage']['fields']);
$export = array();
foreach ($export_fields as $field_name) {
$instance = $instances[$field_name];
$export[] = field_tools_get_field_code($instance);
}
if (module_exists('field_group')) {
$export_groups = array_filter($form_state['storage']['groups']);
$groups = field_group_info_groups($entity_type, $bundle_name, 'form');
foreach ($export_groups as $group_name) {
$group = $groups[$group_name];
$export[] = field_tools_get_group_code($group);
}
}
$code = implode("\n", $export);
$form['code'] = field_tools_textarea(t('Export code'), $code);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Get export code'),
);
return $form;
}
/**
* Submit handler for field exports.
*/
function field_tools_bundle_export_form_submit($form, &$form_state) {
$form_state['rebuild'] = TRUE;
$form_state['storage']['fields'] = $form_state['values']['fields'];
if (module_exists('field_group')) {
$form_state['storage']['groups'] = $form_state['values']['groups'];
}
}
/**
* Import fields into a bundle.
*
* @param $entity_type
* The machine name of the entity.
* @param $bundle
* The machine name of the bundle, or a bundle object if the particular
* entity type has a menu loader for bundles.
*/
function field_tools_bundle_import_form($form, $form_state, $entity_type, $bundle) {
$form = array();
$form['#entity_type'] = $entity_type;
$form['#bundle'] = field_extract_bundle($entity_type, $bundle);
$form['code'] = field_tools_textarea(t('Field code'));
$form['code']['#required'] = TRUE;
$form['code']['#description'] = t('Paste the code of one or more previously exported fields.');
$form['actions']['import'] = array(
'#type' => 'submit',
'#value' => t('Import'),
);
// Add an action to skip the validation, this means that whatever possible
// will be imported, if any of the fields exist on the target bundle already,
// they will be skipped.
$form['actions']['import_force'] = array(
'#type' => 'submit',
'#value' => t('Import (skip validation)'),
);
return $form;
}
/**
* Validation callback for the import form.
*/
function field_tools_bundle_import_form_validate($form, &$form_state) {
if ($form_state['values']['op'] == $form_state['values']['import_force']) {
// Import without validation has been requested, so we can return here.
return;
}
eval($form_state['values']['code']);
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
$errors = array();
if (isset($fields) && count($fields)) {
foreach ($fields as $field_name => $item) {
$field_type = field_info_field_types($item['field']['type']);
if (!$field_type) {
$errors[] = t('Unknown field type %field_type. Field %field_name will not be created.', array(
'%field_type' => $item['field']['type'],
'%field_name' => $field_name,
));
continue;
}
$instance = field_info_instance($entity_type, $field_name, $bundle);
if ($instance) {
$errors[] = t('Bundle %bundle already contains the field %field.', array(
'%field' => $field_name,
'%bundle' => $bundle,
));
}
}
}
if (isset($groups) && count($groups)) {
foreach ($groups as $group_name => $group) {
$existing_groups = field_group_read_groups(array(
'name' => $entity_type,
'bundle' => $bundle,
));
if (isset($existing_groups[$entity_type][$bundle][$group->mode][$group_name])) {
$errors[] = t('Bundle %bundle already contains the group %group.', array(
'%group' => $group_name,
'%bundle' => $bundle,
));
continue;
}
}
}
if (count($errors) > 0) {
form_set_error('code', t('Validation failed for the following reasons:'));
foreach ($errors as $error) {
drupal_set_message($error, 'error');
}
$form_state['rebuild'] = TRUE;
}
}
/**
* Submit handler for the import form.
*/
function field_tools_bundle_import_form_submit($form, &$form_state) {
eval($form_state['values']['code']);
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
if (isset($fields)) {
field_tools_import_fields($entity_type, $bundle, $fields);
}
if (isset($groups) && count($groups)) {
field_tools_import_groups($entity_type, $bundle, $groups);
}
}
/**
* Form to export a single field instance.
*/
function field_tools_field_export_form($form, $form_state, $instance) {
$form = array();
$form['code'] = field_tools_textarea(t('Field code'), field_tools_get_field_code($instance));
return $form;
}
/**
* Form to export a single group.
*/
function field_tools_group_export_form($form, $form_state, $group) {
$form = array();
$form['code'] = field_tools_textarea(t('Group code'), field_tools_get_group_code($group));
return $form;
}
/**
* Retrieve a code representation of the given field instance.
*
* @param array $instance
* A field instance array.
*
* @return string
* The code representation of the field instance.
*/
function field_tools_get_field_code($instance) {
$data = array();
$entity_name = $instance['entity_type'];
$bundle_name = $instance['bundle'];
$field_name = $instance['field_name'];
$data[$field_name] = array(
'field' => field_info_field($field_name),
'instance' => field_info_instance($entity_name, $field_name, $bundle_name),
);
ctools_include('export');
return '$fields[\'' . $field_name . '\'] = ' . ctools_var_export($data[$field_name]) . ';';
}
/**
* Retrieve a code representation of the given field group.
*
* @param object $group
* A group object
* @return string
* The code representation of the group
*/
function field_tools_get_group_code($group) {
// Unset group properties that are related to the current instance and should
// not be exported.
unset($group->id, $group->identifier, $group->bundle, $group->entity_type);
$group_name = $group->group_name;
ctools_include('export');
return '$groups[\'' . $group_name . '\'] = ' . ctools_var_export($group) . ';';
}
/**
* Import fields to a bundle.
*
* @param string $entity_type
* The entity type of the target bundle
* @param string $bundle_name
* The name of the target bundle
* @param array $fields
* An array of fields to be imported, as obtained from
* field_tools_get_field_code().
*/
function field_tools_import_fields($entity_type, $bundle_name, $fields) {
if (count($fields)) {
foreach ($fields as $field_name => $item) {
$field_type = field_info_field_types($item['field']['type']);
if (!$field_type) {
drupal_set_message(t('Unknown field type %field_type. Field %field_name has not been created.', array(
'%field_type' => $item['field']['type'],
'%field_name' => $field_name,
)), 'error');
continue;
}
$field = field_info_field($field_name);
if (!$field) {
field_create_field($item['field']);
drupal_set_message(t('Field %field has been created.', array(
'%field' => $field_name,
)));
}
$instance = field_info_instance($entity_type, $field_name, $bundle_name);
if (!$instance) {
$item['instance']['bundle'] = $bundle_name;
$item['instance']['entity_type'] = $entity_type;
$item['field_id'] = $field['id'];
field_create_instance($item['instance']);
drupal_set_message(t('Field %field has been added to bundle %bundle.', array(
'%field' => $field_name,
'%bundle' => $bundle_name,
)));
}
else {
drupal_set_message(t('Field %field has not been added to bundle %bundle because the bundle already contains this field.', array(
'%field' => $field_name,
'%bundle' => $bundle_name,
)), 'error');
}
}
}
}
/**
* Import groups to a bundle.
*
* @param string $entity_type
* The entity type of the target bundle
* @param string $bundle_name
* The name of the target bundle
* @param array $groups
* An array of groups to be imported to the target bundle, as obtained from
* field_tools_get_group_code().
*/
function field_tools_import_groups($entity_type, $bundle_name, $groups) {
if (count($groups)) {
if (!module_exists('field_group')) {
drupal_set_message(t('Groups could not be imported because the field_group module is not installed.'));
return;
}
foreach ($groups as $group_name => $group) {
$existing_groups = field_group_read_groups(array(
'name' => $entity_type,
'bundle' => $bundle_name,
));
if (isset($existing_groups[$entity_type][$bundle_name][$group->mode][$group_name])) {
drupal_set_message(t('Group %group has not been added to bundle %bundle because the bundle already contains this group.', array(
'%group' => $group_name,
'%bundle' => $bundle_name,
)), 'error');
continue;
}
$group->identifier = $group->group_name . '|' . $entity_type . '|' . $bundle_name . '|' . $group->mode;
$group->bundle = $bundle_name;
$group->entity_type = $entity_type;
if (isset($group->id)) {
unset($group->id);
}
if (isset($group->export_type)) {
unset($group->export_type);
}
ctools_export_crud_save('field_group', $group);
drupal_set_message(t('Group %group has been added to bundle %bundle.', array(
'%group' => $group_name,
'%bundle' => $bundle_name,
)));
}
}
}
/**
* Helper to get FormAPI options for entity bundles.
*
* @param string $current_entity_type
* The current entity type that these options will be used with.
* @param string $current_bundle
* The current bundle name that these options will be used with.
* @param boolean $filter
* Whether to filter out the current bundle.
*
* @return
* An array for FormAPI '#options' properties, with:
* - keys of the form ENTITY:BUNDLE, using machine names.
* - values of the form ENTITY: BUNDLE, using labels.
*/
function field_tools_options_entity_bundle($current_entity_type, $current_bundle, $filter = TRUE) {
$options = array();
foreach (entity_get_info() as $entity_type => $entity_info) {
// Skip entities that don't take fields.
if (empty($entity_info['fieldable'])) {
continue;
}
foreach ($entity_info['bundles'] as $bundle_type => $bundle_info) {
// Don't show the current bundle in the options, unless not filtering.
if (!$filter || !($current_entity_type == $entity_type && $bundle_type == $current_bundle)) {
$options[$entity_type . ':' . $bundle_type] = $entity_info['label'] . ': ' . $bundle_info['label'];
}
}
}
return $options;
}
/**
* Form builder for the cloning multiple fields to a bundle.
*
* @param $current_entity_type
* The machine name of the entity.
* @param $current_bundle_name
* The machine name of the bundle, or a bundle object if the particular
* entity type has a menu loader for bundles.
*/
function field_tools_bundle_fields_clone_to_form($form, &$form_state, $current_entity_type, $current_bundle_name) {
$current_bundle_name = field_extract_bundle($current_entity_type, $current_bundle_name);
$all_instances = field_info_instances();
$entity_types = entity_get_info();
$form['entity_type'] = array(
'#value' => $current_entity_type,
'#type' => 'value',
);
$form['bundle'] = array(
'#value' => $current_bundle_name,
'#type' => 'value',
);
foreach ($entity_types as $entity_key => $entity_type) {
if ($entity_type['fieldable'] == TRUE) {
if (!empty($entity_type['bundles'])) {
// This entity_type has bundles.
$form['fields'][$entity_key] = array(
'#type' => 'fieldset',
'#title' => $entity_type['label'],
'#description' => '',
'#tree' => TRUE,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
foreach ($entity_type['bundles'] as $bundle_name => $bundle) {
if ($current_entity_type == $entity_key && $bundle_name == $current_bundle_name) {
continue;
}
if (empty($all_instances[$entity_key][$bundle_name])) {
// No fields on this bundle.
continue;
}
$form['fields'][$entity_key][$bundle_name . '_set'] = array(
'#type' => 'fieldset',
'#title' => $bundle['label'],
'#description' => '',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['fields'][$entity_key][$bundle_name . '_set'][$bundle_name] = array(
'#type' => 'checkboxes',
'#title' => $bundle['label'],
'#description' => '',
'#options' => array(),
);
foreach ($all_instances[$entity_key][$bundle_name] as $field_name => $field_info) {
// Make sure this field doesn't already exist on the current bundle.
$on_current_bundle = is_array($all_instances[$current_entity_type][$current_bundle_name]) && array_key_exists($field_name, $all_instances[$current_entity_type][$current_bundle_name]);
if (!$on_current_bundle && _field_tools_entity_can_attach_field($current_entity_type, field_info_field($field_name))) {
$form['fields'][$entity_key][$bundle_name . '_set'][$bundle_name]['#options'][$field_name] = $field_info['label'] . " ({$field_name})";
}
}
if (empty($form['fields'][$entity_key][$bundle_name . '_set'][$bundle_name]['#options'])) {
// @todo should we not show a bundle if no fields can be attached??
$form['fields'][$entity_key][$bundle_name . '_set'][$bundle_name]['#description'] = t('Contains no fields that can be attached to this bundle.');
}
}
// Set #parents to skip sets in form values.
foreach (element_children($form['fields'][$entity_key]) as $key) {
if (strrpos($key, '_set') === drupal_strlen($key) - drupal_strlen('_set')) {
foreach (element_children($form['fields'][$entity_key][$key]) as $sub_key) {
$form['fields'][$entity_key][$key][$sub_key]['#parents'] = array(
'fields',
$entity_key,
$sub_key,
);
}
}
}
$bundle_names = element_children($form['fields'][$entity_key]);
if (empty($bundle_names)) {
// Don't show entities that have no bundle with fields.
unset($form['fields'][$entity_key]);
}
}
}
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Add field instances',
);
return $form;
}
/**
* Validation for cloning multiple fields into one bundle.
*
* Make sure no field was selected more than once.
*/
function field_tools_bundle_fields_clone_to_form_validate($form, &$form_state) {
$selected_fields = array();
$fields = $form_state['values']['fields'];
foreach ($fields as $entity_type => $bundles) {
foreach ($bundles as $bundle_name => $bundle_fields) {
$bundle_fields = array_filter($bundle_fields);
$matching_fields = array_intersect_key($selected_fields, $bundle_fields);
if (!empty($matching_fields)) {
$match_key = array_shift($matching_fields);
form_error($form['fields'][$entity_type][$bundle_name . '_set'], t("You have selected the field %field more that once.", array(
'%field' => $match_key,
)));
return;
}
$selected_fields += $bundle_fields;
}
}
}
/**
* Submit handler for the mass clone to bundle form.
*/
function field_tools_bundle_fields_clone_to_form_submit($form, &$form_state) {
$fields = $form_state['values']['fields'];
$current_entity_type = $form_state['values']['entity_type'];
$current_bundle_name = $form_state['values']['bundle'];
foreach ($fields as $entity_type => $bundles) {
foreach ($bundles as $bundle_name => $bundle_fields) {
$bundle_fields = array_filter($bundle_fields);
foreach ($bundle_fields as $field_name) {
$field_info = field_info_instance($entity_type, $field_name, $bundle_name);
_field_tools_add_instance_to_bundles($field_info, array(
$current_entity_type => array(
$current_bundle_name,
),
));
}
}
}
}
/**
* Helper function to clone a single field instance into multiple bundles.
*
* @param array $instance
* The field instance to be added to the bundles.
* @param array $new_instances
* An array describing entity bundles on which to create field instances.
* Each key is an entity type machine name, each value is an array of bundle
* machine names of that entity.
*/
function _field_tools_add_instance_to_bundles($instance, $new_instances) {
$original_display = $instance['display'];
$field_info = field_info_field($instance['field_name']);
$entity_types = entity_get_info();
foreach ($new_instances as $entity_type => $bundles) {
$bundles = array_filter($bundles);
if (!empty($bundles)) {
if (!_field_tools_entity_can_attach_field($entity_type, $field_info)) {
drupal_set_message(t('Field %field_label cannot be attached to entity type %entity_type', array(
'%field_label' => $instance['label'],
'%entity_type' => $entity_types[$entity_type]['label'],
)));
continue;
}
// Strip out keys that are specific to the instance being copied.
$instance = array_diff_key($instance, array_flip(array(
'id',
'field_id',
'bundle',
'entity_type',
'deleted',
)));
// Only bring back displays that have matching "view mode" in this entity
// type.
$view_modes = $entity_types[$entity_type]['view modes'];
// Add a key for the default display settings, so the array intersection
// keeps them, as we always want those.
$view_modes['default'] = TRUE;
$instance['display'] = array_intersect_key($original_display, $view_modes);
if (empty($instance['display'])) {
//@todo should there be logic to handle to no matching 'view modes'
}
$instance['entity_type'] = $entity_type;
foreach ($bundles as $bundle) {
if (_field_tools_field_already_attached($entity_type, $bundle, $field_info)) {
drupal_set_message(t('Field %field_label is already attached to %entity_type - %bundle', array(
'%field_label' => $instance['label'],
'%entity_type' => $entity_types[$entity_type]['label'],
'%bundle' => $entity_types[$entity_type]['bundles'][$bundle]['label'],
)));
continue;
}
$instance['bundle'] = $bundle;
field_create_instance($instance);
drupal_set_message(t('Attached field %field_label to %entity_type - %bundle', array(
'%field_label' => $instance['label'],
'%entity_type' => $entity_types[$entity_type]['label'],
'%bundle' => $entity_types[$entity_type]['bundles'][$bundle]['label'],
)));
}
}
}
}
/**
* Page callback to list all instances of a field with links to edit them.
*/
function field_tools_field_page($field_name) {
$field = field_info_field($field_name);
if (!$field) {
return t('No field found.');
}
//dsm($field);
$field_instance_list = field_tools_info_instances($field_name);
$bundles = field_info_bundles();
$items = array();
foreach ($field_instance_list as $entity_type => $bundle_list) {
foreach ($bundle_list as $bundle) {
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
$items[] = l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields/' . $field_name);
}
}
return theme('item_list', array(
'items' => $items,
));
}
/**
* Helper to format a nested list of field instances, grouped by entity type.
*
* @todo: make this a theme function?
*
* @param $field
* A field definition array.
*
* @return
* A nested list of entities and bundles that this field has instances on.
*/
function field_tools_field_instances_list($field) {
$entity_info = entity_get_info();
$items_entities = array();
foreach ($field['bundles'] as $entity_type => $field_bundle_names) {
// Fields may exist for entities that no longer do.
if (!isset($entity_info[$entity_type])) {
continue;
}
$items_bundles = array();
foreach ($field_bundle_names as $bundle) {
if (!isset($entity_info[$entity_type]['bundles'][$bundle])) {
continue;
}
// @todo: sort these.
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
$bundle_label = $entity_info[$entity_type]['bundles'][$bundle]['label'];
$items_bundles[$bundle_label] = $admin_path ? l($bundle_label, $admin_path . '/fields/' . $field['field_name']) : $bundle_label;
}
ksort($items_bundles);
$entity_label = $entity_info[$entity_type]['label'];
$items_entities[$entity_label] = $entity_label . theme('item_list', array(
'items' => $items_bundles,
));
}
ksort($items_entities);
return theme('item_list', array(
'items' => $items_entities,
));
}
/**
* Build a Form API textarea element to use for import/export.
*
* @param string $label
* The translated label for the textarea element.
* @param string $value
* (optional) The code to show in the text area.
*
* @return array
* A Form API textarea element.
*/
function field_tools_textarea($label, $value = NULL) {
$textarea = array(
'#type' => 'textarea',
'#title' => $label,
'#rows' => 40,
);
if ($value === NULL) {
$textarea['#default_value'] = '';
}
else {
$textarea['#value'] = $value;
}
return $textarea;
}
Functions
Name | Description |
---|---|
field_tools_bundle_export_form | Form to export all fields of a bundle. |
field_tools_bundle_export_form_submit | Submit handler for field exports. |
field_tools_bundle_fields_clone_from_form | Form builder for the cloning multiple fields from a bundle. |
field_tools_bundle_fields_clone_from_form_submit | Submit handler for the mass clone form. |
field_tools_bundle_fields_clone_to_form | Form builder for the cloning multiple fields to a bundle. |
field_tools_bundle_fields_clone_to_form_submit | Submit handler for the mass clone to bundle form. |
field_tools_bundle_fields_clone_to_form_validate | Validation for cloning multiple fields into one bundle. |
field_tools_bundle_import_form | Import fields into a bundle. |
field_tools_bundle_import_form_submit | Submit handler for the import form. |
field_tools_bundle_import_form_validate | Validation callback for the import form. |
field_tools_field_clone_form | Form builder for cloning a single field.. |
field_tools_field_clone_form_submit | Submit handler for the field clone form. |
field_tools_field_delete_form | Form for deleting multiple instances of a field. |
field_tools_field_delete_form_submit | Submit handler for deleting multiple instances. |
field_tools_field_edit_form | Form to edit all instances of a field. |
field_tools_field_edit_form_submit | Submit handler for the form for all instances of a field. |
field_tools_field_edit_form_validate | Validate handler for the form for all instances of a field. |
field_tools_field_export_form | Form to export a single field instance. |
field_tools_field_instances_list | Helper to format a nested list of field instances, grouped by entity type. |
field_tools_field_overview | Page callback for the field overview list. |
field_tools_field_page | Page callback to list all instances of a field with links to edit them. |
field_tools_field_references_graph | Output a graph of references between entity types. |
field_tools_field_references_overview | Page callback for the field references overview list. |
field_tools_get_field_code | Retrieve a code representation of the given field instance. |
field_tools_get_group_code | Retrieve a code representation of the given field group. |
field_tools_group_export_form | Form to export a single group. |
field_tools_import_fields | Import fields to a bundle. |
field_tools_import_groups | Import groups to a bundle. |
field_tools_options_entity_bundle | Helper to get FormAPI options for entity bundles. |
field_tools_textarea | Build a Form API textarea element to use for import/export. |
_field_tools_add_instance_to_bundles | Helper function to clone a single field instance into multiple bundles. |