Index: profile_csv.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/profile_csv/profile_csv.info,v
retrieving revision 1.3.2.2
diff -u -p -r1.3.2.2 profile_csv.info
--- profile_csv.info	11 May 2010 23:32:37 -0000	1.3.2.2
+++ profile_csv.info	8 Sep 2010 14:06:58 -0000
@@ -1,5 +1,3 @@
 name = Profile CSV
-description    = Allows exporting profile data in Comma Separated Values (CSV) format.
-dependencies[] = profile
+description    = "Allows exporting profile data in Comma Separated Values (CSV) format, works with either the core Profile module or nodes via <a href='http://drupal.org/projects/content_profile'>Content_Profile</a>."
 core           = 6.x
-
Index: profile_csv.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/profile_csv/profile_csv.module,v
retrieving revision 1.10.2.6
diff -u -p -r1.10.2.6 profile_csv.module
--- profile_csv.module	12 Aug 2010 15:59:16 -0000	1.10.2.6
+++ profile_csv.module	8 Sep 2010 14:06:58 -0000
@@ -84,9 +84,9 @@ function profile_csv_admin_settings() {
     '#collapsed'   => TRUE,
   );
   $options = array(
-  1 => t('Active'),
-  0 => t('Blocked'),
-  2 => t('Both'),
+    1 => t('Active'),
+    0 => t('Blocked'),
+    2 => t('Both'),
   );
   $form[$set][PROFILE_CSV_STATUS] = array(
     '#type'          => 'select',
@@ -115,35 +115,175 @@ function profile_csv_admin_settings() {
     '#default_value' => variable_get(PROFILE_CSV_PARAM .'fields', array()),
   );
 
+  // Drupal core's profile module.
   $set = 'profile';
-  $form[$set] = array(
-    '#type'        => 'fieldset',
-    '#title'       => t('Categories'),
-    '#description' => t('Select one or more profile fields from categories below.'),
-    '#collapsible' => TRUE,
-    '#collapsed'   => TRUE,
-  );
+  if (!module_exists($set)) {
+    $form[$set] = array(
+      '#type'        => 'fieldset',
+      '#title'       => t('Profile Fields'),
+      '#description' => t('No profile fields are available as the core Profile module is disabled.  Once it is <a href="%link">enabled</a> and fields are added they will be listed here.', array('%link' => url('admin/build/modules'))),
+      '#collapsible' => FALSE,
+      '#collapsed'   => FALSE,
+    );
+  }
+  else {
+    $form[$set] = array(
+      '#type'        => 'fieldset',
+      '#title'       => t('Profile Fields'),
+      '#description' => t('Select one or more profile fields from categories below.  These are provided by the core Durpal Profiles module.'),
+      '#collapsible' => TRUE,
+      '#collapsed'   => TRUE,
+    );
 
-  $result = db_query("SELECT pf.fid, pf.name, pf.title, pf.category
-    FROM {profile_fields} pf
-    ORDER BY pf.category, pf.weight, pf.title");
-  while ($row = db_fetch_object($result)) {
-    $fld = PROFILE_CSV_PARAM .'profile_'. $row->fid;
-    if (!isset($form[$set][$row->category])) {
-      $form[$set][$row->category] = array(
-        '#type'        => 'fieldset',
-        '#title'       => check_plain(t($row->category)),
-        '#collapsible' => TRUE,
+    $result = db_query("SELECT pf.fid, pf.name, pf.title, pf.category
+      FROM {profile_fields} pf
+      ORDER BY pf.category, pf.weight, pf.title");
+    $profile_fields = FALSE;
+    while ($row = db_fetch_object($result)) {
+      $profile_fields = TRUE;
+      $fld = PROFILE_CSV_PARAM .'profile_'. $row->fid;
+      if (!isset($form[$set][$row->category])) {
+        $form[$set][$row->category] = array(
+          '#type'        => 'fieldset',
+          '#title'       => check_plain(t($row->category)),
+          '#collapsible' => TRUE,
+        );
+      }
+
+      $form[$set][$row->category][$fld] = array(
+        '#type'          => 'checkbox',
+        '#title'         => check_plain(t($row->title)),
+        '#return_value'  => 1,
+        '#default_value' => variable_get($fld, FALSE),
       );
     }
+    if (!$profile_fields) {
+      $form[$set]['#description'] .= '<br />' . t('Note: No fields have been configured, once <a href="%link">fields are added</a> they will appear below.', array('%link' => url('admin/user/profile')));
+    }
+  }
 
-    $form[$set][$row->category][$fld] = array(
-      '#type'          => 'checkbox',
-      '#title'         => check_plain(t($row->title)),
-      '#return_value'  => 1,
-      '#default_value' => variable_get($fld, 0),
+  $set = 'content_profile';
+  if (!module_exists($set)) {
+    $form[$set] = array(
+      '#type'        => 'fieldset',
+      '#title'       => t('Content_Profile Fields'),
+      '#description' => t('No fields are available as the <a href="%link">Content Profile</a> contrib module is not installed.', array('%link' => url('http://drupal.org/project/content_profile'))),
+      '#collapsible' => FALSE,
+      '#collapsed'   => FALSE,
+    );
+  }
+  else {
+    $form[$set] = array(
+      '#type'        => 'fieldset',
+      '#title'       => t('Content_Profile Fields'),
+      '#description' => t('Select one or more profile fields from categories below.  These are provided by the <a href="%link">Content Profile</a> contrib module.', array('%link' => url('http://drupal.org/project/content_profile'))),
+      '#collapsible' => TRUE,
+      '#collapsed'   => TRUE,
     );
+
+    // Get a list of all content types.
+    foreach (_profile_csv_get_content_profile_types() as $type_name => $type) {
+      // Start a new fieldset to contain everything.
+      $fieldset = PROFILE_CSV_PARAM . 'content_profile_' . $type_name;
+      $form[$set][$fieldset] = array(
+        '#type'        => 'fieldset',
+        '#title'       => check_plain($type_details['name']),
+        '#collapsible' => TRUE,
+      );
+
+      // Optional title.
+      if ($type->has_title) {
+        $fld = PROFILE_CSV_PARAM . $type_name . '_title';
+        $form[$set][$fieldset][$fld] = array(
+          '#type'          => 'checkbox',
+          '#title'         => check_plain(t($type->title_label . ' (node title)')),
+          '#return_value'  => 1,
+          '#default_value' => variable_get($fld, FALSE),
+        );
+      }
+
+      // Optional body field.
+      if ($type->has_body) {
+        $fld = PROFILE_CSV_PARAM . $type_name . '_body';
+        $form[$set][$fieldset][$fld] = array(
+          '#type'          => 'checkbox',
+          '#title'         => check_plain(t($type->body_label . ' (node body)')),
+          '#return_value'  => 1,
+          '#default_value' => variable_get($fld, FALSE),
+        );
+      }
+
+      // Vocabularies.
+      if (module_exists('taxonomy')) {
+        $vocabs = taxonomy_get_vocabularies($type_name);
+        if (!empty($vocabs)) {
+          $form[$set][$fieldset]['vocabs'] = array(
+            '#type'        => 'fieldset',
+            '#title'       => check_plain(t('Vocabularies')),
+            '#collapsible' => TRUE,
+          );
+          foreach ($vocabs as $vocab_name => $vocab) {
+            $fld = PROFILE_CSV_PARAM . $type_name . '_vocab_' . $vocab_name;
+            $form[$set][$fieldset]['vocabs'][$fld] = array(
+              '#type'          => 'checkbox',
+              '#title'         => check_plain($vocab->name),
+              '#return_value'  => 1,
+              '#default_value' => variable_get($fld, FALSE),
+            );
+          }
+        }
+      }
+
+      // CCK.
+      if (module_exists('content')) {
+        $type_details = content_types($type_name);
+
+        $form_groups = array();
+        if (function_exists('fieldgroup_groups') && $groups = fieldgroup_groups($type_name)) {
+          // Loop over each of the fieldgroups that are used for this type.
+          foreach ($groups as $group_name => $group) {
+            $form_groups[$group_name] = array(
+              '#type'        => 'fieldset',
+              '#title'       => check_plain($group['label']),
+              '#collapsible' => TRUE,
+            );
+            // Loop over each field that is stored in this group.
+            foreach ($group['fields'] as $field_name => $field) {
+              $fld = PROFILE_CSV_PARAM . $type_name . '_' . $field_name;
+              $form_groups[$group_name][$fld] = array(
+                '#type'          => 'checkbox',
+                '#title'         => check_plain($field['label'] . ' (' . $field['widget_type'] . ')'),
+                '#return_value'  => 1,
+                '#default_value' => variable_get($fld, FALSE),
+              );
+              // Remove this field from the main stack so it isn't processed again.
+              unset($type_details['fields'][$field_name]);
+            }
+          }
+        }
+
+        // Loop over each field.
+        foreach ($type_details['fields'] as $field_name => $field) {
+          $fld = PROFILE_CSV_PARAM . $type_name . '_' . $field_name;
+          $form[$set][$fieldset][$fld] = array(
+            '#type'          => 'checkbox',
+            '#title'         => check_plain($field['widget']['label'] . ' (' . $field['widget']['type'] . ')'),
+            '#return_value'  => 1,
+            '#default_value' => variable_get($fld, FALSE),
+          );
+        }
+
+        // Add any fieldgroups after the individual fields.
+        if (!empty($form_groups)) {
+          $form[$set][$fieldset] += $form_groups;
+        }
+      }
+    }
   }
+
+  //TODO: add a hook to allow modules to tap into the output.
+  //TODO: location module support.
+
   return system_settings_form($form);
 }
 
@@ -195,6 +335,9 @@ function profile_csv_page() {
   exit();
 }
 
+/**
+ * List of fields from the core Profile module.
+ */
 function _profile_csv_get_profile_fields() {
   static $fields;
 
@@ -212,17 +355,138 @@ function _profile_csv_get_profile_fields
   return $fields;
 }
 
+/**
+ * List of content types that are used for profiles.
+ */
+function _profile_csv_get_content_profile_types() {
+  static $types;
+
+  if (!isset($types)) {
+    $types = array();
+    foreach (node_get_types() as $type_name => $type) {
+      // See if this content type is used for content_profile.
+      if (variable_get('content_profile_use_' . $type_name, FALSE)) {
+        $types[$type_name] = $type;
+      }
+    }
+  }
+
+  return $types;
+}
+
+/**
+ * List of fields from the Content_Profile module & CCK.
+ */
+function _profile_csv_get_content_profile_fields() {
+  static $fields;
+
+  if (!isset($fields)) {
+    $fields = array();
+    foreach (_profile_csv_get_content_profile_types() as $type_name => $type) {
+      // Title.
+      if ($type->has_title) {
+        $fld = PROFILE_CSV_PARAM . $type_name . '_title';
+        if (variable_set($fld, FALSE)) {
+          $fields[] = array('name' => 'title', 'title' => $type->title_label, 'type' => $type->type, 'visibility' => 1, 'node_type' => $type_name);
+        }
+      }
+      // Body.
+      if ($type->has_body) {
+        $fld = PROFILE_CSV_PARAM . $type_name . '_body';
+        if (variable_set($fld, FALSE)) {
+          $fields[] = array('name' => 'body', 'title' => $type->body_label, 'type' => 'body', 'visibility' => 1, 'node_type' => $type_name);
+        }
+      }
+
+      // Vocabularies.
+      if (module_exists('taxonomy')) {
+        $vocabs = taxonomy_get_vocabularies($type_name);
+        if (!empty($vocabs)) {
+          foreach ($vocabs as $vocab_name => $vocab) {
+            $fld = PROFILE_CSV_PARAM . $type_name . '_vocab_' . $vocab_name;
+            if (variable_set($fld, FALSE)) {
+              $fields[] = array('name' => 'vocab_' . $vocab_name, 'title' => $vocab->name, 'type' => 'vocab', 'visibility' => 1, 'node_type' => $type_name);
+            }
+          }
+        }
+      }
+
+      // CCK.
+      if (module_exists('content')) {
+        $type_details = content_types($type_name);
+        $form_groups = array();
+
+        if (function_exists('fieldgroup_groups') && $groups = fieldgroup_groups($type_name)) {
+          // Loop over each of the fieldgroups that are used for this type.
+          foreach ($groups as $group_name => $group) {
+            // Loop over each field that is stored in this group.
+            foreach ($group['fields'] as $field_name => $field) {
+              $fld = PROFILE_CSV_PARAM . $type_name . '_' . $field_name;
+              if (variable_get($fld, FALSE)) {
+                $form_groups[] = array('name' => $field_name, 'title' => $field['label'], 'type' => $field['widget_type'], 'visibility' => 1, 'node_type' => $type_name);
+              }
+              // Remove this field from the main stack so it isn't processed again.
+              unset($type_details['fields'][$field_name]);
+            }
+          }
+        }
+
+        // Loop over each field.
+        foreach ($type_details['fields'] as $field_name => $field) {
+          $fld = PROFILE_CSV_PARAM . $type_name . '_' . $field_name;
+          if (variable_get($fld, FALSE)) {
+            $fields[] = array('name' => $fld, 'title' => $field['widget']['label'], 'type' => $field['widget']['type'], 'visibility' => 1, 'node_type' => $type_name);
+          }
+        }
+
+        // Add any fieldgroups after the individual fields.
+        if (!empty($form_groups)) {
+          $fields += $form_groups;
+        }
+      }
+    }
+
+    // Allow other modules to alter the output.
+    // hook_profile_csv_fields(&$fields);
+    $hook = 'profile_csv_fields';
+    foreach (module_implements($hook) as $module) {
+      $f = $module . '_' . $hook;
+      $f($fields, $field, $node);
+    }
+  }
+
+  return $fields;
+}
+
 function _profile_csv_format_user($uid = 0) {
-  $user_data = _profile_csv_get_user($uid);
-  $profile_data = _profile_csv_get_profile($uid, $user_data['data']);
-  unset($user_data['data']);
-  $info = array_merge($user_data, $profile_data);
-  //all of the valid fields in ['data'] should have been picked out in _profile_csv_get_profile, so unset it
+  $new_info = array();
+
+  // Get the basic user fields.
+  $info = _profile_csv_get_user($uid);
+
+  // The profile module is enabled.
+  if (module_exists('profile')) {
+    $profile_data = _profile_csv_get_profile($uid, $info['data']);
+    // All of the valid fields in ['data'] should have been picked out in
+    // _profile_csv_get_profile, so unset it.
+    unset($info['data']);
+    $info += $profile_data;
+  }
+
+  // The profile module is enabled.
+  if (module_exists('content_profile')) {
+    $profile_data = _profile_csv_get_content_profile($uid);
+    // All of the valid fields in ['data'] should have been picked out in
+    // _profile_csv_get_profile, so unset it.
+    unset($info['data']);
+    $info += $profile_data;
+  }
 
+  // Compile the fields.
   foreach ($info as $value) {
     $new_info[] = '"'. str_replace('"', '""', $value) .'"';
   }
-  if (isset($new_info)) {
+  if (!empty($new_info)) {
     $line = implode(",", $new_info);
   }
   $data .= trim($line) ."\n";
@@ -233,7 +497,8 @@ function _profile_csv_format_user($uid =
 function _profile_csv_get_user($uid) {
   $user = array();
   $fields = _profile_csv_users_selected_fields();
-  //Verify that the columns haven't been deleted since the last save or the query will fail
+  // Verify that the columns haven't been deleted since the last save or the
+  // query will fail.
   $schema = drupal_get_schema('users');
   foreach ($fields as $field_name => $value) {
     if (!$schema['fields'][$field_name]) {
@@ -253,8 +518,8 @@ function _profile_csv_get_user($uid) {
 function _profile_csv_get_profile($uid=0, $user_data=NULL) {
   $profile_fields = _profile_csv_get_profile_fields();
   $profile_result = array();
-  foreach ($profile_fields  as $profile_field) {
-    if ($profile_field ['visibility'] == 4) {
+  foreach ($profile_fields as $profile_field) {
+    if ($profile_field['visibility'] == 4) {
       // Try to get it from the $user_data
       $value = $user_data[$profile_field['name']];
     }
@@ -277,14 +542,179 @@ function _profile_csv_get_profile($uid=0
   return $profile_result;
 }
 
+/**
+ * Obtain data from the content profile.
+ */
+function _profile_csv_get_content_profile($uid=0) {
+  $profile_fields = _profile_csv_get_content_profile_fields();
+  $profile_result = array();
+  // Loop over each supported profile content type.
+  foreach (_profile_csv_get_content_profile_types() as $type_name => $type) {
+    $results = db_query("SELECT nid FROM {node} WHERE uid=%d AND type='%s'", $uid, $type_name);
+
+    // Loop over each profile node for this user.
+    while ($n = db_fetch_array($results)) {
+      // Load the full node. Note: node caching would help here.
+      $node = node_load($n['nid']);
+
+      // Loop over each field.
+      foreach ($profile_fields as $field) {
+        // If this field is in this node type, process it.
+        if ($field['node_type'] == $type_name) {
+          // Allow some fields to be based on others.
+          if (isset($field['base'])) {
+            $value = $node->{$field['base']};
+          }
+          else {
+            $value = $node->{$field['name']};
+          }
+
+          // See if any hooks want to modify the output.
+          // hook_profile_csv_export(&$value, $field, $node);
+          $from_hook = FALSE;
+          $hook = 'profile_csv_export';
+          foreach (module_implements($hook) as $module) {
+            $f = $module . '_' . $hook;
+            $return = $f($value, $field, $node);
+            // Take the first response that returns.
+            if ($return) {
+              $from_hook = TRUE;
+              break;
+            }
+          }
+
+          // If nothing returned from the hook, handle it here.
+          if (!$from_hook) {
+            switch ($field['type']) {
+              // Core fields.
+              case 'title':
+              case 'body':
+                // Keep the fields as-is.
+                break;
+
+              // Standard CCK text fields.
+              case 'text_textarea':
+              case 'text_textfield':
+                $values = array();
+                foreach ($value as $x => $data) {
+                  $values[] = $data['value'];
+                }
+                $value = $values;
+                unset($values);
+                break;
+
+              // Standard CCK optionwidget fields.
+              case 'optionwidgets_buttons':
+              case 'optionwidgets_select':
+                $values = array();
+                foreach ($value as $x => $data) {
+                  $values[] = $data['value'];
+                }
+                $value = implode(', ', $values);
+                unset($values);
+                break;
+
+              // Date module.
+              case 'date_select':
+                // Empty date strings.
+                $dates = array();
+                foreach ($value as $date) {
+                  // Skip empty dates.
+                  if ($date['value'] != '0000-00-00T00:00:00') {
+                    $dates[] = date_format_date($date['value']);
+                  }
+                }
+                $value = $dates;
+                unset($dates);
+                break;
+
+              // Link module.
+              case 'link':
+                $links = array();
+                foreach ($value as $link) {
+                  if (!empty($link['title'])) {
+                    $links[] = $link['title'] . ': ' . $link['url'];
+                  }
+                  else {
+                    $links[] = $link['url'];
+                  }
+                }
+                $value = implode("\n", $links);
+                break;
+
+              // Location module.
+              case 'location':
+                $locations = array();
+                foreach ($value as $l) {
+                  $locations[] = strip_tags(theme('location', $l));
+                }
+                $value = $locations;
+                unset($locations);
+                break;
+
+              // Content_Taxonomy module.
+              case 'content_taxonomy_autocomplete':
+                $terms = array();
+                foreach ($value as $t) {
+                  $term = taxonomy_get_term($t['value']);
+                  $terms[] = check_plain($term->name);
+                }
+                // These can be joined into one line.
+                $value = implode(', ', $terms);
+                unset($terms);
+                break;
+
+              // Computed module.
+              case 'computed':
+                $output = array();
+                foreach ($value as $val) {
+                  $output[] = check_plain($val);
+                }
+                $value = $output;
+                unset($output);
+                break;
+
+              // Anything else.
+              default:
+                watchdog('profile_csv', "Unknown field {$field['type']}.");
+                $output = array();
+                foreach ($value as $val) {
+                  $output[] = strip_tags(content_format($field['type'], $val));
+                }
+                $value = $output;
+                unset($output);
+            }
+          }
+          if (is_array($value)) {
+            $value = implode("\n", $value);
+          }
+          $profile_result[] = trim($value);
+        }
+      }
+    }
+  }
+  return $profile_result;
+}
+
 function _profile_csv_header() {
   $row = array();
   $fields = _profile_csv_users_selected_fields();
   foreach ($fields as $field_name => $value) {
     $row[] = '"'. _profile_csv_users_map_column_name($field_name) .'"';
   }
-  foreach (_profile_csv_get_profile_fields() as $field) {
-    $row[] = '"'. $field['title'] .'"';
+
+  // The profile module is enabled.
+  if (module_exists('profile')) {
+    foreach (_profile_csv_get_profile_fields() as $field) {
+      $row[] = '"'. $field['title'] .'"';
+    }
+  }
+
+  // The content_profile module is enabled.
+  if (module_exists('content_profile')) {
+    foreach (_profile_csv_get_content_profile_fields() as $field) {
+      $row[] = '"'. $field['title'] .'"';
+    }
   }
 
   return implode(",", $row) ."\n";
