$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 : '';
}
/**
$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);
$returnProperties[$householdRelationshipType][$key] = $value;
}
}
+ // @todo - don't use returnProperties above.
+ $processor->setHouseholdMergeReturnProperties($returnProperties[$householdRelationshipType]);
}
}
}
- list($relationQuery, $allRelContactArray) = self::buildRelatedContactArray($selectAll, $ids, $processor, $componentTable, $returnProperties);
+ self::buildRelatedContactArray($selectAll, $ids, $processor, $componentTable);
// make sure the groups stuff is included only if specifically specified
// by the fields param (CRM-1969), else we limit the contacts outputted to only
$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;
$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;
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)) {
- $relDAO = CRM_Utils_Array::value($iterationDAO->contact_id, $allRelContactArray[$field]);
- $relationQuery[$field]->convertToPseudoNames($relDAO);
- self::fetchRelationshipDetails($relDAO, $value, $field, $row);
- }
- 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
}
// call export hook
- CRM_Utils_Hook::export($exportTempTable, $headerRows, $sqlColumns, $exportMode);
+ CRM_Utils_Hook::export($exportTempTable, $headerRows, $sqlColumns, $exportMode, $componentTable, $ids);
// In order to be able to write a unit test against this function we need to suppress
// the csv writing. In future hopefully the csv writing & the main processing will be in separate functions.
}
}
- /**
- * Name of the export file based on mode.
- *
- * @param string $output
- * Type of output.
- * @param int $mode
- * Export mode.
- *
- * @return string
- * name of the file
- */
- public static function getExportFileName($output = 'csv', $mode = CRM_Export_Form_Select::CONTACT_EXPORT) {
- switch ($mode) {
- case CRM_Export_Form_Select::CONTACT_EXPORT:
- return ts('CiviCRM Contact Search');
-
- case CRM_Export_Form_Select::CONTRIBUTE_EXPORT:
- return ts('CiviCRM Contribution Search');
-
- case CRM_Export_Form_Select::MEMBER_EXPORT:
- return ts('CiviCRM Member Search');
-
- case CRM_Export_Form_Select::EVENT_EXPORT:
- return ts('CiviCRM Participant Search');
-
- case CRM_Export_Form_Select::PLEDGE_EXPORT:
- return ts('CiviCRM Pledge Search');
-
- case CRM_Export_Form_Select::CASE_EXPORT:
- return ts('CiviCRM Case Search');
-
- case CRM_Export_Form_Select::GRANT_EXPORT:
- return ts('CiviCRM Grant Search');
-
- case CRM_Export_Form_Select::ACTIVITY_EXPORT:
- return ts('CiviCRM Activity Search');
- }
- }
-
/**
* Handle import error file creation.
*/
$rows[] = $row;
}
- CRM_Core_Report_Excel::writeCSVFile(self::getExportFileName(), $header, $rows);
+ CRM_Core_Report_Excel::writeCSVFile(ts('CiviCRM Contact Search'), $header, $rows);
CRM_Utils_System::civiExit();
}
*/
public static function mergeSameHousehold($exportTempTable, &$sqlColumns, $prefix) {
$prefixColumn = $prefix . '_';
- $allKeys = array_keys($sqlColumns);
$replaced = array();
// name map of the non standard fields in header rows & sql columns
$mappingFields = array(
'civicrm_primary_id' => 'id',
- 'contact_source' => 'source',
- 'current_employer_id' => 'employer_id',
- 'contact_is_deleted' => 'is_deleted',
- 'name' => 'address_name',
'provider_id' => 'im_service_provider',
'phone_type_id' => 'phone_type',
);
}
$componentDetails[] = $row;
}
- if ($exportMode == 'financial') {
- $getExportFileName = 'CiviCRM Contribution Search';
- }
- else {
- $getExportFileName = self::getExportFileName('csv', $exportMode);
- }
- CRM_Core_Report_Excel::writeCSVFile($getExportFileName,
+ CRM_Core_Report_Excel::writeCSVFile($processor->getExportFileName(),
$headerRows,
$componentDetails,
NULL,
/**
* 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;
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;
foreach ($value as $relationField => $relationValue) {
// below block is same as primary block (duplicate)
if (isset($queryFields[$relationField]['title'])) {
- if ($queryFields[$relationField]['name'] == 'name') {
- $headerName = $field . '-' . $relationField;
- }
- else {
- if ($relationField == 'current_employer') {
- $headerName = $field . '-' . 'current_employer';
- }
- else {
- $headerName = $field . '-' . $queryFields[$relationField]['name'];
- }
- }
+ $headerName = $field . '-' . $relationField;
if (!$processor->isHouseholdMergeRelationshipTypeKey($field)) {
// Do not add to header row if we are only generating for merge reasons.
$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;
$phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
$imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
$i18n = CRM_Core_I18n::singleton();
+ $field = $field . '_';
+
foreach ($value as $relationField => $relationValue) {
if (is_object($relDAO) && property_exists($relDAO, $relationField)) {
$fieldValue = $relDAO->$relationField;
else {
$fieldValue = '';
}
- $field = $field . '_';
$relPrefix = $field . $relationField;
if (is_object($relDAO) && $relationField == 'id') {
* @param $ids
* @param \CRM_Export_BAO_ExportProcessor $processor
* @param $componentTable
- * @param $returnProperties
- *
- * @return array
*/
- protected static function buildRelatedContactArray($selectAll, $ids, $processor, $componentTable, $returnProperties) {
+ protected static function buildRelatedContactArray($selectAll, $ids, $processor, $componentTable) {
$allRelContactArray = $relationQuery = array();
$queryMode = $processor->getQueryMode();
$exportMode = $processor->getExportMode();
- foreach (self::$relationshipTypes as $rel => $dnt) {
- if ($relationReturnProperties = CRM_Utils_Array::value($rel, $returnProperties)) {
- $allRelContactArray[$rel] = array();
- // build Query for each relationship
- $relationQuery[$rel] = new CRM_Contact_BAO_Query(NULL, $relationReturnProperties,
- NULL, FALSE, FALSE, $queryMode
- );
- list($relationSelect, $relationFrom, $relationWhere, $relationHaving) = $relationQuery[$rel]->query();
-
- list($id, $direction) = explode('_', $rel, 2);
- // identify the relationship direction
- $contactA = 'contact_id_a';
- $contactB = 'contact_id_b';
- if ($direction == 'b_a') {
- $contactA = 'contact_id_b';
- $contactB = 'contact_id_a';
- }
- $relIDs = self::getIDsForRelatedContact($ids, $exportMode);
- $relationshipJoin = $relationshipClause = '';
- if (!$selectAll && $componentTable) {
- $relationshipJoin = " INNER JOIN {$componentTable} ctTable ON ctTable.contact_id = {$contactA}";
- }
- elseif (!empty($relIDs)) {
- $relID = implode(',', $relIDs);
- $relationshipClause = " AND crel.{$contactA} IN ( {$relID} )";
- }
+ foreach ($processor->getRelationshipReturnProperties() as $relationshipKey => $relationReturnProperties) {
+ $allRelContactArray[$relationshipKey] = array();
+ // build Query for each relationship
+ $relationQuery = new CRM_Contact_BAO_Query(NULL, $relationReturnProperties,
+ NULL, FALSE, FALSE, $queryMode
+ );
+ list($relationSelect, $relationFrom, $relationWhere, $relationHaving) = $relationQuery->query();
+
+ list($id, $direction) = explode('_', $relationshipKey, 2);
+ // identify the relationship direction
+ $contactA = 'contact_id_a';
+ $contactB = 'contact_id_b';
+ if ($direction == 'b_a') {
+ $contactA = 'contact_id_b';
+ $contactB = 'contact_id_a';
+ }
+ $relIDs = self::getIDsForRelatedContact($ids, $exportMode);
- $relationFrom = " {$relationFrom}
- INNER JOIN civicrm_relationship crel ON crel.{$contactB} = contact_a.id AND crel.relationship_type_id = {$id}
- {$relationshipJoin} ";
-
- //check for active relationship status only
- $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[$rel]->_select, "crel.{$contactA}");
- $relationSelect = "{$relationSelect}, {$contactA} as refContact ";
- $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving $relationGroupBy";
-
- $allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
- while ($allRelContactDAO->fetch()) {
- //FIX Me: Migrate this to table rather than array
- // build the array of all related contacts
- $allRelContactArray[$rel][$allRelContactDAO->refContact] = clone($allRelContactDAO);
- }
- $allRelContactDAO->free();
+ $relationshipJoin = $relationshipClause = '';
+ if (!$selectAll && $componentTable) {
+ $relationshipJoin = " INNER JOIN {$componentTable} ctTable ON ctTable.contact_id = {$contactA}";
+ }
+ elseif (!empty($relIDs)) {
+ $relID = implode(',', $relIDs);
+ $relationshipClause = " AND crel.{$contactA} IN ( {$relID} )";
}
- }
- return array($relationQuery, $allRelContactArray);
- }
- /**
- * @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) {
+ $relationFrom = " {$relationFrom}
+ INNER JOIN civicrm_relationship crel ON crel.{$contactB} = contact_a.id AND crel.relationship_type_id = {$id}
+ {$relationshipJoin} ";
- 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);
- }
+ //check for active relationship status only
+ $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}";
+ CRM_Core_DAO::disableFullGroupByMode();
+ $relationSelect = "{$relationSelect}, {$contactA} as refContact ";
+ $relationQueryString = "$relationSelect $relationFrom $relationWhere $relationHaving GROUP BY crel.{$contactA}";
- 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);
- }
- }
+ $allRelContactDAO = CRM_Core_DAO::executeQuery($relationQueryString);
+ CRM_Core_DAO::reenableFullGroupByMode();
+ while ($allRelContactDAO->fetch()) {
+ $relationQuery->convertToPseudoNames($allRelContactDAO);
+ $row = [];
+ // @todo pass processor to fetchRelationshipDetails and set fields directly within it.
+ self::fetchRelationshipDetails($allRelContactDAO, $relationReturnProperties, $relationshipKey, $row);
+ foreach (array_keys($relationReturnProperties) as $property) {
+ if ($property === 'location') {
+ // @todo - simplify location in self::fetchRelationshipDetails - remove handling here. Or just call
+ // $processor->setRelationshipValue from fetchRelationshipDetails
+ foreach ($relationReturnProperties['location'] as $locationName => $locationValues) {
+ foreach (array_keys($locationValues) as $locationValue) {
+ $key = str_replace(' ', '_', $locationName) . '-' . $locationValue;
+ $processor->setRelationshipValue($relationshipKey, $allRelContactDAO->refContact, $key, $row[$relationshipKey . '__' . $key]);
+ }
}
- return $fieldValue;
+ }
+ else {
+ $processor->setRelationshipValue($relationshipKey, $allRelContactDAO->refContact, $property, $row[$relationshipKey . '_' . $property]);
+ }
}
}
}
- 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 '';
- }
}
}