Commit 6f10a4ed authored by webchick's avatar webchick

Issue #943772 by jpsoto, yched, catch, bojanz, pillarsdotnet, steinmb: Fixed...

Issue #943772 by jpsoto, yched, catch, bojanz, pillarsdotnet, steinmb: Fixed field_delete_field() and others fail for inactive fields.
parent 06715a11
...@@ -305,13 +305,6 @@ class FieldException extends Exception {} ...@@ -305,13 +305,6 @@ class FieldException extends Exception {}
*/ */
class FieldUpdateForbiddenException extends FieldException {} class FieldUpdateForbiddenException extends FieldException {}
/**
* Implements hook_flush_caches().
*/
function field_flush_caches() {
return array('cache_field');
}
/** /**
* Implements hook_help(). * Implements hook_help().
*/ */
...@@ -370,6 +363,7 @@ function field_theme() { ...@@ -370,6 +363,7 @@ function field_theme() {
* Purges some deleted Field API data, if any exists. * Purges some deleted Field API data, if any exists.
*/ */
function field_cron() { function field_cron() {
field_sync_field_status();
$limit = variable_get('field_purge_batch_size', 10); $limit = variable_get('field_purge_batch_size', 10);
field_purge_batch($limit); field_purge_batch($limit);
} }
...@@ -386,45 +380,84 @@ function field_modules_uninstalled($modules) { ...@@ -386,45 +380,84 @@ function field_modules_uninstalled($modules) {
} }
/** /**
* Implements hook_modules_enabled(). * Implements hook_system_info_alter().
*
* Goes through a list of all modules that provide a field type, and makes them
* required if there are any active fields of that type.
*/ */
function field_modules_enabled($modules) { function field_system_info_alter(&$info, $file, $type) {
foreach ($modules as $module) { if ($type == 'module' && module_hook($file->name, 'field_info')) {
field_associate_fields($module); $fields = field_read_fields(array('module' => $file->name), array('include_deleted' => TRUE));
if ($fields) {
$info['required'] = TRUE;
// Provide an explanation message (only mention pending deletions if there
// remains no actual, non-deleted fields)
$non_deleted = FALSE;
foreach ($fields as $field) {
if (empty($field['deleted'])) {
$non_deleted = TRUE;
break;
}
}
if ($non_deleted) {
if (module_exists('field_ui')) {
$explanation = t('Field type(s) in use - see !link', array('!link' => l(t('Field list'), 'admin/reports/fields')));
}
else {
$explanation = t('Fields type(s) in use');
}
}
else {
$explanation = t('Fields pending deletion');
}
$info['explanation'] = $explanation;
}
} }
field_cache_clear();
} }
/** /**
* Implements hook_modules_disabled(). * Implements hook_flush_caches().
*/
function field_flush_caches() {
field_sync_field_status();
return array('cache_field');
}
/**
* Refreshes the 'active' and 'storage_active' columns for fields.
*/ */
function field_modules_disabled($modules) { function field_sync_field_status() {
// Track fields whose field type is being disabled. // Refresh the 'active' and 'storage_active' columns according to the current
// set of enabled modules.
$all_modules = system_rebuild_module_data();
$modules = array();
foreach ($all_modules as $module_name => $module) {
if ($module->status) {
$modules[] = $module_name;
field_associate_fields($module_name);
}
}
db_update('field_config') db_update('field_config')
->fields(array('active' => 0)) ->fields(array('active' => 0))
->condition('module', $modules, 'IN') ->condition('module', $modules, 'NOT IN')
->execute(); ->execute();
// Track fields whose storage backend is being disabled.
db_update('field_config') db_update('field_config')
->fields(array('storage_active' => 0)) ->fields(array('storage_active' => 0))
->condition('storage_module', $modules, 'IN') ->condition('storage_module', $modules, 'NOT IN')
->execute(); ->execute();
field_cache_clear();
} }
/** /**
* Allows a module to update the database for fields and columns it controls. * Allows a module to update the database for fields and columns it controls.
* *
* @param string $module * @param $module
* The name of the module to update on. * The name of the module to update on.
*/ */
function field_associate_fields($module) { function field_associate_fields($module) {
// Associate field types. // Associate field types.
$field_types =(array) module_invoke($module, 'field_info'); $field_types = (array) module_invoke($module, 'field_info');
foreach ($field_types as $name => $field_info) { foreach ($field_types as $name => $field_info) {
watchdog('field', 'Updating field type %type with module %module.', array('%type' => $name, '%module' => $module));
db_update('field_config') db_update('field_config')
->fields(array('module' => $module, 'active' => 1)) ->fields(array('module' => $module, 'active' => 1))
->condition('type', $name) ->condition('type', $name)
...@@ -433,7 +466,6 @@ function field_associate_fields($module) { ...@@ -433,7 +466,6 @@ function field_associate_fields($module) {
// Associate storage backends. // Associate storage backends.
$storage_types = (array) module_invoke($module, 'field_storage_info'); $storage_types = (array) module_invoke($module, 'field_storage_info');
foreach ($storage_types as $name => $storage_info) { foreach ($storage_types as $name => $storage_info) {
watchdog('field', 'Updating field storage %type with module %module.', array('%type' => $name, '%module' => $module));
db_update('field_config') db_update('field_config')
->fields(array('storage_module' => $module, 'storage_active' => 1)) ->fields(array('storage_module' => $module, 'storage_active' => 1))
->condition('storage_type', $name) ->condition('storage_type', $name)
......
...@@ -2356,6 +2356,7 @@ class FieldCrudTestCase extends FieldTestCase { ...@@ -2356,6 +2356,7 @@ class FieldCrudTestCase extends FieldTestCase {
$this->assertTrue($field_definition <= $field, t('The field was properly read.')); $this->assertTrue($field_definition <= $field, t('The field was properly read.'));
module_disable($modules, FALSE); module_disable($modules, FALSE);
drupal_flush_all_caches();
$fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE)); $fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
$this->assertTrue(isset($fields[$field_name]) && $field_definition < $field, t('The field is properly read when explicitly fetching inactive fields.')); $this->assertTrue(isset($fields[$field_name]) && $field_definition < $field, t('The field is properly read when explicitly fetching inactive fields.'));
...@@ -2368,6 +2369,7 @@ class FieldCrudTestCase extends FieldTestCase { ...@@ -2368,6 +2369,7 @@ class FieldCrudTestCase extends FieldTestCase {
$module = array_shift($modules); $module = array_shift($modules);
module_enable(array($module), FALSE); module_enable(array($module), FALSE);
drupal_flush_all_caches();
} }
// Check that the field is active again after all modules have been // Check that the field is active again after all modules have been
......
...@@ -12,17 +12,27 @@ function field_ui_fields_list() { ...@@ -12,17 +12,27 @@ function field_ui_fields_list() {
$instances = field_info_instances(); $instances = field_info_instances();
$field_types = field_info_field_types(); $field_types = field_info_field_types();
$bundles = field_info_bundles(); $bundles = field_info_bundles();
$modules = system_rebuild_module_data();
$header = array(t('Field name'), t('Field type'), t('Used in')); $header = array(t('Field name'), t('Field type'), t('Used in'));
$rows = array(); $rows = array();
foreach ($instances as $entity_type => $type_bundles) { foreach ($instances as $entity_type => $type_bundles) {
foreach ($type_bundles as $bundle => $bundle_instances) { foreach ($type_bundles as $bundle => $bundle_instances) {
foreach ($bundle_instances as $field_name => $instance) { foreach ($bundle_instances as $field_name => $instance) {
$field = field_info_field($field_name); $field = field_info_field($field_name);
// Initialize the row if we encounter the field for the first time.
if (!isset($rows[$field_name])) {
$rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
$rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
$module_name = $field_types[$field['type']]['module'];
$rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
}
// Add the current instance.
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
$rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
$rows[$field_name]['data'][1] = $field_types[$field['type']]['label'];
$rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label']; $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
$rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
} }
} }
} }
...@@ -1717,6 +1727,14 @@ function field_ui_field_delete_form_submit($form, &$form_state) { ...@@ -1717,6 +1727,14 @@ function field_ui_field_delete_form_submit($form, &$form_state) {
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
$form_state['redirect'] = field_ui_get_destinations(array($admin_path . '/fields')); $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);
} }
/** /**
......
...@@ -113,6 +113,11 @@ function forum_uninstall() { ...@@ -113,6 +113,11 @@ function forum_uninstall() {
variable_del('forum_block_num_active'); variable_del('forum_block_num_active');
variable_del('forum_block_num_new'); variable_del('forum_block_num_new');
variable_del('node_options_forum'); 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);
} }
/** /**
......
...@@ -31,6 +31,7 @@ class ForumTestCase extends DrupalWebTestCase { ...@@ -31,6 +31,7 @@ class ForumTestCase extends DrupalWebTestCase {
// Create users. // Create users.
$this->admin_user = $this->drupalCreateUser(array( $this->admin_user = $this->drupalCreateUser(array(
'access administration pages', 'access administration pages',
'administer modules',
'administer blocks', 'administer blocks',
'administer forums', 'administer forums',
'administer menu', 'administer menu',
...@@ -51,6 +52,30 @@ class ForumTestCase extends DrupalWebTestCase { ...@@ -51,6 +52,30 @@ class ForumTestCase extends DrupalWebTestCase {
$this->web_user = $this->drupalCreateUser(array()); $this->web_user = $this->drupalCreateUser(array());
} }
/**
* Tests disabling and re-enabling forum.
*/
function testEnableForumField() {
$this->drupalLogin($this->admin_user);
// Disable the forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
module_list(TRUE);
$this->assertFalse(module_exists('forum'), t('Forum module is not enabled.'));
// Attempt to re-enable the forum module and ensure it does not try to
// recreate the taxonomy_forums field.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
module_list(TRUE);
$this->assertTrue(module_exists('forum'), t('Forum module is enabled.'));
}
/** /**
* Login users, create forum nodes, and test forum functionality through the admin and user interfaces. * Login users, create forum nodes, and test forum functionality through the admin and user interfaces.
*/ */
......
...@@ -799,7 +799,7 @@ function system_modules($form, $form_state = array()) { ...@@ -799,7 +799,7 @@ function system_modules($form, $form_state = array()) {
$extra['enabled'] = (bool) $module->status; $extra['enabled'] = (bool) $module->status;
if (!empty($module->info['required'] )) { if (!empty($module->info['required'] )) {
$extra['disabled'] = TRUE; $extra['disabled'] = TRUE;
$extra['required_by'][] = $distribution_name; $extra['required_by'][] = $distribution_name . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : '');
} }
// If this module requires other modules, add them to the array. // If this module requires other modules, add them to the array.
......
...@@ -445,39 +445,6 @@ class ModuleDependencyTestCase extends ModuleTestCase { ...@@ -445,39 +445,6 @@ class ModuleDependencyTestCase extends ModuleTestCase {
} }
/**
* Tests re-enabling forum with taxonomy disabled.
*/
function testEnableForumTaxonomyFieldDependency() {
// Enable the forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), TRUE);
// Disable the forum module.
$edit = array();
$edit['modules[Core][forum][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE);
// Disable the taxonomy module.
$edit = array();
$edit['modules[Core][taxonomy][enable]'] = FALSE;
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('taxonomy'), FALSE);
// Attempt to re-enable the forum module with taxonomy disabled and ensure
// forum does not try to recreate the taxonomy_forums field.
$edit = array();
$edit['modules[Core][forum][enable]'] = 'forum';
$this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertText(t('Some required modules must be enabled'), t('Dependency required.'));
$this->drupalPost(NULL, NULL, t('Continue'));
$this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
$this->assertModules(array('taxonomy', 'forum'), TRUE);
}
/** /**
* Tests that module dependencies are enabled in the correct order via the * Tests that module dependencies are enabled in the correct order via the
* UI. Dependencies should be enabled before their dependents. * UI. Dependencies should be enabled before their dependents.
...@@ -516,18 +483,18 @@ class ModuleDependencyTestCase extends ModuleTestCase { ...@@ -516,18 +483,18 @@ class ModuleDependencyTestCase extends ModuleTestCase {
$this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), TRUE); $this->assertModules(array('forum'), TRUE);
// Disable forum and taxonomy. Both should now be installed but disabled. // Disable forum and comment. Both should now be installed but disabled.
$edit = array('modules[Core][forum][enable]' => FALSE); $edit = array('modules[Core][forum][enable]' => FALSE);
$this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('forum'), FALSE); $this->assertModules(array('forum'), FALSE);
$edit = array('modules[Core][taxonomy][enable]' => FALSE); $edit = array('modules[Core][comment][enable]' => FALSE);
$this->drupalPost('admin/modules', $edit, t('Save configuration')); $this->drupalPost('admin/modules', $edit, t('Save configuration'));
$this->assertModules(array('taxonomy'), FALSE); $this->assertModules(array('comment'), FALSE);
// Check that the taxonomy module cannot be uninstalled. // Check that the taxonomy module cannot be uninstalled.
$this->drupalGet('admin/modules/uninstall'); $this->drupalGet('admin/modules/uninstall');
$checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[taxonomy]"]'); $checkbox = $this->xpath('//input[@type="checkbox" and @disabled="disabled" and @name="uninstall[comment]"]');
$this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the taxonomy module is disabled.')); $this->assert(count($checkbox) == 1, t('Checkbox for uninstalling the comment module is disabled.'));
// Uninstall the forum module, and check that taxonomy now can also be // Uninstall the forum module, and check that taxonomy now can also be
// uninstalled. // uninstalled.
...@@ -535,7 +502,7 @@ class ModuleDependencyTestCase extends ModuleTestCase { ...@@ -535,7 +502,7 @@ class ModuleDependencyTestCase extends ModuleTestCase {
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall')); $this->drupalPost(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.')); $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
$edit = array('uninstall[taxonomy]' => 'taxonomy'); $edit = array('uninstall[comment]' => 'comment');
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall')); $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, NULL, t('Uninstall')); $this->drupalPost(NULL, NULL, t('Uninstall'));
$this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.')); $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
......
...@@ -360,7 +360,6 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase { ...@@ -360,7 +360,6 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase {
$this->field_name = drupal_strtolower($this->randomName() . '_field_name'); $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
$this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4); $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
$this->field = field_create_field($this->field); $this->field = field_create_field($this->field);
$this->field_id = $this->field['id'];
$this->instance = array( $this->instance = array(
'field_name' => $this->field_name, 'field_name' => $this->field_name,
'entity_type' => 'taxonomy_term', 'entity_type' => 'taxonomy_term',
...@@ -370,6 +369,7 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase { ...@@ -370,6 +369,7 @@ class TaxonomyVocabularyUnitTest extends TaxonomyWebTestCase {
field_create_instance($this->instance); field_create_instance($this->instance);
module_disable(array('taxonomy')); module_disable(array('taxonomy'));
drupal_flush_all_caches();
require_once DRUPAL_ROOT . '/includes/install.inc'; require_once DRUPAL_ROOT . '/includes/install.inc';
drupal_uninstall_modules(array('taxonomy')); drupal_uninstall_modules(array('taxonomy'));
module_enable(array('taxonomy')); module_enable(array('taxonomy'));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment