? .DS_Store
? features-649298.patch
Index: includes/features.content.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/features/includes/features.content.inc,v
retrieving revision 1.1.2.12
diff -u -p -r1.1.2.12 features.content.inc
--- includes/features.content.inc	21 May 2010 23:00:42 -0000	1.1.2.12
+++ includes/features.content.inc	12 Jul 2010 15:22:35 -0000
@@ -121,25 +121,71 @@ function content_features_export_render(
 
 /**
  * Implementation of hook_features_revert().
+ *
+ * This process will inactive, but not delete, any undefined field instances
+ * on content types that are defined by this feature. Inactivated field
+ * instances can either be permanently deleted in an update hook or re-activated 
+ * by adding them back to this or any other feature.
  */
 function content_features_revert($module) {
-  content_features_rebuild($module);
+  
+  $fields = module_invoke($module, 'content_default_fields');
+  $inactivated_instances = array();
+    
+  if (module_hook($module, 'node_info')){
+    $default_types = module_invoke($module, 'node_info');
+
+    foreach ($default_types as $type_name => $type_info) {
+      $db_instances = content_db_instances($type_name);  
+      $features_instances = content_features_instances($type_name);
+      
+      // Inactive any field instances that are no longer defined by any feature for this content type.
+      if (!empty($db_instances)) {
+        foreach ($db_instances as $key => $instance) {
+          if (!array_key_exists($key, $features_instances) && (!isset($instance['widget_active']) || !empty($instance['widget_active']))) {
+            db_query("UPDATE {". content_instance_tablename() ."} SET widget_active = 0 WHERE field_name = '%s' AND type_name = '%s'", $instance['field_name'], $instance['type_name']);
+            $inactivated_instances[] = $instance['type_name'] .'-'. $instance['field_name'];
+          }
+        }
+      }
+    }
+  }
+  
+  if (!empty($inactivated_instances)) {
+    watchdog('features', t('The following field instances have been inactivated by the @module feature: @list', array('@list' => implode(', ', $inactivated_instances), '@module' => $module)));
+  }
+  // Once unused field instances have been de-activated, add/update instances that are still in use.
+  content_features_rebuild($module);  
 }
 
 /**
  * Implementation of hook_features_rebuild().
- * Rebuilds CCK field definitions from code defaults.
+ * Rebuilds CCK field definitions from code defaults.  
+ *
+ * Checks for previously-inactivated fields using the same name to re-activate
+ * them before running update.
  */
 function content_features_rebuild($module) {
   $fields = module_invoke($module, 'content_default_fields');
+  $db_instances = content_db_instances();  
+  $activated_instances = array();
+  
+  // Create or update any fields defined by this module.
   if (!empty($fields)) {
     module_load_include('inc', 'content', 'includes/content.crud');
     content_clear_type_cache(TRUE);
 
     foreach ($fields as $field) {
-      $existing_field = content_fields($field['field_name']);
-      $existing_instance = content_fields($field['field_name'], $field['type_name']);
-      if ($existing_field && $existing_instance) {
+      // If this existing instance exists but is inactive, we need to activate it before
+      // running content_field_instance_update().
+      $key = $field['type_name'] .'-'. $field['field_name'];
+      if ($existing_instance = $db_instances[$key]) {
+        if (empty($existing_instance['widget_active'])) {
+          db_query("UPDATE {". content_instance_tablename() ."} SET widget_active = 1 WHERE field_name = '%s' AND type_name = '%s'", $field['field_name'], $field['type_name']);
+          // We need to clear the type cache again, unfortunately.
+          content_clear_type_cache(TRUE);
+          $activated_instances[] = $key;
+        }
         content_field_instance_update($field, FALSE);
       }
       else {
@@ -152,6 +198,48 @@ function content_features_rebuild($modul
         content_field_instance_create($field, FALSE);
       }
       variable_set('menu_rebuild_needed', TRUE);
+    } 
+    content_clear_type_cache(TRUE); 
+  }
+  
+  if (!empty($activated_instances)) {
+    watchdog('features', t('The following inactive field instances have been re-activated by the @module feature: @list', array('@list' => implode(', ', $activated_instances), '@module' => $module)));
+  }
+}
+
+/**
+ * Helper function to return array of all field instances 
+ * defined by any feature, optionally limited
+ * to instances for a specific content type.
+ */
+function content_features_instances($type_name = NULL) {
+  $features_instances = array();
+  $modules = module_implements('content_default_fields');
+  foreach ($modules as $module) {
+    $fields = module_invoke($module, 'content_default_fields');
+    foreach ($fields as $field) {
+      if (empty($type_name) || $field['type_name'] == $type_name) {
+        $features_instances["{$field['type_name']}-{$field['field_name']}"] = $field;
+      }
     }
   }
+  return $features_instances;
 }
+
+/**
+ * Helper function to return array of all instances that exist in the database,
+ * including any that were previously marked inactive, optionally limited
+ * to instances from a specific content type.
+ *
+ * Uses API function to read directly from the database to include inactive instances.
+ */
+function content_db_instances($type_name = NULL) {
+  module_load_include('inc', 'content', 'includes/content.crud');
+  $db_instances = array();
+  foreach (content_field_instance_read(NULL, TRUE) as $field) {
+    if (empty($type_name) || $field['type_name'] == $type_name) {
+      $db_instances[$field['type_name'] .'-'. $field['field_name']] = $field;
+    }
+  }
+  return $db_instances;
+}
\ No newline at end of file
