First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,500 @@
<?php
/**
* @file
* Defines an entity type.
*/
/**
* Implements hook_entity_info().
*/
function field_test_entity_info() {
// If requested, clear the field cache while this hook is being called. See
// testFieldInfoCache().
if (variable_get('field_test_clear_info_cache_in_hook_entity_info', FALSE)) {
field_info_cache_clear();
}
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
$test_entity_modes = array(
'full' => array(
'label' => t('Full object'),
'custom settings' => TRUE,
),
'teaser' => array(
'label' => t('Teaser'),
'custom settings' => TRUE,
),
);
return array(
'test_entity' => array(
'label' => t('Test Entity'),
'fieldable' => TRUE,
'field cache' => FALSE,
'base table' => 'test_entity',
'revision table' => 'test_entity_revision',
'entity keys' => array(
'id' => 'ftid',
'revision' => 'ftvid',
'bundle' => 'fttype',
),
'bundles' => $bundles,
'view modes' => $test_entity_modes,
),
// This entity type doesn't get form handling for now...
'test_cacheable_entity' => array(
'label' => t('Test Entity, cacheable'),
'fieldable' => TRUE,
'field cache' => TRUE,
'entity keys' => array(
'id' => 'ftid',
'revision' => 'ftvid',
'bundle' => 'fttype',
),
'bundles' => $bundles,
'view modes' => $test_entity_modes,
),
'test_entity_bundle_key' => array(
'label' => t('Test Entity with a bundle key.'),
'base table' => 'test_entity_bundle_key',
'fieldable' => TRUE,
'field cache' => FALSE,
'entity keys' => array(
'id' => 'ftid',
'bundle' => 'fttype',
),
'bundles' => array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2')) + $bundles,
'view modes' => $test_entity_modes,
),
// In this case, the bundle key is not stored in the database.
'test_entity_bundle' => array(
'label' => t('Test Entity with a specified bundle.'),
'base table' => 'test_entity_bundle',
'fieldable' => TRUE,
'controller class' => 'TestEntityBundleController',
'field cache' => FALSE,
'entity keys' => array(
'id' => 'ftid',
'bundle' => 'fttype',
),
'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')) + $bundles,
'view modes' => $test_entity_modes,
),
// @see EntityPropertiesTestCase::testEntityLabel()
'test_entity_no_label' => array(
'label' => t('Test entity without label'),
'fieldable' => TRUE,
'field cache' => FALSE,
'base table' => 'test_entity',
'entity keys' => array(
'id' => 'ftid',
'revision' => 'ftvid',
'bundle' => 'fttype',
),
'bundles' => $bundles,
'view modes' => $test_entity_modes,
),
'test_entity_label' => array(
'label' => t('Test entity label'),
'fieldable' => TRUE,
'field cache' => FALSE,
'base table' => 'test_entity',
'entity keys' => array(
'id' => 'ftid',
'revision' => 'ftvid',
'bundle' => 'fttype',
'label' => 'ftlabel',
),
'bundles' => $bundles,
'view modes' => $test_entity_modes,
),
'test_entity_label_callback' => array(
'label' => t('Test entity label callback'),
'fieldable' => TRUE,
'field cache' => FALSE,
'base table' => 'test_entity',
'label callback' => 'field_test_entity_label_callback',
'entity keys' => array(
'id' => 'ftid',
'revision' => 'ftvid',
'bundle' => 'fttype',
),
'bundles' => $bundles,
'view modes' => $test_entity_modes,
),
);
}
/**
* Implements hook_entity_info_alter().
*/
function field_test_entity_info_alter(&$entity_info) {
// Enable/disable field_test as a translation handler.
foreach (field_test_entity_info_translatable() as $entity_type => $translatable) {
$entity_info[$entity_type]['translation']['field_test'] = $translatable;
}
// Disable locale as a translation handler.
foreach ($entity_info as $entity_type => $info) {
$entity_info[$entity_type]['translation']['locale'] = FALSE;
}
}
/**
* Helper function to enable entity translations.
*/
function field_test_entity_info_translatable($entity_type = NULL, $translatable = NULL) {
drupal_static_reset('field_has_translation_handler');
$stored_value = &drupal_static(__FUNCTION__, array());
if (isset($entity_type)) {
$stored_value[$entity_type] = $translatable;
entity_info_cache_clear();
}
return $stored_value;
}
/**
* Creates a new bundle for test_entity entities.
*
* @param $bundle
* The machine-readable name of the bundle.
* @param $text
* The human-readable name of the bundle. If none is provided, the machine
* name will be used.
*/
function field_test_create_bundle($bundle, $text = NULL) {
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
$bundles += array($bundle => array('label' => $text ? $text : $bundle));
variable_set('field_test_bundles', $bundles);
$info = field_test_entity_info();
foreach ($info as $type => $type_info) {
field_attach_create_bundle($type, $bundle);
}
}
/**
* Renames a bundle for test_entity entities.
*
* @param $bundle_old
* The machine-readable name of the bundle to rename.
* @param $bundle_new
* The new machine-readable name of the bundle.
*/
function field_test_rename_bundle($bundle_old, $bundle_new) {
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
$bundles[$bundle_new] = $bundles[$bundle_old];
unset($bundles[$bundle_old]);
variable_set('field_test_bundles', $bundles);
$info = field_test_entity_info();
foreach ($info as $type => $type_info) {
field_attach_rename_bundle($type, $bundle_old, $bundle_new);
}
}
/**
* Deletes a bundle for test_entity objects.
*
* @param $bundle
* The machine-readable name of the bundle to delete.
*/
function field_test_delete_bundle($bundle) {
$bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle')));
unset($bundles[$bundle]);
variable_set('field_test_bundles', $bundles);
$info = field_test_entity_info();
foreach ($info as $type => $type_info) {
field_attach_delete_bundle($type, $bundle);
}
}
/**
* Creates a basic test_entity entity.
*/
function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $label = '') {
$entity = new stdClass();
// Only set id and vid properties if they don't come as NULL (creation form).
if (isset($id)) {
$entity->ftid = $id;
}
if (isset($vid)) {
$entity->ftvid = $vid;
}
$entity->fttype = $bundle;
$label = !empty($label) ? $label : $bundle . ' label';
$entity->ftlabel = $label;
return $entity;
}
/**
* Loads a test_entity.
*
* @param $ftid
* The id of the entity to load.
* @param $ftvid
* (Optional) The revision id of the entity to load. If not specified, the
* current revision will be used.
* @return
* The loaded entity.
*/
function field_test_entity_test_load($ftid, $ftvid = NULL) {
// Load basic strucure.
$query = db_select('test_entity', 'fte', array())
->condition('fte.ftid', $ftid);
if ($ftvid) {
$query->join('test_entity_revision', 'fter', 'fte.ftid = fter.ftid');
$query->addField('fte', 'ftid');
$query->addField('fte', 'fttype');
$query->addField('fter', 'ftvid');
$query->condition('fter.ftvid', $ftvid);
}
else {
$query->fields('fte');
}
$entities = $query->execute()->fetchAllAssoc('ftid');
// Attach fields.
if ($ftvid) {
field_attach_load_revision('test_entity', $entities);
}
else {
field_attach_load('test_entity', $entities);
}
return $entities[$ftid];
}
/**
* Saves a test_entity.
*
* A new entity is created if $entity->ftid and $entity->is_new are both empty.
* A new revision is created if $entity->revision is not empty.
*
* @param $entity
* The entity to save.
*/
function field_test_entity_save(&$entity) {
field_attach_presave('test_entity', $entity);
if (!isset($entity->is_new)) {
$entity->is_new = empty($entity->ftid);
}
if (!$entity->is_new && !empty($entity->revision)) {
$entity->old_ftvid = $entity->ftvid;
unset($entity->ftvid);
}
$update_entity = TRUE;
if ($entity->is_new) {
drupal_write_record('test_entity', $entity);
drupal_write_record('test_entity_revision', $entity);
$op = 'insert';
}
else {
drupal_write_record('test_entity', $entity, 'ftid');
if (!empty($entity->revision)) {
drupal_write_record('test_entity_revision', $entity);
}
else {
drupal_write_record('test_entity_revision', $entity, 'ftvid');
$update_entity = FALSE;
}
$op = 'update';
}
if ($update_entity) {
db_update('test_entity')
->fields(array('ftvid' => $entity->ftvid))
->condition('ftid', $entity->ftid)
->execute();
}
// Save fields.
$function = "field_attach_$op";
$function('test_entity', $entity);
}
/**
* Menu callback: displays the 'Add new test_entity' form.
*/
function field_test_entity_add($fttype) {
$fttype = str_replace('-', '_', $fttype);
$entity = (object)array('fttype' => $fttype);
drupal_set_title(t('Create test_entity @bundle', array('@bundle' => $fttype)), PASS_THROUGH);
return drupal_get_form('field_test_entity_form', $entity, TRUE);
}
/**
* Menu callback: displays the 'Edit exiisting test_entity' form.
*/
function field_test_entity_edit($entity) {
drupal_set_title(t('test_entity @ftid revision @ftvid', array('@ftid' => $entity->ftid, '@ftvid' => $entity->ftvid)), PASS_THROUGH);
return drupal_get_form('field_test_entity_form', $entity);
}
/**
* Test_entity form.
*/
function field_test_entity_form($form, &$form_state, $entity, $add = FALSE) {
// During initial form build, add the entity to the form state for use during
// form building and processing. During a rebuild, use what is in the form
// state.
if (!isset($form_state['test_entity'])) {
$form_state['test_entity'] = $entity;
}
else {
$entity = $form_state['test_entity'];
}
foreach (array('ftid', 'ftvid', 'fttype') as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => isset($entity->$key) ? $entity->$key : NULL,
);
}
// Add field widgets.
field_attach_form('test_entity', $entity, $form, $form_state);
if (!$add) {
$form['revision'] = array(
'#access' => user_access('administer field_test content'),
'#type' => 'checkbox',
'#title' => t('Create new revision'),
'#default_value' => FALSE,
'#weight' => 100,
);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#weight' => 101,
);
return $form;
}
/**
* Validate handler for field_test_entity_form().
*/
function field_test_entity_form_validate($form, &$form_state) {
entity_form_field_validate('test_entity', $form, $form_state);
}
/**
* Submit handler for field_test_entity_form().
*/
function field_test_entity_form_submit($form, &$form_state) {
$entity = field_test_entity_form_submit_build_test_entity($form, $form_state);
$insert = empty($entity->ftid);
field_test_entity_save($entity);
$message = $insert ? t('test_entity @id has been created.', array('@id' => $entity->ftid)) : t('test_entity @id has been updated.', array('@id' => $entity->ftid));
drupal_set_message($message);
if ($entity->ftid) {
$form_state['redirect'] = 'test-entity/manage/' . $entity->ftid . '/edit';
}
else {
// Error on save.
drupal_set_message(t('The entity could not be saved.'), 'error');
$form_state['rebuild'] = TRUE;
}
}
/**
* Updates the form state's entity by processing this submission's values.
*/
function field_test_entity_form_submit_build_test_entity($form, &$form_state) {
$entity = $form_state['test_entity'];
entity_form_submit_build_entity('test_entity', $entity, $form, $form_state);
return $entity;
}
/**
* Form combining two separate entities.
*/
function field_test_entity_nested_form($form, &$form_state, $entity_1, $entity_2) {
// First entity.
foreach (array('ftid', 'ftvid', 'fttype') as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => $entity_1->$key,
);
}
field_attach_form('test_entity', $entity_1, $form, $form_state);
// Second entity.
$form['entity_2'] = array(
'#type' => 'fieldset',
'#title' => t('Second entity'),
'#tree' => TRUE,
'#parents' => array('entity_2'),
'#weight' => 50,
);
foreach (array('ftid', 'ftvid', 'fttype') as $key) {
$form['entity_2'][$key] = array(
'#type' => 'value',
'#value' => $entity_2->$key,
);
}
field_attach_form('test_entity', $entity_2, $form['entity_2'], $form_state);
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
'#weight' => 100,
);
return $form;
}
/**
* Validate handler for field_test_entity_nested_form().
*/
function field_test_entity_nested_form_validate($form, &$form_state) {
$entity_1 = (object) $form_state['values'];
field_attach_form_validate('test_entity', $entity_1, $form, $form_state);
$entity_2 = (object) $form_state['values']['entity_2'];
field_attach_form_validate('test_entity', $entity_2, $form['entity_2'], $form_state);
}
/**
* Submit handler for field_test_entity_nested_form().
*/
function field_test_entity_nested_form_submit($form, &$form_state) {
$entity_1 = (object) $form_state['values'];
field_attach_submit('test_entity', $entity_1, $form, $form_state);
field_test_entity_save($entity_1);
$entity_2 = (object) $form_state['values']['entity_2'];
field_attach_submit('test_entity', $entity_2, $form['entity_2'], $form_state);
field_test_entity_save($entity_2);
drupal_set_message(t('test_entities @id_1 and @id_2 have been updated.', array('@id_1' => $entity_1->ftid, '@id_2' => $entity_2->ftid)));
}
/**
* Controller class for the test_entity_bundle entity type.
*
* This extends the DrupalDefaultEntityController class, adding required
* special handling for bundles (since they are not stored in the database).
*/
class TestEntityBundleController extends DrupalDefaultEntityController {
protected function attachLoad(&$entities, $revision_id = FALSE) {
// Add bundle information.
foreach ($entities as $key => $entity) {
$entity->fttype = 'test_entity_bundle';
$entities[$key] = $entity;
}
parent::attachLoad($entities, $revision_id);
}
}

View file

@ -0,0 +1,413 @@
<?php
/**
* @file
* Defines a field type and its formatters and widgets.
*/
/**
* Implements hook_field_info().
*/
function field_test_field_info() {
return array(
'test_field' => array(
'label' => t('Test field'),
'description' => t('Dummy field type used for tests.'),
'settings' => array(
'test_field_setting' => 'dummy test string',
'changeable' => 'a changeable field setting',
'unchangeable' => 'an unchangeable field setting',
),
'instance_settings' => array(
'test_instance_setting' => 'dummy test string',
'test_hook_field_load' => FALSE,
),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
),
'shape' => array(
'label' => t('Shape'),
'description' => t('Another dummy field type.'),
'settings' => array(
'foreign_key_name' => 'shape',
),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
),
'hidden_test_field' => array(
'no_ui' => TRUE,
'label' => t('Hidden from UI test field'),
'description' => t('Dummy hidden field type used for tests.'),
'settings' => array(),
'instance_settings' => array(),
'default_widget' => 'test_field_widget',
'default_formatter' => 'field_test_default',
),
);
}
/**
* Implements hook_field_update_forbid().
*/
function field_test_field_update_forbid($field, $prior_field, $has_data) {
if ($field['type'] == 'test_field' && $field['settings']['unchangeable'] != $prior_field['settings']['unchangeable']) {
throw new FieldException("field_test 'unchangeable' setting cannot be changed'");
}
}
/**
* Implements hook_field_load().
*/
function field_test_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
foreach ($items as $id => $item) {
// To keep the test non-intrusive, only act for instances with the
// test_hook_field_load setting explicitly set to TRUE.
if ($instances[$id]['settings']['test_hook_field_load']) {
foreach ($item as $delta => $value) {
// Don't add anything on empty values.
if ($value) {
$items[$id][$delta]['additional_key'] = 'additional_value';
}
}
}
}
}
/**
* Implements hook_field_insert().
*/
function field_test_field_insert($entity_type, $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_update().
*/
function field_test_field_update($entity_type, $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_delete().
*/
function field_test_field_delete($entity_type, $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_field_validate().
*
* Possible error codes:
* - 'field_test_invalid': The value is invalid.
*/
function field_test_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
foreach ($items as $delta => $item) {
if ($item['value'] == -1) {
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'field_test_invalid',
'message' => t('%name does not accept the value -1.', array('%name' => $instance['label'])),
);
}
}
}
/**
* Implements hook_field_is_empty().
*/
function field_test_field_is_empty($item, $field) {
return empty($item['value']);
}
/**
* Implements hook_field_settings_form().
*/
function field_test_field_settings_form($field, $instance, $has_data) {
$settings = $field['settings'];
$form['test_field_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field setting'),
'#default_value' => $settings['test_field_setting'],
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field setting.'),
);
return $form;
}
/**
* Implements hook_field_instance_settings_form().
*/
function field_test_field_instance_settings_form($field, $instance) {
$settings = $instance['settings'];
$form['test_instance_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field instance setting'),
'#default_value' => $settings['test_instance_setting'],
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field instance setting.'),
);
return $form;
}
/**
* Implements hook_field_widget_info().
*/
function field_test_field_widget_info() {
return array(
'test_field_widget' => array(
'label' => t('Test field'),
'field types' => array('test_field', 'hidden_test_field'),
'settings' => array('test_widget_setting' => 'dummy test string'),
),
'test_field_widget_multiple' => array(
'label' => t('Test field 1'),
'field types' => array('test_field'),
'settings' => array('test_widget_setting_multiple' => 'dummy test string'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
),
),
);
}
/**
* Implements hook_field_widget_form().
*/
function field_test_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
switch ($instance['widget']['type']) {
case 'test_field_widget':
$element += array(
'#type' => 'textfield',
'#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
);
return array('value' => $element);
case 'test_field_widget_multiple':
$values = array();
foreach ($items as $delta => $value) {
$values[] = $value['value'];
}
$element += array(
'#type' => 'textfield',
'#default_value' => implode(', ', $values),
'#element_validate' => array('field_test_widget_multiple_validate'),
);
return $element;
}
}
/**
* Form element validation handler for 'test_field_widget_multiple' widget.
*/
function field_test_widget_multiple_validate($element, &$form_state) {
$values = array_map('trim', explode(',', $element['#value']));
$items = array();
foreach ($values as $value) {
$items[] = array('value' => $value);
}
form_set_value($element, $items, $form_state);
}
/**
* Implements hook_field_widget_error().
*/
function field_test_field_widget_error($element, $error, $form, &$form_state) {
// @todo No easy way to differenciate widget types, we should receive it as a
// parameter.
if (isset($element['value'])) {
// Widget is test_field_widget.
$error_element = $element['value'];
}
else {
// Widget is test_field_widget_multiple.
$error_element = $element;
}
form_error($error_element, $error['message']);
}
/**
* Implements hook_field_widget_settings_form().
*/
function field_test_field_widget_settings_form($field, $instance) {
$widget = $instance['widget'];
$settings = $widget['settings'];
$form['test_widget_setting'] = array(
'#type' => 'textfield',
'#title' => t('Field test field widget setting'),
'#default_value' => $settings['test_widget_setting'],
'#required' => FALSE,
'#description' => t('A dummy form element to simulate field widget setting.'),
);
return $form;
}
/**
* Implements hook_field_formatter_info().
*/
function field_test_field_formatter_info() {
return array(
'field_test_default' => array(
'label' => t('Default'),
'description' => t('Default formatter'),
'field types' => array('test_field'),
'settings' => array(
'test_formatter_setting' => 'dummy test string',
),
),
'field_test_multiple' => array(
'label' => t('Multiple'),
'description' => t('Multiple formatter'),
'field types' => array('test_field'),
'settings' => array(
'test_formatter_setting_multiple' => 'dummy test string',
),
),
'field_test_with_prepare_view' => array(
'label' => t('Tests hook_field_formatter_prepare_view()'),
'field types' => array('test_field'),
'settings' => array(
'test_formatter_setting_additional' => 'dummy test string',
),
),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function field_test_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$element = array();
// The name of the setting depends on the formatter type.
$map = array(
'field_test_default' => 'test_formatter_setting',
'field_test_multiple' => 'test_formatter_setting_multiple',
'field_test_with_prepare_view' => 'test_formatter_setting_additional',
);
if (isset($map[$display['type']])) {
$name = $map[$display['type']];
$element[$name] = array(
'#title' => t('Setting'),
'#type' => 'textfield',
'#size' => 20,
'#default_value' => $settings[$name],
'#required' => TRUE,
);
}
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function field_test_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = '';
// The name of the setting depends on the formatter type.
$map = array(
'field_test_default' => 'test_formatter_setting',
'field_test_multiple' => 'test_formatter_setting_multiple',
'field_test_with_prepare_view' => 'test_formatter_setting_additional',
);
if (isset($map[$display['type']])) {
$name = $map[$display['type']];
$summary = t('@setting: @value', array('@setting' => $name, '@value' => $settings[$name]));
}
return $summary;
}
/**
* Implements hook_field_formatter_prepare_view().
*/
function field_test_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
foreach ($items as $id => $item) {
// To keep the test non-intrusive, only act on the
// 'field_test_with_prepare_view' formatter.
if ($displays[$id]['type'] == 'field_test_with_prepare_view') {
foreach ($item as $delta => $value) {
// Don't add anything on empty values.
if ($value) {
$items[$id][$delta]['additional_formatter_value'] = $value['value'] + 1;
}
}
}
}
}
/**
* Implements hook_field_formatter_view().
*/
function field_test_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
$settings = $display['settings'];
switch ($display['type']) {
case 'field_test_default':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $settings['test_formatter_setting'] . '|' . $item['value']);
}
break;
case 'field_test_with_prepare_view':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $settings['test_formatter_setting_additional'] . '|' . $item['value'] . '|' . $item['additional_formatter_value']);
}
break;
case 'field_test_multiple':
if (!empty($items)) {
$array = array();
foreach ($items as $delta => $item) {
$array[] = $delta . ':' . $item['value'];
}
$element[0] = array('#markup' => $settings['test_formatter_setting_multiple'] . '|' . implode('|', $array));
}
break;
}
return $element;
}
/**
* Sample 'default value' callback.
*/
function field_test_default_value($entity_type, $entity, $field, $instance) {
return array(array('value' => 99));
}
/**
* Implements hook_field_access().
*/
function field_test_field_access($op, $field, $entity_type, $entity, $account) {
if ($field['field_name'] == "field_no_{$op}_access") {
return FALSE;
}
return TRUE;
}

View file

@ -0,0 +1,13 @@
name = "Field API Test"
description = "Support module for the Field API tests."
core = 7.x
package = Testing
files[] = field_test.entity.inc
version = VERSION
hidden = TRUE
; Information added by Drupal.org packaging script on 2017-06-21
version = "7.56"
project = "drupal"
datestamp = "1498069849"

View file

@ -0,0 +1,162 @@
<?php
/**
* @file
* Install, update and uninstall functions for the field_test module.
*/
/**
* Implements hook_install().
*/
function field_test_install() {
// hook_entity_info_alter() needs to be executed as last.
db_update('system')
->fields(array('weight' => 1))
->condition('name', 'field_test')
->execute();
}
/**
* Implements hook_schema().
*/
function field_test_schema() {
$schema['test_entity'] = array(
'description' => 'The base table for test_entities.',
'fields' => array(
'ftid' => array(
'description' => 'The primary identifier for a test_entity.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'ftvid' => array(
'description' => 'The current {test_entity_revision}.ftvid version identifier.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'fttype' => array(
'description' => 'The type of this test_entity.',
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'default' => '',
),
'ftlabel' => array(
'description' => 'The label of this test_entity.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
),
'unique keys' => array(
'ftvid' => array('ftvid'),
),
'primary key' => array('ftid'),
);
$schema['test_entity_bundle_key'] = array(
'description' => 'The base table for test entities with a bundle key.',
'fields' => array(
'ftid' => array(
'description' => 'The primary identifier for a test_entity_bundle_key.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'fttype' => array(
'description' => 'The type of this test_entity.',
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
'default' => '',
),
),
);
$schema['test_entity_bundle'] = array(
'description' => 'The base table for test entities with a bundle.',
'fields' => array(
'ftid' => array(
'description' => 'The primary identifier for a test_entity_bundle.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
),
);
$schema['test_entity_revision'] = array(
'description' => 'Stores information about each saved version of a {test_entity}.',
'fields' => array(
'ftid' => array(
'description' => 'The {test_entity} this version belongs to.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'ftvid' => array(
'description' => 'The primary identifier for this version.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'indexes' => array(
'nid' => array('ftid'),
),
'primary key' => array('ftvid'),
);
return $schema;
}
/**
* Implements hook_field_schema().
*/
function field_test_field_schema($field) {
if ($field['type'] == 'test_field') {
return array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'medium',
'not null' => FALSE,
),
),
'indexes' => array(
'value' => array('value'),
),
);
}
else {
$foreign_keys = array();
// The 'foreign keys' key is not always used in tests.
if (!empty($field['settings']['foreign_key_name'])) {
$foreign_keys['foreign keys'] = array(
// This is a dummy foreign key definition, references a table that
// doesn't exist, but that's not a problem.
$field['settings']['foreign_key_name'] => array(
'table' => $field['settings']['foreign_key_name'],
'columns' => array($field['settings']['foreign_key_name'] => 'id'),
),
);
}
return array(
'columns' => array(
'shape' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
'color' => array(
'type' => 'varchar',
'length' => 32,
'not null' => FALSE,
),
),
) + $foreign_keys;
}
}

View file

@ -0,0 +1,284 @@
<?php
/**
* @file
* Helper module for the Field API tests.
*
* The module defines
* - an entity type (field_test.entity.inc)
* - a field type and its formatters and widgets (field_test.field.inc)
* - a field storage backend (field_test.storage.inc)
*
* The main field_test.module file implements generic hooks and provides some
* test helper functions
*/
require_once DRUPAL_ROOT . '/modules/field/tests/field_test.entity.inc';
require_once DRUPAL_ROOT . '/modules/field/tests/field_test.field.inc';
require_once DRUPAL_ROOT . '/modules/field/tests/field_test.storage.inc';
/**
* Implements hook_permission().
*/
function field_test_permission() {
$perms = array(
'access field_test content' => array(
'title' => t('Access field_test content'),
'description' => t('View published field_test content.'),
),
'administer field_test content' => array(
'title' => t('Administer field_test content'),
'description' => t('Manage field_test content'),
),
);
return $perms;
}
/**
* Implements hook_menu().
*/
function field_test_menu() {
$items = array();
$bundles = field_info_bundles('test_entity');
foreach ($bundles as $bundle_name => $bundle_info) {
$bundle_url_str = str_replace('_', '-', $bundle_name);
$items['test-entity/add/' . $bundle_url_str] = array(
'title' => t('Add %bundle test_entity', array('%bundle' => $bundle_info['label'])),
'page callback' => 'field_test_entity_add',
'page arguments' => array(2),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
}
$items['test-entity/manage/%field_test_entity_test/edit'] = array(
'title' => 'Edit test entity',
'page callback' => 'field_test_entity_edit',
'page arguments' => array(2),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
$items['test-entity/nested/%field_test_entity_test/%field_test_entity_test'] = array(
'title' => 'Nested entity form',
'page callback' => 'drupal_get_form',
'page arguments' => array('field_test_entity_nested_form', 2, 3),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
/**
* Generic op to test _field_invoke behavior.
*
* This simulates a field operation callback to be invoked by _field_invoke().
*/
function field_test_field_test_op($entity_type, $entity, $field, $instance, $langcode, &$items) {
return array($langcode => hash('sha256', serialize(array($entity_type, $entity, $field['field_name'], $langcode, $items))));
}
/**
* Generic op to test _field_invoke_multiple behavior.
*
* This simulates a multiple field operation callback to be invoked by
* _field_invoke_multiple().
*/
function field_test_field_test_op_multiple($entity_type, $entities, $field, $instances, $langcode, &$items) {
$result = array();
foreach ($entities as $id => $entity) {
// Entities, instances and items are assumed to be consistently grouped by
// language. To verify this we try to access all the passed data structures
// by entity id. If they are grouped correctly, one entity, one instance and
// one array of items should be available for each entity id.
$field_name = $instances[$id]['field_name'];
$result[$id] = array($langcode => hash('sha256', serialize(array($entity_type, $entity, $field_name, $langcode, $items[$id]))));
}
return $result;
}
/**
* Implements hook_field_available_languages_alter().
*/
function field_test_field_available_languages_alter(&$languages, $context) {
if (variable_get('field_test_field_available_languages_alter', FALSE)) {
// Add an unavailable language.
$languages[] = 'xx';
// Remove an available language.
$index = array_search('en', $languages);
unset($languages[$index]);
}
}
/**
* Implements hook_field_language_alter().
*/
function field_test_field_language_alter(&$display_language, $context) {
if (variable_get('field_test_language_fallback', TRUE)) {
locale_field_language_fallback($display_language, $context['entity'], $context['language']);
}
}
/**
* Store and retrieve keyed data for later verification by unit tests.
*
* This function is a simple in-memory key-value store with the
* distinction that it stores all values for a given key instead of
* just the most recently set value. field_test module hooks call
* this function to record their arguments, keyed by hook name. The
* unit tests later call this function to verify that the correct
* hooks were called and were passed the correct arguments.
*
* This function ignores all calls until the first time it is called
* with $key of NULL. Each time it is called with $key of NULL, it
* erases all previously stored data from its internal cache, but also
* returns the previously stored data to the caller. A typical usage
* scenario is:
*
* @code
* // calls to field_test_memorize() here are ignored
*
* // turn on memorization
* field_test_memorize();
*
* // call some Field API functions that invoke field_test hooks
* $field = field_create_field(...);
*
* // retrieve and reset the memorized hook call data
* $mem = field_test_memorize();
*
* // make sure hook_field_create_field() is invoked correctly
* assertEqual(count($mem['field_test_field_create_field']), 1);
* assertEqual($mem['field_test_field_create_field'][0], array($field));
* @endcode
*
* @param $key
* The key under which to store to $value, or NULL as described above.
* @param $value
* A value to store for $key.
* @return
* An array mapping each $key to an array of each $value passed in
* for that key.
*/
function field_test_memorize($key = NULL, $value = NULL) {
$memorize = &drupal_static(__FUNCTION__, NULL);
if (!isset($key)) {
$return = $memorize;
$memorize = array();
return $return;
}
if (is_array($memorize)) {
$memorize[$key][] = $value;
}
}
/**
* Memorize calls to hook_field_create_field().
*/
function field_test_field_create_field($field) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Implements hook_entity_query_alter().
*/
function field_test_entity_query_alter(&$query) {
if (!empty($query->alterMyExecuteCallbackPlease)) {
$query->executeCallback = 'field_test_dummy_field_storage_query';
}
}
/**
* Pseudo-implements hook_field_storage_query().
*/
function field_test_dummy_field_storage_query(EntityFieldQuery $query) {
// Return dummy values that will be checked by the test.
return array(
'user' => array(
1 => entity_create_stub_entity('user', array(1, NULL, NULL)),
),
);
}
/**
* Implements callback_entity_info_label().
*
* @return
* The label of the entity prefixed with "label callback".
*/
function field_test_entity_label_callback($entity) {
return 'label callback ' . $entity->ftlabel;
}
/**
* Implements hook_field_attach_view_alter().
*/
function field_test_field_attach_view_alter(&$output, $context) {
if (!empty($context['display']['settings']['alter'])) {
$output['test_field'][] = array('#markup' => 'field_test_field_attach_view_alter');
}
if (isset($output['test_field'])) {
$output['test_field'][] = array('#markup' => 'field language is ' . $context['language']);
}
}
/**
* Implements hook_field_widget_properties_alter().
*/
function field_test_field_widget_properties_alter(&$widget, $context) {
// Make the alter_test_text field 42 characters for nodes and comments.
if (in_array($context['entity_type'], array('node', 'comment')) && ($context['field']['field_name'] == 'alter_test_text')) {
$widget['settings']['size'] = 42;
}
}
/**
* Implements hook_field_widget_properties_ENTITY_TYPE_alter().
*/
function field_test_field_widget_properties_user_alter(&$widget, $context) {
// Always use buttons for the alter_test_options field on user forms.
if ($context['field']['field_name'] == 'alter_test_options') {
$widget['type'] = 'options_buttons';
}
}
/**
* Implements hook_field_widget_form_alter().
*/
function field_test_field_widget_form_alter(&$element, &$form_state, $context) {
switch ($context['field']['field_name']) {
case 'alter_test_text':
drupal_set_message('Field size: ' . $context['instance']['widget']['settings']['size']);
break;
case 'alter_test_options':
drupal_set_message('Widget type: ' . $context['instance']['widget']['type']);
break;
}
}
/**
* Implements hook_query_TAG_alter() for tag 'efq_table_prefixing_test'.
*
* @see EntityFieldQueryTestCase::testTablePrefixing()
*/
function field_test_query_efq_table_prefixing_test_alter(&$query) {
// Add an additional join onto the entity base table. This will cause an
// exception if the EFQ does not properly prefix the base table.
$query->join('test_entity','te2','%alias.ftid = test_entity.ftid');
}
/**
* Implements hook_query_TAG_alter() for tag 'store_global_test_query'.
*/
function field_test_query_store_global_test_query_alter($query) {
// Save the query in a global variable so that it can be examined by tests.
// This can be used by any test which needs to check a query, but see
// FieldSqlStorageTestCase::testFieldSqlStorageMultipleConditionsSameColumn()
// for an example.
$GLOBALS['test_query'] = $query;
}

View file

@ -0,0 +1,473 @@
<?php
/**
* @file
* Defines a field storage backend.
*/
/**
* Implements hook_field_storage_info().
*/
function field_test_field_storage_info() {
return array(
'field_test_storage' => array(
'label' => t('Test storage'),
'description' => t('Dummy test storage backend. Stores field values in the variable table.'),
),
'field_test_storage_failure' => array(
'label' => t('Test storage failure'),
'description' => t('Dummy test storage backend. Always fails to create fields.'),
),
);
}
/**
* Implements hook_field_storage_details().
*/
function field_test_field_storage_details($field) {
$details = array();
// Add field columns.
$columns = array();
foreach ((array) $field['columns'] as $column_name => $attributes) {
$columns[$column_name] = $column_name;
}
return array(
'drupal_variables' => array(
'field_test_storage_data[FIELD_LOAD_CURRENT]' => $columns,
'field_test_storage_data[FIELD_LOAD_REVISION]' => $columns,
),
);
}
/**
* Implements hook_field_storage_details_alter().
*
* @see FieldAttachStorageTestCase::testFieldStorageDetailsAlter()
*/
function field_test_field_storage_details_alter(&$details, $field) {
// For testing, storage details are changed only because of the field name.
if ($field['field_name'] == 'field_test_change_my_details') {
$columns = array();
foreach ((array) $field['columns'] as $column_name => $attributes) {
$columns[$column_name] = $column_name;
}
$details['drupal_variables'] = array(
FIELD_LOAD_CURRENT => array(
'moon' => $columns,
),
FIELD_LOAD_REVISION => array(
'mars' => $columns,
),
);
}
}
/**
* Helper function: stores or retrieves data from the 'storage backend'.
*/
function _field_test_storage_data($data = NULL) {
if (!isset($data)) {
return variable_get('field_test_storage_data', array());
}
else {
variable_set('field_test_storage_data', $data);
}
}
/**
* Implements hook_field_storage_load().
*/
function field_test_field_storage_load($entity_type, $entities, $age, $fields, $options) {
$data = _field_test_storage_data();
$load_current = $age == FIELD_LOAD_CURRENT;
foreach ($fields as $field_id => $ids) {
$field = field_info_field_by_id($field_id);
$field_name = $field['field_name'];
$field_data = $data[$field['id']];
$sub_table = $load_current ? 'current' : 'revisions';
$delta_count = array();
foreach ($field_data[$sub_table] as $row) {
if ($row->type == $entity_type && (!$row->deleted || $options['deleted'])) {
if (($load_current && in_array($row->entity_id, $ids)) || (!$load_current && in_array($row->revision_id, $ids))) {
if (in_array($row->language, field_available_languages($entity_type, $field))) {
if (!isset($delta_count[$row->entity_id][$row->language])) {
$delta_count[$row->entity_id][$row->language] = 0;
}
if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta_count[$row->entity_id][$row->language] < $field['cardinality']) {
$item = array();
foreach ($field['columns'] as $column => $attributes) {
$item[$column] = $row->{$column};
}
$entities[$row->entity_id]->{$field_name}[$row->language][] = $item;
$delta_count[$row->entity_id][$row->language]++;
}
}
}
}
}
}
}
/**
* Implements hook_field_storage_write().
*/
function field_test_field_storage_write($entity_type, $entity, $op, $fields) {
$data = _field_test_storage_data();
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
foreach ($fields as $field_id) {
$field = field_info_field_by_id($field_id);
$field_name = $field['field_name'];
$field_data = &$data[$field_id];
$all_languages = field_available_languages($entity_type, $field);
$field_languages = array_intersect($all_languages, array_keys((array) $entity->$field_name));
// Delete and insert, rather than update, in case a value was added.
if ($op == FIELD_STORAGE_UPDATE) {
// Delete languages present in the incoming $entity->$field_name.
// Delete all languages if $entity->$field_name is empty.
$languages = !empty($entity->$field_name) ? $field_languages : $all_languages;
if ($languages) {
foreach ($field_data['current'] as $key => $row) {
if ($row->type == $entity_type && $row->entity_id == $id && in_array($row->language, $languages)) {
unset($field_data['current'][$key]);
}
}
if (isset($vid)) {
foreach ($field_data['revisions'] as $key => $row) {
if ($row->type == $entity_type && $row->revision_id == $vid) {
unset($field_data['revisions'][$key]);
}
}
}
}
}
foreach ($field_languages as $langcode) {
$items = (array) $entity->{$field_name}[$langcode];
$delta_count = 0;
foreach ($items as $delta => $item) {
$row = (object) array(
'field_id' => $field_id,
'type' => $entity_type,
'entity_id' => $id,
'revision_id' => $vid,
'bundle' => $bundle,
'delta' => $delta,
'deleted' => FALSE,
'language' => $langcode,
);
foreach ($field['columns'] as $column => $attributes) {
$row->{$column} = isset($item[$column]) ? $item[$column] : NULL;
}
$field_data['current'][] = $row;
if (isset($vid)) {
$field_data['revisions'][] = $row;
}
if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ++$delta_count == $field['cardinality']) {
break;
}
}
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_storage_delete().
*/
function field_test_field_storage_delete($entity_type, $entity, $fields) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
// Note: reusing field_test_storage_purge(), like field_sql_storage.module
// does, is highly inefficient in our case...
foreach (field_info_instances($bundle) as $instance) {
if (isset($fields[$instance['field_id']])) {
$field = field_info_field_by_id($instance['field_id']);
field_test_field_storage_purge($entity_type, $entity, $field, $instance);
}
}
}
/**
* Implements hook_field_storage_purge().
*/
function field_test_field_storage_purge($entity_type, $entity, $field, $instance) {
$data = _field_test_storage_data();
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$field_data = &$data[$field['id']];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as $key => $row) {
if ($row->type == $entity_type && $row->entity_id == $id) {
unset($field_data[$sub_table][$key]);
}
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_storage_delete_revision().
*/
function field_test_field_storage_delete_revision($entity_type, $entity, $fields) {
$data = _field_test_storage_data();
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
foreach ($fields as $field_id) {
$field_data = &$data[$field_id];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as $key => $row) {
if ($row->type == $entity_type && $row->entity_id == $id && $row->revision_id == $vid) {
unset($field_data[$sub_table][$key]);
}
}
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_storage_query().
*/
function field_test_field_storage_query($field_id, $conditions, $count, &$cursor = NULL, $age) {
$data = _field_test_storage_data();
$load_current = $age == FIELD_LOAD_CURRENT;
$field = field_info_field_by_id($field_id);
$field_columns = array_keys($field['columns']);
$field_data = $data[$field['id']];
$sub_table = $load_current ? 'current' : 'revisions';
// We need to sort records by entity type and entity id.
usort($field_data[$sub_table], '_field_test_field_storage_query_sort_helper');
// Initialize results array.
$return = array();
$entity_count = 0;
$rows_count = 0;
$rows_total = count($field_data[$sub_table]);
$skip = $cursor;
$skipped = 0;
foreach ($field_data[$sub_table] as $row) {
if ($count != FIELD_QUERY_NO_LIMIT && $entity_count >= $count) {
break;
}
if ($row->field_id == $field['id']) {
$match = TRUE;
$condition_deleted = FALSE;
// Add conditions.
foreach ($conditions as $condition) {
@list($column, $value, $operator) = $condition;
if (empty($operator)) {
$operator = is_array($value) ? 'IN' : '=';
}
switch ($operator) {
case '=':
$match = $match && $row->{$column} == $value;
break;
case '<>':
case '<':
case '<=':
case '>':
case '>=':
eval('$match = $match && ' . $row->{$column} . ' ' . $operator . ' '. $value);
break;
case 'IN':
$match = $match && in_array($row->{$column}, $value);
break;
case 'NOT IN':
$match = $match && !in_array($row->{$column}, $value);
break;
case 'BETWEEN':
$match = $match && $row->{$column} >= $value[0] && $row->{$column} <= $value[1];
break;
case 'STARTS_WITH':
case 'ENDS_WITH':
case 'CONTAINS':
// Not supported.
$match = FALSE;
break;
}
// Track condition on 'deleted'.
if ($column == 'deleted') {
$condition_deleted = TRUE;
}
}
// Exclude deleted data unless we have a condition on it.
if (!$condition_deleted && $row->deleted) {
$match = FALSE;
}
if ($match) {
if (!isset($skip) || $skipped >= $skip) {
$cursor++;
// If querying all revisions and the entity type has revisions, we need
// to key the results by revision_ids.
$entity_type = entity_get_info($row->type);
$id = ($load_current || empty($entity_type['entity keys']['revision'])) ? $row->entity_id : $row->revision_id;
if (!isset($return[$row->type][$id])) {
$return[$row->type][$id] = entity_create_stub_entity($row->type, array($row->entity_id, $row->revision_id, $row->bundle));
$entity_count++;
}
}
else {
$skipped++;
}
}
}
$rows_count++;
// The query is complete if we walked the whole array.
if ($count != FIELD_QUERY_NO_LIMIT && $rows_count >= $rows_total) {
$cursor = FIELD_QUERY_COMPLETE;
}
}
return $return;
}
/**
* Sort helper for field_test_field_storage_query().
*
* Sorts by entity type and entity id.
*/
function _field_test_field_storage_query_sort_helper($a, $b) {
if ($a->type == $b->type) {
if ($a->entity_id == $b->entity_id) {
return 0;
}
else {
return $a->entity_id < $b->entity_id ? -1 : 1;
}
}
else {
return $a->type < $b->type ? -1 : 1;
}
}
/**
* Implements hook_field_storage_create_field().
*/
function field_test_field_storage_create_field($field) {
if ($field['storage']['type'] == 'field_test_storage_failure') {
throw new Exception('field_test_storage_failure engine always fails to create fields');
}
$data = _field_test_storage_data();
$data[$field['id']] = array(
'current' => array(),
'revisions' => array(),
);
_field_test_storage_data($data);
}
/**
* Implements hook_field_storage_delete_field().
*/
function field_test_field_storage_delete_field($field) {
$data = _field_test_storage_data();
$field_data = &$data[$field['id']];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as &$row) {
$row->deleted = TRUE;
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_storage_delete_instance().
*/
function field_test_field_storage_delete_instance($instance) {
$data = _field_test_storage_data();
$field = field_info_field($instance['field_name']);
$field_data = &$data[$field['id']];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as &$row) {
if ($row->bundle == $instance['bundle']) {
$row->deleted = TRUE;
}
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_attach_create_bundle().
*/
function field_test_field_attach_create_bundle($bundle) {
// We don't need to do anything here.
}
/**
* Implements hook_field_attach_rename_bundle().
*/
function field_test_field_attach_rename_bundle($bundle_old, $bundle_new) {
$data = _field_test_storage_data();
// We need to account for deleted or inactive fields and instances.
$instances = field_read_instances(array('bundle' => $bundle_new), array('include_deleted' => TRUE, 'include_inactive' => TRUE));
foreach ($instances as $field_name => $instance) {
$field = field_info_field_by_id($instance['field_id']);
if ($field['storage']['type'] == 'field_test_storage') {
$field_data = &$data[$field['id']];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as &$row) {
if ($row->bundle == $bundle_old) {
$row->bundle = $bundle_new;
}
}
}
}
}
_field_test_storage_data($data);
}
/**
* Implements hook_field_attach_delete_bundle().
*/
function field_test_field_attach_delete_bundle($entity_type, $bundle, $instances) {
$data = _field_test_storage_data();
foreach ($instances as $field_name => $instance) {
$field = field_info_field($field_name);
if ($field['storage']['type'] == 'field_test_storage') {
$field_data = &$data[$field['id']];
foreach (array('current', 'revisions') as $sub_table) {
foreach ($field_data[$sub_table] as &$row) {
if ($row->bundle == $bundle_old) {
$row->deleted = TRUE;
}
}
}
}
}
_field_test_storage_data($data);
}