Issue #1371938 by yched, Everett Zufelt, xjm, casey: Fixed hook_field_delete() no longer invoked during field_purge_data().

8.0.x
catch 2012-01-13 22:41:01 +09:00
parent 8a3f461360
commit 123249f208
4 changed files with 129 additions and 45 deletions

View File

@ -194,8 +194,10 @@ function _field_invoke($op, $entity_type, $entity, &$a = NULL, &$b = NULL, $opti
// Iterate through the instances and collect results.
$return = array();
foreach ($instances as $instance) {
$field_name = $instance['field_name'];
$field = field_info_field($field_name);
// field_info_field() is not available for deleted fields, so use
// field_info_field_by_id().
$field = field_info_field_by_id($instance['field_id']);
$field_name = $field['field_name'];
$function = $options['default'] ? 'field_default_' . $op : $field['module'] . '_field_' . $op;
if (function_exists($function)) {
// Determine the list of languages to iterate on.
@ -703,7 +705,8 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
}
// Invoke field-type module's hook_field_load().
_field_invoke_multiple('load', $entity_type, $queried_entities, $age, $options);
$null = NULL;
_field_invoke_multiple('load', $entity_type, $queried_entities, $age, $null, $options);
// Invoke hook_field_attach_load(): let other modules act on loading the
// entitiy.

View File

@ -2994,22 +2994,54 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
*/
function _generateStubEntities($entity_type, $entities, $field_name = NULL) {
$stubs = array();
foreach ($entities as $entity) {
foreach ($entities as $id => $entity) {
$stub = entity_create_stub_entity($entity_type, entity_extract_ids($entity_type, $entity));
if (isset($field_name)) {
$stub->{$field_name} = $entity->{$field_name};
}
$stubs[] = $stub;
$stubs[$id] = $stub;
}
return $stubs;
}
/**
* Tests that the expected hooks have been invoked on the expected entities.
*
* @param $expected_hooks
* An array keyed by hook name, with one entry per expected invocation.
* Each entry is the value of the "$entity" parameter the hook is expected
* to have been passed.
* @param $actual_hooks
* The array of actual hook invocations recorded by field_test_memorize().
*/
function checkHooksInvocations($expected_hooks, $actual_hooks) {
foreach ($expected_hooks as $hook => $invocations) {
$actual_invocations = $actual_hooks[$hook];
// Check that the number of invocations is correct.
$this->assertEqual(count($actual_invocations), count($invocations), "$hook() was called the expected number of times.");
// Check that the hook was called for each expected argument.
foreach ($invocations as $argument) {
$found = FALSE;
foreach ($actual_invocations as $actual_arguments) {
if ($actual_arguments[1] == $argument) {
$found = TRUE;
break;
}
}
$this->assertTrue($found, "$hook() was called on expected argument");
}
}
}
function setUp() {
parent::setUp('field_test');
// Clean up data from previous test cases.
$this->fields = array();
$this->instances = array();
$this->entities = array();
$this->entities_by_bundles = array();
// Create two bundles.
$this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2');
@ -3045,7 +3077,10 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
foreach ($this->fields as $field) {
$entity->{$field['field_name']}[LANGUAGE_NONE] = $this->_generateTestFieldValues($field['cardinality']);
}
$this->entities[$id] = $entity;
// Also keep track of the entities per bundle.
$this->entities_by_bundles[$bundle][$id] = $entity;
field_attach_insert($this->entity_type, $entity);
$id++;
}
@ -3110,6 +3145,7 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
* instance is deleted.
*/
function testPurgeInstance() {
// Start recording hook invocations.
field_test_memorize();
$bundle = reset($this->bundles);
@ -3124,7 +3160,7 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
$this->assertEqual(count($mem), 0, 'No field hooks were called');
$batch_size = 2;
for ($count = 8; $count >= 0; $count -= 2) {
for ($count = 8; $count >= 0; $count -= $batch_size) {
// Purge two entities.
field_purge_batch($batch_size);
@ -3138,19 +3174,21 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
$this->assertEqual($count ? count($found['test_entity']) : count($found), $count, 'Correct number of entities found after purging 2');
}
// hook_field_delete() was called on a pseudo-entity for each entity. Each
// pseudo entity has a $field property that matches the original entity,
// but no others.
$mem = field_test_memorize();
$this->assertEqual(count($mem['field_test_field_delete']), 10, 'hook_field_delete was called for the right number of entities');
$stubs = $this->_generateStubEntities($this->entity_type, $this->entities, $field['field_name']);
$count = count($stubs);
foreach ($mem['field_test_field_delete'] as $args) {
$entity = $args[1];
$this->assertEqual($stubs[$entity->ftid], $entity, 'hook_field_delete() called with the correct stub');
unset($stubs[$entity->ftid]);
// Check hooks invocations.
// - hook_field_load() (multiple hook) should have been called on all
// entities by pairs of two.
// - hook_field_delete() should have been called once for each entity in the
// bundle.
$actual_hooks = field_test_memorize();
$hooks = array();
$stubs = $this->_generateStubEntities($this->entity_type, $this->entities_by_bundles[$bundle], $field['field_name']);
foreach (array_chunk($stubs, $batch_size, TRUE) as $chunk) {
$hooks['field_test_field_load'][] = $chunk;
}
$this->assertEqual(count($stubs), $count-10, 'hook_field_delete was called with each entity once');
foreach ($stubs as $stub) {
$hooks['field_test_field_delete'][] = $stub;
}
$this->checkHooksInvocations($hooks, $actual_hooks);
// The instance still exists, deleted.
$instances = field_read_instances(array('field_id' => $field['id'], 'deleted' => 1), array('include_deleted' => 1, 'include_inactive' => 1));
@ -3173,15 +3211,37 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
* instances are deleted and purged.
*/
function testPurgeField() {
// Start recording hook invocations.
field_test_memorize();
$field = reset($this->fields);
// Delete the first instance.
$instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_1');
$bundle = reset($this->bundles);
$instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
field_delete_instance($instance);
// Assert that hook_field_delete() was not called yet.
$mem = field_test_memorize();
$this->assertEqual(count($mem), 0, 'No field hooks were called.');
// Purge the data.
field_purge_batch(10);
// Check hooks invocations.
// - hook_field_load() (multiple hook) should have been called once, for all
// entities in the bundle.
// - hook_field_delete() should have been called once for each entity in the
// bundle.
$actual_hooks = field_test_memorize();
$hooks = array();
$stubs = $this->_generateStubEntities($this->entity_type, $this->entities_by_bundles[$bundle], $field['field_name']);
$hooks['field_test_field_load'][] = $stubs;
foreach ($stubs as $stub) {
$hooks['field_test_field_delete'][] = $stub;
}
$this->checkHooksInvocations($hooks, $actual_hooks);
// Purge again to purge the instance.
field_purge_batch(0);
@ -3190,12 +3250,27 @@ class FieldBulkDeleteTestCase extends FieldTestCase {
$this->assertTrue(isset($fields[$field['id']]) && !$fields[$field['id']]['deleted'], 'The field exists and is not deleted');
// Delete the second instance.
$instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_2');
$bundle = next($this->bundles);
$instance = field_info_instance($this->entity_type, $field['field_name'], $bundle);
field_delete_instance($instance);
// Assert that hook_field_delete() was not called yet.
$mem = field_test_memorize();
$this->assertEqual(count($mem), 0, 'No field hooks were called.');
// Purge the data.
field_purge_batch(10);
// Check hooks invocations (same as above, for the 2nd bundle).
$actual_hooks = field_test_memorize();
$hooks = array();
$stubs = $this->_generateStubEntities($this->entity_type, $this->entities_by_bundles[$bundle], $field['field_name']);
$hooks['field_test_field_load'][] = $stubs;
foreach ($stubs as $stub) {
$hooks['field_test_field_delete'][] = $stub;
}
$this->checkHooksInvocations($hooks, $actual_hooks);
// The field still exists, deleted.
$fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1));
$this->assertTrue(isset($fields[$field['id']]) && $fields[$field['id']]['deleted'], 'The field exists and is deleted');

View File

@ -58,6 +58,9 @@ function field_test_field_update_forbid($field, $prior_field, $has_data) {
* 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.
@ -72,6 +75,30 @@ function field_test_field_load($entity_type, $entities, $field, $instances, $lan
}
}
/**
* 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().
*
@ -79,6 +106,9 @@ function field_test_field_load($entity_type, $entities, $field, $instances, $lan
* - '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(

View File

@ -182,30 +182,6 @@ function field_test_field_create_field($field) {
field_test_memorize(__FUNCTION__, $args);
}
/**
* Memorize calls to hook_field_insert().
*/
function field_test_field_insert($entity_type, $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Memorize calls to hook_field_update().
*/
function field_test_field_update($entity_type, $entity, $field, $instance, $items) {
$args = func_get_args();
field_test_memorize(__FUNCTION__, $args);
}
/**
* Memorize calls to 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_entity_query_alter().
*/