Fix Export when full group by mode is used
[civicrm-core.git] / CRM / Export / BAO / Export.php
index c5e82945f7b95c8cca93c980e5c88d43eace0673..c56ca09031a3e90cd3b6ac6af59c833085a04e2b 100644 (file)
@@ -166,14 +166,7 @@ class CRM_Export_BAO_Export {
       $groupBy = "civicrm_activity.id ";
     }
 
-    if (!empty($groupBy)) {
-      if (!Civi::settings()->get('searchPrimaryDetailsOnly')) {
-        CRM_Core_DAO::disableFullGroupByMode();
-      }
-      $groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($query->_select, $groupBy);
-    }
-
-    return $groupBy;
+    return $groupBy ? ' GROUP BY ' . $groupBy : '';
   }
 
   /**
@@ -228,15 +221,8 @@ class CRM_Export_BAO_Export {
 
     $processor = new CRM_Export_BAO_ExportProcessor($exportMode, $fields, $queryOperator, $mergeSameHousehold);
     $returnProperties = array();
-
-    $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
-    // Warning - this imProviders var is used in a somewhat fragile way - don't rename it
-    // without manually testing the export of IM provider still works.
-    $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
     self::$relationshipTypes = $processor->getRelationshipTypes();
 
-    $queryMode = $processor->getQueryMode();
-
     if ($fields) {
       foreach ($fields as $key => $value) {
         $fieldName = CRM_Utils_Array::value(1, $value);
@@ -432,29 +418,19 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
     $paymentDetails = array();
     if ($processor->isExportPaymentFields()) {
-
       // get payment related in for event and members
       $paymentDetails = CRM_Contribute_BAO_Contribution::getContributionDetails($exportMode, $ids);
       //get all payment headers.
       // If we haven't selected specific payment fields, load in all the
       // payment headers.
       if (!$processor->isExportSpecifiedPaymentFields()) {
-        $paymentHeaders = self::componentPaymentFields();
         if (!empty($paymentDetails)) {
           $addPaymentHeader = TRUE;
         }
       }
-      // 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 {
-        $paymentHeaders = array();
-      }
-      $nullContributionDetails = array_fill_keys(array_keys($paymentHeaders), NULL);
     }
 
     $componentDetails = array();
-    $setHeader = TRUE;
 
     $rowCount = self::EXPORT_ROW_COUNT;
     $offset = 0;
@@ -463,15 +439,26 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
     $count = -1;
 
-    // for CRM-3157 purposes
-    $i18n = CRM_Core_I18n::singleton();
-
     list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor);
 
+    // add payment headers if required
+    if ($addPaymentHeader && $processor->isExportPaymentFields()) {
+      // @todo rather than do this for every single row do it before the loop starts.
+      // where other header definitions take place.
+      $headerRows = array_merge($headerRows, $processor->getPaymentHeaders());
+      foreach (array_keys($processor->getPaymentHeaders()) as $paymentHdr) {
+        self::sqlColumnDefn($processor, $sqlColumns, $paymentHdr);
+      }
+    }
+
+    $exportTempTable = self::createTempTable($sqlColumns);
     $limitReached = FALSE;
+
     while (!$limitReached) {
       $limitQuery = "{$queryString} LIMIT {$offset}, {$rowCount}";
+      CRM_Core_DAO::disableFullGroupByMode();
       $iterationDAO = CRM_Core_DAO::executeQuery($limitQuery);
+      CRM_Core_DAO::reenableFullGroupByMode();
       // If this is less than our limit by the end of the iteration we do not need to run the query again to
       // check if some remain.
       $rowsThisIteration = 0;
@@ -479,99 +466,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       while ($iterationDAO->fetch()) {
         $count++;
         $rowsThisIteration++;
-        $row = array();
-        $query->convertToPseudoNames($iterationDAO);
-
-        //first loop through output columns so that we return what is required, and in same order.
-        foreach ($outputColumns as $field => $value) {
-
-          // add im_provider to $dao object
-          if ($field == 'im_provider' && property_exists($iterationDAO, 'provider_id')) {
-            $iterationDAO->im_provider = $iterationDAO->provider_id;
-          }
-
-          //build row values (data)
-          $fieldValue = NULL;
-          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];
-            }
-            elseif ($field == 'provider_id' || $field == 'im_provider') {
-              $fieldValue = CRM_Utils_Array::value($fieldValue, $imProviders);
-            }
-            elseif (strstr($field, 'master_id')) {
-              $masterAddressId = NULL;
-              if (isset($iterationDAO->$field)) {
-                $masterAddressId = $iterationDAO->$field;
-              }
-              // get display name of contact that address is shared.
-              $fieldValue = CRM_Contact_BAO_Contact::getMasterDisplayName($masterAddressId);
-            }
-          }
-
-          if ($processor->isRelationshipTypeKey($field)) {
-            foreach (array_keys($value) as $property) {
-              if ($property === 'location') {
-                // @todo just undo all this nasty location wrangling!
-                foreach ($value['location'] as $locationKey => $locationFields) {
-                  foreach (array_keys($locationFields) as $locationField) {
-                    $fieldKey = str_replace(' ', '_', $locationKey . '-' . $locationField);
-                    $row[$field . '_' . $fieldKey] = $processor->getRelationshipValue($field, $iterationDAO->contact_id, $fieldKey);
-                  }
-                }
-              }
-              else {
-                $row[$field . '_' . $property] = $processor->getRelationshipValue($field, $iterationDAO->contact_id, $property);
-              }
-            }
-          }
-          else {
-            $row[$field] = self::getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor);
-          }
-        }
-
-        // add payment headers if required
-        if ($addPaymentHeader && $processor->isExportPaymentFields()) {
-          // @todo rather than do this for every single row do it before the loop starts.
-          // where other header definitions take place.
-          $headerRows = array_merge($headerRows, $paymentHeaders);
-          foreach (array_keys($paymentHeaders) as $paymentHdr) {
-            self::sqlColumnDefn($processor, $sqlColumns, $paymentHdr);
-          }
-        }
-
-        if ($setHeader) {
-          $exportTempTable = self::createTempTable($sqlColumns);
-        }
-
-        //build header only once
-        $setHeader = FALSE;
-
-        // If specific payment fields have been selected for export, payment
-        // data will already be in $row. Otherwise, add payment related
-        // information, if appropriate.
-        if ($addPaymentHeader) {
-          if (!$processor->isExportSpecifiedPaymentFields()) {
-            if ($processor->isExportPaymentFields()) {
-              $paymentData = CRM_Utils_Array::value($row[$paymentTableId], $paymentDetails);
-              if (!is_array($paymentData) || empty($paymentData)) {
-                $paymentData = $nullContributionDetails;
-              }
-              $row = array_merge($row, $paymentData);
-            }
-            elseif (!empty($paymentDetails)) {
-              $row = array_merge($row, $nullContributionDetails);
-            }
-          }
-        }
-        //remove organization name for individuals if it is set for current employer
-        if (!empty($row['contact_type']) &&
-          $row['contact_type'] == 'Individual' && array_key_exists('organization_name', $row)
-        ) {
-          $row['organization_name'] = '';
-        }
+        $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader, $paymentTableId);
 
         // add component info
         // write the row to a file
@@ -1304,6 +1199,11 @@ WHERE  {$whereClause}";
 
   /**
    * Build componentPayment fields.
+   *
+   * This is no longer used by export but BAO_Mapping still calls it & we
+   * should find a generic way to handle this or move this to that class.
+   *
+   * @deprecated
    */
   public static function componentPaymentFields() {
     static $componentPaymentFields;
@@ -1341,12 +1241,8 @@ WHERE  {$whereClause}";
     elseif (isset($queryFields[$field]['title'])) {
       $headerRows[] = $queryFields[$field]['title'];
     }
-    elseif ($field == 'provider_id') {
-      // @todo - set this correctly in the xml rather than here.
-      $headerRows[] = ts('IM Service Provider');
-    }
-    elseif ($processor->isExportPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
-      $headerRows[] = CRM_Utils_Array::value($field, self::componentPaymentFields());
+    elseif ($processor->isExportPaymentFields() && array_key_exists($field, $processor->getcomponentPaymentFields())) {
+      $headerRows[] = CRM_Utils_Array::value($field, $processor->getcomponentPaymentFields());
     }
     else {
       $headerRows[] = $field;
@@ -1414,11 +1310,6 @@ WHERE  {$whereClause}";
             $headerRows[] = $headerName;
             self::sqlColumnDefn($processor, $sqlColumns, $headerName);
           }
-          elseif ($relationField == 'provider_id') {
-            $headerName = $field . '-' . 'Im Service Provider';
-            $headerRows[] = $headerName;
-            self::sqlColumnDefn($processor, $sqlColumns, $headerName);
-          }
           elseif ($relationField == 'state_province_id') {
             $headerName = $field . '-' . 'state_province_id';
             $headerRows[] = $headerName;
@@ -1689,11 +1580,13 @@ WHERE  {$whereClause}";
       $today = date('Ymd');
       $relationActive = " AND (crel.is_active = 1 AND ( crel.end_date is NULL OR crel.end_date >= {$today} ) )";
       $relationWhere = " WHERE contact_a.is_deleted = 0 {$relationshipClause} {$relationActive}";
-      $relationGroupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($relationQuery->_select, "crel.{$contactA}");
+      CRM_Core_DAO::disableFullGroupByMode();
       $relationSelect = "{$relationSelect}, {$contactA} as refContact ";
-      $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving $relationGroupBy";
+      $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving GROUP BY crel.{$contactA}";
 
       $allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
+      CRM_Core_DAO::reenableFullGroupByMode();
+
       while ($allRelContactDAO->fetch()) {
         $relationQuery->convertToPseudoNames($allRelContactDAO);
         $row = [];
@@ -1718,111 +1611,4 @@ WHERE  {$whereClause}";
     }
   }
 
-  /**
-   * @param $field
-   * @param $iterationDAO
-   * @param $fieldValue
-   * @param $i18n
-   * @param $metadata
-   * @param $paymentDetails
-   *
-   * @param \CRM_Export_BAO_ExportProcessor $processor
-   *
-   * @return string
-   */
-  protected static function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor) {
-
-    if ($field == 'id') {
-      return $iterationDAO->contact_id;
-      // special case for calculated field
-    }
-    elseif ($field == 'source_contact_id') {
-      return $iterationDAO->contact_id;
-    }
-    elseif ($field == 'pledge_balance_amount') {
-      return $iterationDAO->pledge_amount - $iterationDAO->pledge_total_paid;
-      // special case for calculated field
-    }
-    elseif ($field == 'pledge_next_pay_amount') {
-      return $iterationDAO->pledge_next_pay_amount + $iterationDAO->pledge_outstanding_amount;
-    }
-    elseif (isset($fieldValue) &&
-      $fieldValue != ''
-    ) {
-      //check for custom data
-      if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) {
-        return CRM_Core_BAO_CustomField::displayValue($fieldValue, $cfID);
-      }
-
-      elseif (in_array($field, array(
-        'email_greeting',
-        'postal_greeting',
-        'addressee',
-      ))) {
-        //special case for greeting replacement
-        $fldValue = "{$field}_display";
-        return $iterationDAO->$fldValue;
-      }
-      else {
-        //normal fields with a touch of CRM-3157
-        switch ($field) {
-          case 'country':
-          case 'world_region':
-            return $i18n->crm_translate($fieldValue, array('context' => 'country'));
-
-          case 'state_province':
-            return $i18n->crm_translate($fieldValue, array('context' => 'province'));
-
-          case 'gender':
-          case 'preferred_communication_method':
-          case 'preferred_mail_format':
-          case 'communication_style':
-            return $i18n->crm_translate($fieldValue);
-
-          default:
-            if (isset($metadata[$field])) {
-              // No I don't know why we do it this way & whether we could
-              // make better use of pseudoConstants.
-              if (!empty($metadata[$field]['context'])) {
-                return $i18n->crm_translate($fieldValue, $metadata[$field]);
-              }
-              if (!empty($metadata[$field]['pseudoconstant'])) {
-                // This is not our normal syntax for pseudoconstants but I am a bit loath to
-                // call an external function until sure it is not increasing php processing given this
-                // may be iterated 100,000 times & we already have the $imProvider var loaded.
-                // That can be next refactor...
-                // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
-                // but I have to reach a stable point....
-                $varName = $metadata[$field]['pseudoconstant']['var'];
-                if ($varName === 'imProviders') {
-                  return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_IM', 'provider_id', $fieldValue);
-                }
-                if ($varName === 'phoneTypes') {
-                  return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_Phone', 'phone_type_id', $fieldValue);
-                }
-              }
-
-            }
-            return $fieldValue;
-        }
-      }
-    }
-    elseif ($processor->isExportSpecifiedPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
-      $paymentTableId = $processor->getPaymentTableID();
-      $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
-      $payFieldMapper = array(
-        'componentPaymentField_total_amount' => 'total_amount',
-        'componentPaymentField_contribution_status' => 'contribution_status',
-        'componentPaymentField_payment_instrument' => 'pay_instru',
-        'componentPaymentField_transaction_id' => 'trxn_id',
-        'componentPaymentField_received_date' => 'receive_date',
-      );
-      return CRM_Utils_Array::value($payFieldMapper[$field], $paymentData, '');
-    }
-    else {
-      // if field is empty or null
-      return '';
-    }
-  }
-
 }