=== modified file 'includes/common.inc'
--- includes/common.inc 2010-08-22 12:46:21 +0000
+++ includes/common.inc 2010-08-27 06:23:30 +0000
@@ -6309,8 +6309,8 @@ function drupal_flush_all_caches() {
system_rebuild_theme_data();
drupal_theme_rebuild();
- menu_rebuild();
node_types_rebuild();
+ menu_rebuild();
// Don't clear cache_form - in-progress form submissions may break.
// Ordered so clearing the page cache will always be the last action.
=== modified file 'includes/install.inc'
--- includes/install.inc 2010-08-22 15:31:18 +0000
+++ includes/install.inc 2010-08-27 09:37:21 +0000
@@ -628,6 +628,11 @@ function drupal_uninstall_modules($modul
drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED);
}
+ // Remove the node types defined by the module.
+ $node_types = db_query("SELECT * FROM {node_type} WHERE defining_module = :module", array(':module' => $module));
+ foreach ($node_types as $type_object) {
+ node_type_delete($type_object);
+ }
if (!empty($module_list)) {
// Call hook_module_uninstall to let other modules act
=== modified file 'modules/node/content_types.inc'
--- modules/node/content_types.inc 2010-08-08 13:02:37 +0000
+++ modules/node/content_types.inc 2010-08-27 07:51:07 +0000
@@ -317,6 +317,7 @@ function node_type_form_submit($form, &$
$type->custom = $form_state['values']['custom'];
$type->modified = TRUE;
$type->locked = $form_state['values']['locked'];
+ $type->defining_module = $form['#node_type']->defining_module;
if ($op == t('Delete content type')) {
$form_state['redirect'] = 'admin/structure/types/manage/' . str_replace('_', '-', $type->old_type) . '/delete';
=== modified file 'modules/node/node.install'
--- modules/node/node.install 2010-08-22 13:55:53 +0000
+++ modules/node/node.install 2010-08-27 06:27:12 +0000
@@ -294,6 +294,12 @@ function node_schema() {
'length' => 255,
'not null' => TRUE,
),
+ 'defining_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,12 @@ 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',
=== modified file 'modules/node/node.module'
--- modules/node/node.module 2010-08-23 22:15:34 +0000
+++ modules/node/node.module 2010-08-27 09:42:35 +0000
@@ -464,16 +464,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);
}
/**
@@ -502,7 +493,7 @@ function node_type_load($name) {
function node_type_save($info) {
$is_existing = FALSE;
$existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
- $is_existing = (bool) db_query_range('SELECT 1 FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
+ $is_existing = (bool) db_query_range('SELECT COUNT(*) FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
$type = node_type_set_defaults($info);
$fields = array(
@@ -516,6 +507,8 @@ function node_type_save($info) {
'custom' => (int) $type->custom,
'modified' => (int) $type->modified,
'locked' => (int) $type->locked,
+ 'disabled' => (int) $type->disabled,
+ 'defining_module' => $type->defining_module,
);
if ($is_existing) {
@@ -623,14 +616,15 @@ function node_field_extra_fields() {
* Deletes a node type from the database.
*
* @param $type
- * The machine-readable name of the node type to be deleted.
+ * The machine-readable name of the node type or the node type object itself
+ * to be deleted.
*/
function node_type_delete($type) {
- $info = node_type_get_type($type);
+ $info = is_string($type) ? node_type_get_type($type) : $type;
db_delete('node_type')
- ->condition('type', $type)
+ ->condition('type', $info->type)
->execute();
- field_attach_delete_bundle('node', $type);
+ field_attach_delete_bundle('node', $info->type);
module_invoke_all('node_type_delete', $info);
// Clear the node type cache.
@@ -676,42 +670,66 @@ function node_type_update_nodes($old_typ
* 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]->defining_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;
+ $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);
@@ -745,6 +763,7 @@ function node_type_set_defaults($info =
$type->custom = 0;
$type->modified = 0;
$type->locked = 1;
+ $type->disabled = 0;
$type->is_new = 1;
$type->has_title = 1;
=== modified file 'modules/node/node.test'
--- modules/node/node.test 2010-08-22 16:11:12 +0000
+++ modules/node/node.test 2010-08-27 06:08:15 +0000
@@ -1141,6 +1141,76 @@ class NodeTypeTestCase extends DrupalWeb
}
/**
+ * Test node type customizations persist.
+ */
+class NodeTypePersistTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Node type persist',
+ 'description' => 'Ensures that node type customization survive module enabling and disabling.',
+ 'group' => 'Node',
+ );
+ }
+
+ 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->assertIdentical($disabled, FALSE, t('Poll node type is not found in the database'));
+ $this->drupalGet('node/add');
+ $this->assertNoText('poll', t('poll type is no longer found on node/add'));
+
+ // Reenable poll and check that the customization did not survive the
+ // module uninstall.
+ $this->drupalPost('admin/modules', $poll_enable, t('Save configuration'));
+ $this->drupalGet('node/add');
+ $this->assertNoText($description, t('Customized description is not found'));
+ }
+}
+
+/**
* Rebuild the node_access table.
*/
class NodeAccessRebuildTestCase extends DrupalWebTestCase {
=== modified file 'modules/system/system.admin.inc'
--- modules/system/system.admin.inc 2010-08-22 12:55:04 +0000
+++ modules/system/system.admin.inc 2010-08-27 06:32:35 +0000
@@ -1294,7 +1294,8 @@ function system_modules_uninstall($form,
// Load the .install file, and check for an uninstall or schema hook.
// If the hook exists, the module can be uninstalled.
module_load_install($module->name);
- if (module_hook($module->name, 'uninstall') || module_hook($module->name, 'schema')) {
+ $node_type_count = db_query("SELECT COUNT(*) FROM {node_type} WHERE defining_module = :module", array(':module' => $module->name))->fetchField();
+ if (module_hook($module->name, 'uninstall') || module_hook($module->name, 'schema') || $node_type_count) {
$form['modules'][$module->name]['name'] = array('#markup' => $info['name'] ? $info['name'] : $module->name);
$form['modules'][$module->name]['description'] = array('#markup' => t($info['description']));
$options[$module->name] = '';
=== modified file 'profiles/standard/standard.install'
--- profiles/standard/standard.install 2010-08-09 19:55:57 +0000
+++ profiles/standard/standard.install 2010-08-27 06:31:39 +0000
@@ -210,6 +210,7 @@ function standard_install() {
'type' => 'page',
'name' => st('Basic page'),
'base' => 'node_content',
+ 'defining_module' => 'node',
'description' => st("Use basic pages for your static content, such as an 'About us' page."),
'custom' => 1,
'modified' => 1,
@@ -219,6 +220,7 @@ function standard_install() {
'type' => 'article',
'name' => st('Article'),
'base' => 'node_content',
+ 'defining_module' => 'node',
'description' => st('Use articles for time-sensitive content like news, press releases or blog posts.'),
'custom' => 1,
'modified' => 1,