CRM-14398 ... export issues
[civicrm-core.git] / CRM / Export / BAO / Export.php
index d82899b468e2b5a4dfd6dc4ad67e7123fd027e6c..7e78d6f310c14d9c1b7a6cf6b6d399e5a4938a04 100644 (file)
@@ -78,10 +78,7 @@ class CRM_Export_BAO_Export {
     $headerRows = $returnProperties = array();
     $primary    = $paymentFields    = $selectedPaymentFields = FALSE;
     $origFields = $fields;
-    $queryMode  = $relationField = NULL;
-
-    $allCampaigns = array();
-    $exportCampaign = FALSE;
+    $relationField = NULL;
 
     $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
     $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
@@ -157,9 +154,6 @@ class CRM_Export_BAO_Export {
         elseif ($fieldName == 'im') {
           $imProviderId = CRM_Utils_Array::value(3, $value);
         }
-        elseif (substr($fieldName, -8) == 'campaign') {
-          $exportCampaign = TRUE;
-        }
 
         if (array_key_exists($relationshipTypes, $contactRelationshipTypes)) {
           if (CRM_Utils_Array::value(2, $value)) {
@@ -236,12 +230,6 @@ class CRM_Export_BAO_Export {
           }
           else {
             $returnProperties[$fieldName] = 1;
-
-            //campaign field export.
-            if (substr($fieldName, -8) == 'campaign') {
-              $fldNames = explode('_', $fieldName);
-              $returnProperties["{$fldNames[0]}_campaign_id"] = 1;
-            }
           }
         }
       }
@@ -318,17 +306,6 @@ class CRM_Export_BAO_Export {
 
       if ($queryMode != CRM_Contact_BAO_Query::MODE_CONTACTS) {
         $componentReturnProperties = CRM_Contact_BAO_Query::defaultReturnProperties($queryMode);
-
-        $campaignReturnProperties = array();;
-        foreach ($componentReturnProperties as $fld => $true) {
-          $campaignReturnProperties[$fld] = $true;
-          if (substr($fld, -11) == 'campaign_id') {
-            $exportCampaign = TRUE;
-            $campaignReturnProperties[substr($fld, 0, -3)] = 1;
-          }
-        }
-        $componentReturnProperties = $campaignReturnProperties;
-
         $returnProperties = array_merge($returnProperties, $componentReturnProperties);
 
         if (!empty($extraReturnProperties)) {
@@ -401,6 +378,12 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       }
     }
 
+    // rectify params to what proximity search expects if there is a value for prox_distance
+    // CRM-7021
+    if (!empty($params)) {
+      CRM_Contact_BAO_ProximityQuery::fixInputParams($params);
+    }
+
     $query = new CRM_Contact_BAO_Query($params, $returnProperties, NULL,
       FALSE, FALSE, $queryMode,
       FALSE, TRUE, TRUE, NULL, $queryOperator
@@ -549,6 +532,20 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       }
     }
 
+    // CRM-13982 - check if is deleted
+    $excludeTrashed = TRUE;
+    foreach ($params as $value) {
+      if ($value[0] == 'contact_is_deleted') {
+        $excludeTrashed = FALSE;
+      }
+    }
+    if (empty($where) && $excludeTrashed) {
+      $where = "WHERE contact_a.is_deleted != 1";
+    }
+    elseif ($excludeTrashed) {
+      $where .= " AND contact_a.is_deleted != 1";
+    }
+
     $queryString = "$select $from $where $having";
 
     $groupBy = "";
@@ -561,6 +558,20 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       $groupBy = " GROUP BY contact_a.id";
     }
 
+    switch ($exportMode) {
+      case CRM_Export_Form_Select::CONTRIBUTE_EXPORT:
+        $groupBy = 'GROUP BY civicrm_contribution.id';
+        break;
+
+      case CRM_Export_Form_Select::EVENT_EXPORT:
+        $groupBy = 'GROUP BY civicrm_participant.id';
+        break;
+
+      case CRM_Export_Form_Select::MEMBER_EXPORT:
+        $groupBy = " GROUP BY civicrm_membership.id";
+        break;
+    }
+
     if ($queryMode & CRM_Contact_BAO_Query::MODE_ACTIVITY) {
       $groupBy = " GROUP BY civicrm_activity.id ";
     }
@@ -591,7 +602,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
           $addPaymentHeader = TRUE;
         }
       }
-      // If we have seleted specific payment fields, leave the payment headers
+      // If we have selected specific payment fields, leave the payment headers
       // as an empty array; the headers for each selected field will be added
       // elsewhere.
       else {
@@ -600,11 +611,6 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       $nullContributionDetails = array_fill_keys(array_keys($paymentHeaders), NULL);
     }
 
-    //get all campaigns.
-    if ($exportCampaign) {
-      $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE);
-    }
-
     $componentDetails = $headerRows = $sqlColumns = array();
     $setHeader = TRUE;
 
@@ -617,7 +623,17 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
     // for CRM-3157 purposes
     $i18n = CRM_Core_I18n::singleton();
-
+    $outputColumns = array();
+    //@todo - it would be clearer to start defining output columns earlier in this function rather than stick with return properties until this point
+    // as the array is not actually 'returnProperties' after the sql query is formed - making the alterations to it confusing
+    foreach ($returnProperties as $key => $value) {
+      $outputColumns[$key] = $value;
+      if (substr($key, -11) == 'campaign_id') {
+        // the field $dao->x_campaign_id_id holds the id whereas the field $dao->campaign_id
+        // we want to insert it directly after campaign id
+        $outputColumns[$key . '_id'] = 1;
+      }
+    }
     while (1) {
       $limitQuery = "{$queryString} LIMIT {$offset}, {$rowCount}";
       $dao = CRM_Core_DAO::executeQuery($limitQuery);
@@ -629,18 +645,33 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
         $count++;
         $row = array();
 
-        if ($exportMode == CRM_Export_Form_Select::CONTACT_EXPORT) {
-          //convert the pseudo constants
-          $query->convertToPseudoNames($dao);
-        }
-
-        //first loop through returnproperties so that we return what is required, and in same order.
+        //convert the pseudo constants
+        // CRM-14398 there is problem in this architecture that is not easily solved. For now we are using the cloned
+        // temporary iterationDAO object to get around it.
+        // the issue is that the convertToPseudoNames function is adding additional properties (e.g for campaign) to the DAO object
+        // these additional properties are NOT reset when the $dao cycles through the while loop
+        // nor are they overwritten as they are not in the loop
+        // the convertToPseudoNames will not adequately over-write them either as it doesn't 'kick-in' unless the
+        // relevant property is set.
+        // It may be that a long-term fix could be introduced there - however, it's probably necessary to figure out how to test the
+        // export class before tackling a better architectural fix
+        $iterationDAO = clone $dao;
+        $query->convertToPseudoNames($iterationDAO);
+
+        //first loop through output columns so that we return what is required, and in same order.
         $relationshipField = 0;
-        foreach ($returnProperties as $field => $value) {
+        foreach ($outputColumns as $field => $value) {
           //we should set header only once
           if ($setHeader) {
             $sqlDone = FALSE;
-            if (isset($query->_fields[$field]['title'])) {
+            // Split campaign into 2 fields for id and title
+            if (substr($field, -11) == 'campaign_id') {
+              $headerRows[] = ts('Campaign Title');
+            }
+            elseif (substr($field, -14) == 'campaign_id_id') {
+              $headerRows[] = ts('Campaign ID');
+            }
+            elseif (isset($query->_fields[$field]['title'])) {
               $headerRows[] = $query->_fields[$field]['title'];
             }
             elseif ($field == 'phone_type_id') {
@@ -751,14 +782,14 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
           }
 
           // add im_provider to $dao object
-          if ($field == 'im_provider' && property_exists($dao, 'provider_id')) {
-            $dao->im_provider = $dao->provider_id;
+          if ($field == 'im_provider' && property_exists($iterationDAO, 'provider_id')) {
+            $iterationDAO->im_provider = $iterationDAO->provider_id;
           }
 
           //build row values (data)
           $fieldValue = NULL;
-          if (property_exists($dao, $field)) {
-            $fieldValue = $dao->$field;
+          if (property_exists($iterationDAO, $field)) {
+            $fieldValue = $iterationDAO->$field;
             // to get phone type from phone type id
             if ($field == 'phone_type_id' && isset($phoneTypes[$fieldValue])) {
               $fieldValue = $phoneTypes[$fieldValue];
@@ -768,39 +799,36 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
             }
             elseif ($field == 'participant_role_id') {
               $participantRoles = CRM_Event_PseudoConstant::participantRole();
-              $sep              = CRM_Core_DAO::VALUE_SEPARATOR;
-              $viewRoles        = array();
-              foreach (explode($sep, $dao->$field) as $k => $v) {
+              $sep = CRM_Core_DAO::VALUE_SEPARATOR;
+              $viewRoles = array();
+              foreach (explode($sep, $iterationDAO->$field) as $k => $v) {
                 $viewRoles[] = $participantRoles[$v];
               }
               $fieldValue = implode(',', $viewRoles);
             }
             elseif ($field == 'master_id') {
               $masterAddressId = NULL;
-              if (isset($dao->master_id)) {
-                $masterAddressId = $dao->master_id;
+              if (isset($iterationDAO->master_id)) {
+                $masterAddressId = $iterationDAO->master_id;
               }
               // get display name of contact that address is shared.
-              $fieldValue = CRM_Contact_BAO_Contact::getMasterDisplayName($masterAddressId, $dao->contact_id);
+              $fieldValue = CRM_Contact_BAO_Contact::getMasterDisplayName($masterAddressId, $iterationDAO->contact_id);
             }
           }
 
           if ($field == 'id') {
-            $row[$field] = $dao->contact_id;
+            $row[$field] = $iterationDAO->contact_id;
             // special case for calculated field
           }
           elseif ($field == 'source_contact_id') {
-            $row[$field] = $dao->contact_id;
+            $row[$field] = $iterationDAO->contact_id;
           }
           elseif ($field == 'pledge_balance_amount') {
-            $row[$field] = $dao->pledge_amount - $dao->pledge_total_paid;
+            $row[$field] = $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
             // special case for calculated field
           }
           elseif ($field == 'pledge_next_pay_amount') {
-            $row[$field] = $dao->pledge_next_pay_amount + $dao->pledge_outstanding_amount;
-          }
-          elseif (in_array(substr($field, 0, -3), array('gender', 'prefix', 'suffix'))) {
-            $row[$field] = CRM_Core_PseudoConstant::getLabel('CRM_Contact_DAO_Contact', $field, $dao->$field);
+            $row[$field] = $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
           }
           elseif (is_array($value) && $field == 'location') {
             // fix header for location type case
@@ -808,36 +836,40 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
               foreach (array_keys($val) as $fld) {
                 $type = explode('-', $fld);
                 $fldValue = "{$ltype}-" . $type[0];
+                // CRM-14076 - fix label to work as the query object expects
+                // FIXME: We should not be using labels as keys!
+                $daoField = CRM_Utils_String::munge($ltype) . '-' . $type[0];
 
                 if (CRM_Utils_Array::value(1, $type)) {
                   $fldValue .= "-" . $type[1];
+                  $daoField .= "-" . $type[1];
                 }
 
                 // CRM-3157: localise country, region (both have ‘country’ context) and state_province (‘province’ context)
                 switch ($fld) {
                   case 'country':
                   case 'world_region':
-                    $row[$fldValue] = $i18n->crm_translate($dao->$fldValue, array('context' => 'country'));
+                    $row[$fldValue] = $i18n->crm_translate($iterationDAO->$daoField, array('context' => 'country'));
                     break;
 
                   case 'state_province':
-                    $row[$fldValue] = $i18n->crm_translate($dao->$fldValue, array('context' => 'province'));
+                    $row[$fldValue] = $i18n->crm_translate($iterationDAO->$daoField, array('context' => 'province'));
                     break;
 
                   case 'im_provider':
-                    $imFieldvalue = $fldValue . "-provider_id";
-                    $row[$fldValue] = CRM_Utils_Array::value($dao->$imFieldvalue, $imProviders);
+                    $imFieldvalue = $daoField . "-provider_id";
+                    $row[$fldValue] = CRM_Utils_Array::value($iterationDAO->$imFieldvalue, $imProviders);
                     break;
 
                   default:
-                    $row[$fldValue] = $dao->$fldValue;
+                    $row[$fldValue] = $iterationDAO->$daoField;
                     break;
                 }
               }
             }
           }
           elseif (array_key_exists($field, $contactRelationshipTypes)) {
-            $relDAO = CRM_Utils_Array::value($dao->contact_id, $allRelContactArray[$field]);
+            $relDAO = CRM_Utils_Array::value($iterationDAO->contact_id, $allRelContactArray[$field]);
             foreach ($value as $relationField => $relationValue) {
               if (is_object($relDAO) && property_exists($relDAO, $relationField)) {
                 $fieldValue = $relDAO->$relationField;
@@ -848,13 +880,28 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
                   $fieldValue = CRM_Utils_Array::value($relationValue, $imProviders);
                 }
               }
+              // CRM-13995
+              elseif (is_object($relDAO) && in_array($relationField, array(
+                'email_greeting', 'postal_greeting', 'addressee'))) {
+                //special case for greeting replacement
+                $fldValue = "{$relationField}_display";
+                $fieldValue = $relDAO->$fldValue;
+              }
+              elseif ( is_object($relDAO) && $relationField == 'state_province' ) {
+                $fieldValue = CRM_Core_PseudoConstant::stateProvince($relDAO->state_province_id);
+              }
+              elseif ( is_object($relDAO) && $relationField == 'country' ) {
+                $fieldValue = CRM_Core_PseudoConstant::country($relDAO->country_id);
+              }
               else {
                 $fieldValue = '';
               }
               $field = $field . '_';
+
               if (is_object($relDAO) && $relationField == 'id') {
                 $row[$field . $relationField] = $relDAO->contact_id;
-                            } else  if ( is_object( $relDAO ) && is_array( $relationValue ) && $relationField == 'location' ) {
+              }
+              elseif ( is_object( $relDAO ) && is_array( $relationValue ) && $relationField == 'location' ) {
                 foreach ($relationValue as $ltype => $val) {
                   foreach (array_keys($val) as $fld) {
                     $type = explode('-', $fld);
@@ -896,12 +943,6 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
                     $relationQuery[$field]->_options
                   );
                 }
-                elseif (in_array($relationField, array(
-                  'email_greeting', 'postal_greeting', 'addressee'))) {
-                  //special case for greeting replacement
-                  $fldValue = "{$relationField}_display";
-                  $row[$field . $relationField] = $relDAO->$fldValue;
-                }
                 else {
                   //normal relationship fields
                   // CRM-3157: localise country, region (both have ‘country’ context) and state_province (‘province’ context)
@@ -950,11 +991,12 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
               CRM_Core_OptionGroup::lookupValues($paramsNew, $name, FALSE);
               $row[$field] = $paramsNew[$field];
             }
+
             elseif (in_array($field, array(
               'email_greeting', 'postal_greeting', 'addressee'))) {
               //special case for greeting replacement
               $fldValue = "{$field}_display";
-              $row[$field] = $dao->$fldValue;
+              $row[$field] = $iterationDAO->$fldValue;
             }
             else {
               //normal fields with a touch of CRM-3157
@@ -980,12 +1022,8 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
               }
             }
           }
-          elseif (substr($field, -8) == 'campaign') {
-            $campIdFld = "{$field}_id";
-            $row[$field] = CRM_Utils_Array::value($dao->$campIdFld, $allCampaigns, '');
-          }
           elseif ($selectedPaymentFields && array_key_exists($field, self::componentPaymentFields())) {
-            $paymentData = CRM_Utils_Array::value($dao->$paymentTableId, $paymentDetails);
+            $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
             $payFieldMapper = array(
               'componentPaymentField_total_amount'        => 'total_amount',
               'componentPaymentField_contribution_status' => 'contribution_status',
@@ -1138,7 +1176,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
    * Function to handle import error file creation.
    *
    */
-  function invoke() {
+  static function invoke() {
     $type = CRM_Utils_Request::retrieve('type', 'Positive', CRM_Core_DAO::$_nullObject);
     $parserName = CRM_Utils_Request::retrieve('parser', 'String', CRM_Core_DAO::$_nullObject);
     if (empty($parserName) || empty($type)) {
@@ -1175,7 +1213,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
     CRM_Utils_System::civiExit();
   }
 
-  function exportCustom($customSearchClass, $formValues, $order) {
+  static function exportCustom($customSearchClass, $formValues, $order) {
     $ext = CRM_Extension_System::singleton()->getMapper();
     if (!$ext->isExtensionClass($customSearchClass)) {
       require_once (str_replace('_', DIRECTORY_SEPARATOR, $customSearchClass) . '.php');
@@ -1236,6 +1274,13 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       return;
     }
 
+    if (substr($fieldName, -11) == 'campaign_id') {
+      // CRM-14398
+      $sqlColumns[$fieldName] = "$fieldName varchar(128)";
+      $sqlColumns[$fieldName . '_id'] = "{$fieldName}_id varchar(16)";
+      return;
+    }
+
     // set the sql columns
     if (isset($query->_fields[$field]['type'])) {
       switch ($query->_fields[$field]['type']) {
@@ -1276,7 +1321,19 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
     }
     else {
       if (substr($fieldName, -3, 3) == '_id') {
-        $sqlColumns[$fieldName] = "$fieldName varchar(16)";
+        // for trxn_id and its variants use a longer buffer
+        // to accomodate different systems - CRM-13739
+        static $notRealIDFields = NULL;
+        if ($notRealIDFields == NULL) {
+          $notRealIDFields = array( 'trxn_id', 'componentpaymentfield_transaction_id' );
+        }
+
+        if (in_array($fieldName, $notRealIDFields)) {
+          $sqlColumns[$fieldName] = "$fieldName varchar(255)";
+        }
+        else {
+          $sqlColumns[$fieldName] = "$fieldName varchar(16)";
+        }
       }
       else {
         $changeFields = array(
@@ -1803,7 +1860,7 @@ LIMIT $offset, $limit
    * or have no street address
    *
    */
-  function postalMailingFormat($exportTempTable, &$headerRows, &$sqlColumns, $exportParams) {
+  static function postalMailingFormat($exportTempTable, &$headerRows, &$sqlColumns, $exportParams) {
     $whereClause = array();
 
     if (array_key_exists('is_deceased', $sqlColumns)) {