Commit 65b99dc8 authored by webchick's avatar webchick

#895014 by Damien Tournoud, chx, catch: Fixed all fields of a node type are lost on module disable.

parent 466c8ff5
......@@ -6727,8 +6727,10 @@ function drupal_flush_all_caches() {
system_rebuild_theme_data();
drupal_theme_rebuild();
menu_rebuild();
node_types_rebuild();
// node_menu() defines menu items based on node types so it needs to come
// after node types are rebuilt.
menu_rebuild();
// Synchronize to catch any actions that were added or removed.
actions_synchronize();
......
......@@ -71,30 +71,30 @@ function forum_enable() {
);
$term = (object) $edit;
taxonomy_term_save($term);
}
// Create the instance on the bundle.
$instance = array(
'field_name' => 'taxonomy_' . $vocabulary->machine_name,
'entity_type' => 'node',
'label' => $vocabulary->name,
'bundle' => 'forum',
'required' => TRUE,
'widget' => array(
'type' => 'options_select',
),
'display' => array(
'default' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
// Create the instance on the bundle.
$instance = array(
'field_name' => 'taxonomy_' . $vocabulary->machine_name,
'entity_type' => 'node',
'label' => $vocabulary->name,
'bundle' => 'forum',
'required' => TRUE,
'widget' => array(
'type' => 'options_select',
),
'teaser' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
'display' => array(
'default' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
),
'teaser' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
),
),
),
);
field_create_instance($instance);
);
field_create_instance($instance);
}
// Ensure the forum node type is available.
node_types_rebuild();
......
......@@ -320,6 +320,9 @@ function node_type_form_submit($form, &$form_state) {
$type->custom = $form_state['values']['custom'];
$type->modified = TRUE;
$type->locked = $form_state['values']['locked'];
if (isset($form['#node_type']->module)) {
$type->module = $form['#node_type']->module;
}
if ($op == t('Delete content type')) {
$form_state['redirect'] = 'admin/structure/types/manage/' . str_replace('_', '-', $type->old_type) . '/delete';
......
......@@ -294,6 +294,12 @@ function node_schema() {
'length' => 255,
'not null' => TRUE,
),
'module' => array(
'description' => 'The module defining this node type.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
),
'description' => array(
'description' => 'A brief description of this type.',
'type' => 'text',
......@@ -344,6 +350,13 @@ function node_schema() {
'default' => 0,
'size' => 'tiny',
),
'disabled' => array(
'description' => 'A boolean indicating whether the node type is disabled.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny'
),
'orig_type' => array(
'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
'type' => 'varchar',
......@@ -438,16 +451,40 @@ function _update_7000_node_get_types() {
*/
/**
* Fix node type 'module' attribute to avoid name-space conflicts.
* Upgrade the node type table and fix node type 'module' attribute to avoid name-space conflicts.
*/
function node_update_7000() {
// Rename the module column to base.
db_change_field('node_type', 'module', 'base', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
db_add_field('node_type', 'module', array(
'description' => 'The module defining this node type.',
'type' => 'varchar',
'default' => '',
'length' => 255,
'not null' => TRUE,
));
db_add_field('node_type', 'disabled', array(
'description' => 'A boolean indicating whether the node type is disabled.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny'
));
$modules = db_select('system', 's')
->fields('s', array('name'))
->condition('type', 'module');
db_update('node_type')
->fields(array('module' => 'node_content'))
->condition('module', 'node')
->expression('module', 'base')
->condition('base', $modules, 'IN')
->execute();
// Rename the module column to base.
db_change_field('node_type', 'module', 'base', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
db_update('node_type')
->fields(array('base' => 'node_content'))
->condition('base', 'node')
->execute();
}
/**
......
......@@ -461,16 +461,7 @@ function node_type_get_name($node) {
* and obsolete types.
*/
function node_types_rebuild() {
// Reset and load updated node types.
drupal_static_reset('_node_types_build');
foreach (node_type_get_types() as $type => $info) {
if (!empty($info->is_new)) {
node_type_save($info);
}
if (!empty($info->disabled)) {
node_type_delete($info->type);
}
}
_node_types_build(TRUE);
}
/**
......@@ -513,6 +504,8 @@ function node_type_save($info) {
'custom' => (int) $type->custom,
'modified' => (int) $type->modified,
'locked' => (int) $type->locked,
'disabled' => (int) $type->disabled,
'module' => $type->module,
);
if ($is_existing) {
......@@ -660,6 +653,8 @@ function node_type_update_nodes($old_type, $type) {
* These two information sources are not synchronized during module installation
* until node_types_rebuild() is called.
*
* @param $rebuild
* TRUE to rebuild node types. Equivalent to calling node_types_rebuild().
* @return
* Associative array with two components:
* - names: Associative array of the names of node types, keyed by the type.
......@@ -673,42 +668,66 @@ function node_type_update_nodes($old_type, $type) {
* implementations, but are still in the database. These are indicated in the
* type object by $type->disabled being set to TRUE.
*/
function _node_types_build() {
$_node_types = &drupal_static(__FUNCTION__);
if (is_object($_node_types)) {
return $_node_types;
function _node_types_build($rebuild = FALSE) {
if (!$rebuild) {
$_node_types = &drupal_static(__FUNCTION__);
if (is_object($_node_types)) {
return $_node_types;
}
}
$_node_types = (object)array('types' => array(), 'names' => array());
$info_array = module_invoke_all('node_info');
foreach ($info_array as $type => $info) {
$info['type'] = $type;
$_node_types->types[$type] = node_type_set_defaults($info);
$_node_types->names[$type] = $info['name'];
foreach (module_implements('node_info') as $module) {
$info_array = module_invoke($module, 'node_info');
foreach ($info_array as $type => $info) {
$info['type'] = $type;
$_node_types->types[$type] = node_type_set_defaults($info);
$_node_types->types[$type]->module = $module;
$_node_types->names[$type] = $info['name'];
}
}
$type_result = db_select('node_type', 'nt')
$query = db_select('node_type', 'nt')
->addTag('translatable')
->addTag('node_type_access')
->fields('nt')
->orderBy('nt.type', 'ASC')
->execute();
foreach ($type_result as $type_object) {
->orderBy('nt.type', 'ASC');
if (!$rebuild) {
$query->condition('disabled', 0);
}
foreach ($query->execute() as $type_object) {
$type_db = $type_object->type;
// Original disabled value.
$disabled = $type_object->disabled;
// Check for node types from disabled modules and mark their types for removal.
// Types defined by the node module in the database (rather than by a separate
// module using hook_node_info) have a base value of 'node_content'. The isset()
// check prevents errors on old (pre-Drupal 7) databases.
if (isset($type_object->base) && $type_object->base != 'node_content' && empty($info_array[$type_object->type])) {
if (isset($type_object->base) && $type_object->base != 'node_content' && empty($info_array[$type_db])) {
$type_object->disabled = TRUE;
}
if (!isset($_node_types->types[$type_object->type]) || $type_object->modified) {
$_node_types->types[$type_object->type] = $type_object;
$_node_types->names[$type_object->type] = $type_object->name;
if (isset($info_array[$type_db])) {
$type_object->disabled = FALSE;
}
if (!isset($_node_types->types[$type_db]) || $type_object->modified) {
$_node_types->types[$type_db] = $type_object;
$_node_types->names[$type_db] = $type_object->name;
if ($type_object->type != $type_object->orig_type) {
if ($type_db != $type_object->orig_type) {
unset($_node_types->types[$type_object->orig_type]);
unset($_node_types->names[$type_object->orig_type]);
}
}
$_node_types->types[$type_db]->disabled = $type_object->disabled;
$_node_types->types[$type_db]->disabled_changed = $disabled != $type_object->disabled;
}
if ($rebuild) {
foreach ($_node_types->types as $type => $type_object) {
if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {
node_type_save($type_object);
}
}
}
asort($_node_types->names);
......@@ -742,6 +761,7 @@ function node_type_set_defaults($info = array()) {
$type->custom = 0;
$type->modified = 0;
$type->locked = 1;
$type->disabled = 0;
$type->is_new = 1;
$type->has_title = 1;
......@@ -757,6 +777,9 @@ function node_type_set_defaults($info = array()) {
if (!$new_type->has_title) {
$new_type->title_label = '';
}
if (empty($new_type->module)) {
$new_type->module = $new_type->base == 'node_content' ? 'node' : '';
}
$new_type->orig_type = isset($info['type']) ? $info['type'] : '';
return $new_type;
......
......@@ -1148,6 +1148,82 @@ class NodeTypeTestCase extends DrupalWebTestCase {
}
}
/**
* Test node type customizations persistence.
*/
class NodeTypePersistenceTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Node type persist',
'description' => 'Ensures that node type customization survives module enabling and disabling.',
'group' => 'Node',
);
}
/**
* Test node type customizations persist through disable and uninstall.
*/
function testNodeTypeCustomizationPersistence() {
$web_user = $this->drupalCreateUser(array('bypass node access', 'administer content types', 'administer modules'));
$this->drupalLogin($web_user);
$poll_key = 'modules[Core][poll][enable]';
$poll_enable = array($poll_key => "1");
$poll_disable = array($poll_key => FALSE);
// Enable poll and verify that the node type is in the DB and is not
// disabled.
$this->drupalPost('admin/modules', $poll_enable, t('Save configuration'));
$disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'poll'))->fetchField();
$this->assertNotIdentical($disabled, FALSE, t('Poll node type found in the database'));
$this->assertEqual($disabled, 0, t('Poll node type is not disabled'));
// Check that poll node type (uncustomized) shows up.
$this->drupalGet('node/add');
$this->assertText('poll', t('poll type is found on node/add'));
// Customize poll description.
$description = $this->randomName();
$edit = array('description' => $description);
$this->drupalPost('admin/structure/types/manage/poll', $edit, t('Save content type'));
// Check that poll node type customization shows up.
$this->drupalGet('node/add');
$this->assertText($description, t('Customized description found'));
// Disable poll and check that the node type gets disabled.
$this->drupalPost('admin/modules', $poll_disable, t('Save configuration'));
$disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'poll'))->fetchField();
$this->assertEqual($disabled, 1, t('Poll node type is disabled'));
$this->drupalGet('node/add');
$this->assertNoText('poll', t('poll type is not found on node/add'));
// Reenable poll and check that the customization survived the module
// disable.
$this->drupalPost('admin/modules', $poll_enable, t('Save configuration'));
$disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'poll'))->fetchField();
$this->assertNotIdentical($disabled, FALSE, t('Poll node type found in the database'));
$this->assertEqual($disabled, 0, t('Poll node type is not disabled'));
$this->drupalGet('node/add');
$this->assertText($description, t('Customized description found'));
// Disable and uninstall poll.
$this->drupalPost('admin/modules', $poll_disable, t('Save configuration'));
$edit = array('uninstall[poll]' => 'poll');
$this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
$this->drupalPost(NULL, array(), t('Uninstall'));
$disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'poll'))->fetchField();
$this->assertTrue($disabled, t('Poll node type is in the database and is disabled'));
$this->drupalGet('node/add');
$this->assertNoText('poll', t('poll type is no longer found on node/add'));
// Reenable poll and check that the customization survived the module
// uninstall.
$this->drupalPost('admin/modules', $poll_enable, t('Save configuration'));
$this->drupalGet('node/add');
$this->assertText($description, t('Customized description is found even after uninstall and reenable.'));
}
}
/**
* Rebuild the node_access table.
*/
......
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