diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc index c643e40..e08e154 100644 --- a/modules/field/field.attach.inc +++ b/modules/field/field.attach.inc @@ -1341,7 +1341,8 @@ function field_attach_delete_bundle($entity_type, $bundle) { // disabled entity types or bundles. $instances = field_read_instances(array('entity_type' => $entity_type, 'bundle' => $bundle), array('include_inactive' => 1)); foreach ($instances as $instance) { - field_delete_instance($instance); + // Delete fields as we go along, but do not perform purges. + field_delete_instance($instance, TRUE, FALSE); } // Clear the cache. diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc index a6aaab1..1124590 100644 --- a/modules/field/field.crud.inc +++ b/modules/field/field.crud.inc @@ -384,8 +384,11 @@ function field_read_fields($params = array(), $include_additional = array()) { * * @param $field_name * The field name to delete. + * @param $purge + * (optional) If TRUE, the field deletion will be followed by a purge pass. + * Defaults to TRUE. */ -function field_delete_field($field_name) { +function field_delete_field($field_name, $purge = TRUE) { // Delete all non-deleted instances. $field = field_info_field($field_name); if (isset($field['bundles'])) { @@ -410,6 +413,16 @@ function field_delete_field($field_name) { field_cache_clear(TRUE); module_invoke_all('field_delete_field', $field); + + // Fields are purged on cron. However field module prevents disabling modules + // when field types they provided are used in a field until it is fully + // purged. In the case that a field has minimal or no content, a single call + // to field_purge_batch() will remove it from the system at once and avoid + // administrators having to wait for cron runs when removing instances that + // meet this criteria. + if ($purge) { + field_purge_batch(10, $field['id']); + } } /** @@ -726,11 +739,14 @@ function field_read_instances($params = array(), $include_additional = array()) * @param $instance * An instance structure. * @param $field_cleanup - * If TRUE, the field will be deleted as well if its last instance is being - * deleted. If FALSE, it is the caller's responsability to handle the case of - * fields left without instances. Defaults to TRUE. + * (optional) If TRUE, the field will be deleted as well if its last instance + * is being deleted. If FALSE, it is the caller's responsability to handle the + * case of fields left without instances. Defaults to TRUE. + * @param $purge + * (optional) If TRUE and $field_cleanup is TRUE, the field deletion will be + * followed by a purge pass. Defaults to TRUE. */ -function field_delete_instance($instance, $field_cleanup = TRUE) { +function field_delete_instance($instance, $field_cleanup = TRUE, $purge = TRUE) { // Mark the field instance for deletion. db_update('field_config_instance') ->fields(array('deleted' => 1)) @@ -751,7 +767,7 @@ function field_delete_instance($instance, $field_cleanup = TRUE) { // Delete the field itself if we just deleted its last instance. if ($field_cleanup && count($field['bundles']) == 0) { - field_delete_field($field['field_name']); + field_delete_field($field['field_name'], $purge); } } @@ -837,11 +853,17 @@ function field_delete_instance($instance, $field_cleanup = TRUE) { * * @param $batch_size * The maximum number of field data records to purge before returning. + * @param $field_id + * @todo */ -function field_purge_batch($batch_size) { +function field_purge_batch($batch_size, $field_id = NULL) { // Retrieve all deleted field instances. We cannot use field_info_instances() // because that function does not return deleted instances. - $instances = field_read_instances(array('deleted' => 1), array('include_deleted' => 1)); + $options = array('deleted' => 1); + if ($field_id) { + $options['field_id'] = $field_id; + } + $instances = field_read_instances($options, array('include_deleted' => 1)); foreach ($instances as $instance) { // field_purge_data() will need the field array. @@ -855,23 +877,28 @@ function field_purge_batch($batch_size) { ->range(0, $batch_size) ->execute(); - if ($results) { - foreach ($results as $entity_type => $stub_entities) { - field_attach_load($entity_type, $stub_entities, FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1)); - foreach ($stub_entities as $stub_entity) { - // Purge the data for the entity. - field_purge_data($entity_type, $stub_entity, $field, $instance); - } + $count = 0; + foreach ($results as $entity_type => $stub_entities) { + field_attach_load($entity_type, $stub_entities, FIELD_LOAD_CURRENT, array('field_id' => $field['id'], 'deleted' => 1)); + foreach ($stub_entities as $stub_entity) { + // Purge the data for the entity. + field_purge_data($entity_type, $stub_entity, $field, $instance); + $count++; } } - else { - // No field data remains for the instance, so we can remove it. + // If we received less results than we asked for, we know that no field data + // remains for the instance, so we can remove it. + if ($count < $batch_size) { field_purge_instance($instance); } } // Retrieve all deleted fields. Any that have no instances can be purged. - $fields = field_read_fields(array('deleted' => 1), array('include_deleted' => 1)); + $options = array('deleted' => 1); + if ($field_id) { + $options['id'] = $field_id; + } + $fields = field_read_fields($options, array('include_deleted' => 1)); foreach ($fields as $field) { $instances = field_read_instances(array('field_id' => $field['id']), array('include_deleted' => 1)); if (empty($instances)) { diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test index b361637..9d07ddc 100644 --- a/modules/field/tests/field.test +++ b/modules/field/tests/field.test @@ -2167,7 +2167,9 @@ class FieldCrudTestCase extends FieldTestCase { // Test that the first field is not deleted, and then delete it. $field = field_read_field($this->field['field_name'], array('include_deleted' => TRUE)); $this->assertTrue(!empty($field) && empty($field['deleted']), t('A new field is not marked for deletion.')); - field_delete_field($this->field['field_name']); + // We test the intermediate state betwenn the deletion and the purge, so we + // explicitly instruct field_delete_field() to not run a purge pass. + field_delete_field($this->field['field_name'], FALSE); // Make sure that the field is marked as deleted when it is specifically // loaded. @@ -2596,8 +2598,9 @@ class FieldInstanceCrudTestCase extends FieldTestCase { $another_instance = field_read_instance('test_entity', $this->another_instance_definition['field_name'], $this->another_instance_definition['bundle']); $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), t('A non-deleted field instance is not marked for deletion.')); - // Make sure the field is deleted when its last instance is deleted. - field_delete_instance($another_instance); + // Make sure the field is marked deleted when its last instance is deleted + // (do not perform purge). + field_delete_instance($another_instance, TRUE, FALSE); $field = field_read_field($another_instance['field_name'], array('include_deleted' => TRUE)); $this->assertTrue(!empty($field['deleted']), t('A deleted field is marked for deletion after all its instances have been marked for deletion.')); } @@ -3174,11 +3177,9 @@ class FieldBulkDeleteTestCase extends FieldTestCase { $instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_1'); field_delete_instance($instance); - // Purge the data. - field_purge_batch(10); - - // Purge again to purge the instance. - field_purge_batch(0); + // Purge the data and the instance (make sure this happens in one single + // pass by giving a batch size greater than the amounnt of data). + field_purge_batch(11); // The field still exists, not deleted. $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1)); @@ -3188,15 +3189,13 @@ class FieldBulkDeleteTestCase extends FieldTestCase { $instance = field_info_instance($this->entity_type, $field['field_name'], 'bb_2'); field_delete_instance($instance); - // Purge the data. - field_purge_batch(10); - // 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'); - // Purge again to purge the instance and the field. - field_purge_batch(0); + // Purge the data, the instance and the field (make sure this happens in one + // single pass by giving a batch size greater than the amounnt of data). + field_purge_batch(11); // The field is gone. $fields = field_read_fields(array('id' => $field['id']), array('include_deleted' => 1, 'include_inactive' => 1)); diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc index 3f60085..811e0f5 100644 --- a/modules/field_ui/field_ui.admin.inc +++ b/modules/field_ui/field_ui.admin.inc @@ -1727,14 +1727,6 @@ function field_ui_field_delete_form_submit($form, &$form_state) { $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); $form_state['redirect'] = field_ui_get_destinations(array($admin_path . '/fields')); - - // Fields are purged on cron. However field module prevents disabling modules - // when field types they provided are used in a field until it is fully - // purged. In the case that a field has minimal or no content, a single call - // to field_purge_batch() will remove it from the system. Call this with a - // low batch limit to avoid administrators having to wait for cron runs when - // removing instances that meet this criteria. - field_purge_batch(10); } /** diff --git a/modules/forum/forum.install b/modules/forum/forum.install index 2eebd7f..68bf209 100644 --- a/modules/forum/forum.install +++ b/modules/forum/forum.install @@ -115,9 +115,6 @@ function forum_uninstall() { variable_del('node_options_forum'); field_delete_field('taxonomy_forums'); - // Purge field data now to allow taxonomy module to be uninstalled - // if this is the only field remaining. - field_purge_batch(10); } /**