public static function exportComponents($selectAll, $ids, $params, $order = NULL, $fields = NULL, $moreReturnProperties = NULL, $exportMode = CRM_Export_Form_Select_Relationship::RELATIONSHIP_EXPORT, $componentClause = NULL, $componentTable = NULL, $mergeSameAddress = FALSE, $mergeSameHousehold = FALSE, $exportParams = array(), $queryOperator = 'AND') { $headerRows = $returnProperties = array(); $queryMode = CRM_Relationship_BAO_Query::MODE_RELATIONSHIPS; //Welke velden exporteren, gezet bij een mapping, indien niet gezet, primary fields. if ($fields) { foreach ($fields as $key => $value) { $fieldName = CRM_Utils_Array::value(0, $value); if (!$fieldName) { continue; } $returnProperties[$fieldName] = 1; } } else { // Copied from CRM_Relationship_BAO_QUERY should be refactored to seperate // method. $fields = CRM_Contact_BAO_Relationship::fields(); // Add display_name for both contacts $contact_fields = CRM_Contact_BAO_Contact::exportableFields('All', FALSE, TRUE, TRUE); $fields['contact_a'] = $contact_fields['display_name']; $fields['contact_a']['where'] = 'contact_a.display_name'; $fields['contact_b'] = $contact_fields['display_name']; $fields['contact_b']['where'] = 'contact_b.display_name'; // Add relationship type field $relationship_type_fields = CRM_Contact_BAO_RelationshipType::fields(); $fields['relationship_type'] = $relationship_type_fields['label_a_b']; $fields['relationship_type']['where'] = 'relationship_type.label_a_b'; // Add custom fields $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Relationship')); $returnProperties = CRM_Relationship_BAO_Query::defaultReturnProperties(); } if ($moreReturnProperties) { $returnProperties = array_merge($returnProperties, $moreReturnProperties); } $query = new CRM_Relationship_BAO_Query($params, $returnProperties, NULL, FALSE, FALSE, FALSE, TRUE, $queryOperator); //sort by state //CRM-15301 $query->_sort = $order; list($select, $from, $where, $having) = $query->query(); $allRelContactArray = $relationQuery = array(); if (!$selectAll && $componentTable) { // TODO For not select all //$from .= " INNER JOIN $componentTable ctTable ON ctTable.contact_id = contact_a.id "; } elseif ($componentClause) { if (empty($where)) { $where = "WHERE {$componentClause}"; } else { $where .= " AND {$componentClause}"; } } $queryString = "{$select} {$from} {$where} {$having}"; $groupBy = ""; if ($queryMode & CRM_Relationship_BAO_Query::MODE_RELATIONSHIPS && $query->_useGroupBy) { $groupBy = " GROUP BY relationship.id"; } $queryString .= $groupBy; // always add relationship.id to the ORDER clause // so the order is deterministic if (strpos('relationship.id', $order) === FALSE) { $order .= ", relationship.id"; } if ($order) { list($field, $dir) = explode(' ', $order, 2); $field = trim($field); if (!empty($returnProperties[$field])) { //CRM-15301 $queryString .= " ORDER BY {$order}"; } } $componentDetails = $headerRows = $sqlColumns = array(); $setHeader = TRUE; $rowCount = self::EXPORT_ROW_COUNT; $offset = 0; // we write to temp table often to avoid using too much memory $tempRowCount = 100; $count = -1; // 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; } while (1) { $limitQuery = "{$queryString} LIMIT {$offset}, {$rowCount}"; $dao = CRM_Core_DAO::executeQuery($limitQuery); if ($dao->N <= 0) { break; } while ($dao->fetch()) { $count++; $row = array(); //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; //first loop through output columns so that we return what is required, and in same order. foreach ($outputColumns as $field => $value) { //we should set header only once if ($setHeader) { $sqlDone = FALSE; $headerRows[] = $query->_fields[$field]['title']; if (!$sqlDone) { self::sqlColumnDefn($query, $sqlColumns, $field); } } //build row values (data) $fieldValue = NULL; if (property_exists($iterationDAO, $field)) { $fieldValue = $iterationDAO->{$field}; } if ($field == 'id') { $row[$field] = $iterationDAO->relationship_id; } elseif (isset($fieldValue) && $fieldValue != '') { //check for custom data if ($cfID = CRM_Core_BAO_CustomField::getKeyID($field)) { $row[$field] = CRM_Core_BAO_CustomField::getDisplayValue($fieldValue, $cfID, $query->_options); } else { //normal fields with a touch of CRM-3157 $row[$field] = $fieldValue; } } else { // if field is empty or null $row[$field] = ''; } } if ($setHeader) { $exportTempTable = self::createTempTable($sqlColumns); } //build header only once $setHeader = FALSE; // add component info // write the row to a file $componentDetails[] = $row; // output every $tempRowCount rows if ($count % $tempRowCount == 0) { self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns); $componentDetails = array(); } } $dao->free(); $offset += $rowCount; } if ($exportTempTable) { self::writeDetailsToTable($exportTempTable, $componentDetails, $sqlColumns); // do merge same address and merge same household processing if ($mergeSameAddress) { self::mergeSameAddress($exportTempTable, $headerRows, $sqlColumns, $exportParams); } // merge the records if they have corresponding households if ($mergeSameHousehold) { self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, $relationKeyMOH); self::mergeSameHousehold($exportTempTable, $headerRows, $sqlColumns, $relationKeyHOH); } // call export hook CRM_Utils_Hook::export($exportTempTable, $headerRows, $sqlColumns, $exportMode); // now write the CSV file self::writeCSVFromTable($exportTempTable, $headerRows, $sqlColumns, $exportMode); // delete the export temp table and component table $sql = "DROP TABLE IF EXISTS {$exportTempTable}"; CRM_Core_DAO::executeQuery($sql); CRM_Utils_System::civiExit(); } else { CRM_Core_Error::fatal(ts('No records to export')); } }
/** * Class constructor which also does all the work. * * @param array $params * @param array $returnProperties * @param array $fields * @param bool $includeRelationshipIds * @param bool $strict * * @param bool $skipPermission * @param string $operator * * @return \CRM_Relationship_BAO_Query */ public function __construct($params = NULL, $returnProperties = NULL, $fields = NULL, $includeRelationshipIds = FALSE, $strict = FALSE, $mode = 1, $skipPermission = FALSE, $operator = 'AND') { $this->_params =& $params; if ($this->_params == NULL) { $this->_params = array(); } if (empty($returnProperties)) { $this->_returnProperties = self::defaultReturnProperties($mode); } else { $this->_returnProperties =& $returnProperties; } $this->_includeRelationshipIds = $includeRelationshipIds; $this->_strict = $strict; $this->_mode = $mode; $this->_skipPermission = $skipPermission; //$this->setOperator($operator); if ($fields) { $this->_fields =& $fields; $this->_search = FALSE; $this->_skipPermission = TRUE; } else { $this->_fields = CRM_Contact_BAO_Relationship::fields(); foreach ($this->_fields as $defaultFieldKey => $defaultField) { $this->_fields[$defaultFieldKey]['where'] = 'relationship.' . $defaultFieldKey; } // Add display_name for both contacts $contact_fields = CRM_Contact_BAO_Contact::exportableFields('All', FALSE, TRUE, TRUE); $this->_fields['contact_a'] = $contact_fields['display_name']; $this->_fields['contact_a']['where'] = 'contact_a.display_name'; $this->_fields['contact_b'] = $contact_fields['display_name']; $this->_fields['contact_b']['where'] = 'contact_b.display_name'; // Add relationship type field $relationship_type_fields = CRM_Contact_BAO_RelationshipType::fields(); $this->_fields['relationship_type'] = $relationship_type_fields['label_a_b']; $this->_fields['relationship_type']['where'] = 'relationship_type.label_a_b'; // Add custom fields $this->_fields = array_merge($this->_fields, CRM_Core_BAO_CustomField::getFieldsForImport('Relationship')); } // basically do all the work once, and then reuse it $this->initialize(); }
/** * Build the mapping form. * * @param CRM_Core_Form $form * @param string $mappingType * (Export/Import/Search Builder). * @param int $mappingId * @param int $columnNo * @param int $blockCount * (no of blocks shown). * @param NULL $exportMode * * @return void */ public static function buildMappingForm(&$form, $mappingType = 'Export', $mappingId = NULL, $columnNo, $blockCount = 3, $exportMode = NULL) { $name = "Map"; $columnCount = array('1' => $columnNo); $form->applyFilter('saveMappingName', 'trim'); //to save the current mappings if (!isset($mappingId)) { $saveDetailsName = ts('Save this field mapping'); $form->add('text', 'saveMappingName', ts('Name')); $form->add('text', 'saveMappingDesc', ts('Description')); } else { $form->assign('loadedMapping', $mappingId); $params = array('id' => $mappingId); $temp = array(); $mappingDetails = CRM_Core_BAO_Mapping::retrieve($params, $temp); $form->assign('savedName', $mappingDetails->name); $form->add('hidden', 'mappingId', $mappingId); $form->addElement('checkbox', 'updateMapping', ts('Update this field mapping'), NULL); $saveDetailsName = ts('Save as a new field mapping'); $form->add('text', 'saveMappingName', ts('Name')); $form->add('text', 'saveMappingDesc', ts('Description')); } $form->addElement('checkbox', 'saveMapping', $saveDetailsName, NULL, array('onclick' => "showSaveDetails(this)")); $form->addFormRule(array('CRM_Export_Form_Map', 'formRule'), $form->get('mappingTypeId')); $defaults = array(); $hasLocationTypes = array(); $hasRelationTypes = array(); $fields = array(); if ($mappingType == 'Export') { $required = TRUE; } $fields = CRM_Contact_BAO_Relationship::fields(); // add custom fields $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Relationship')); ksort($fields); // add component fields $compArray = array(); foreach ($fields as $key => $value) { //CRM-2676, replacing the conflict for same custom field name from different custom group. $customGroupName = self::getCustomGroupName($key); if ($customGroupName) { $relatedMapperFields[$key] = $mapperFields[$key] = $customGroupName . ': ' . $value['title']; } else { $relatedMapperFields[$key] = $mapperFields[$key] = $value['title']; } } $mapperKeys = array_keys($mapperFields); $sel1 = array('' => ts('- select field -')) + $mapperFields; if (isset($mappingId)) { $colCnt = 0; list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingImProvider, $mappingRelation, $mappingOperator, $mappingValue) = CRM_Core_BAO_Mapping::getMappingFields($mappingId); $blkCnt = count($mappingName); if ($blkCnt >= $blockCount) { $blockCount = $blkCnt + 1; } for ($x = 1; $x < $blockCount; $x++) { if (isset($mappingName[$x])) { $colCnt = count($mappingName[$x]); if ($colCnt >= $columnCount[$x]) { $columnCount[$x] = $colCnt; } } } } $form->_blockCount = $blockCount; $form->_columnCount = $columnCount; $form->set('blockCount', $form->_blockCount); $form->set('columnCount', $form->_columnCount); $defaults = $noneArray = $nullArray = array(); //used to warn for mismatch column count or mismatch mapping $warning = 0; for ($x = 1; $x < $blockCount; $x++) { for ($i = 0; $i < $columnCount[$x]; $i++) { $sel =& $form->addElement('hierselect', "mapper[{$x}][{$i}]", ts('Mapper for Field %1', array(1 => $i)), NULL); $jsSet = FALSE; if (isset($mappingId)) { //TODO opgeslagen mappings } //Fix for Export $j = 7; $formValues = $form->exportValues(); if (!$jsSet) { if (empty($formValues)) { // Incremented length for third select box(relationship type) for ($k = 1; $k < $j; $k++) { $noneArray[] = array($x, $i, $k); } } else { if (!empty($formValues['mapper'][$x])) { foreach ($formValues['mapper'][$x] as $value) { for ($k = 1; $k < $j; $k++) { if (!isset($formValues['mapper'][$x][$i][$k]) || !$formValues['mapper'][$x][$i][$k]) { $noneArray[] = array($x, $i, $k); } else { $nullArray[] = array($x, $i, $k); } } } } else { for ($k = 1; $k < $j; $k++) { $noneArray[] = array($x, $i, $k); } } } } //Fix for Export $sel->setOptions(array($sel1)); } $title = ts('Select more fields'); $form->addElement('submit', "addMore[{$x}]", $title, array('class' => 'submit-link')); } //end of block for $js = "<script type='text/javascript'>\n"; $formName = "document.{$name}"; if (!empty($nullArray)) { $js .= "var nullArray = ["; $elements = array(); $seen = array(); foreach ($nullArray as $element) { $key = "{$element[0]}, {$element[1]}, {$element[2]}"; if (!isset($seen[$key])) { $elements[] = "[{$key}]"; $seen[$key] = 1; } } $js .= implode(', ', $elements); $js .= "]"; $js .= "\n for (var i=0;i<nullArray.length;i++) {\n if ( {$formName}['mapper['+nullArray[i][0]+']['+nullArray[i][1]+']['+nullArray[i][2]+']'] ) {\n {$formName}['mapper['+nullArray[i][0]+']['+nullArray[i][1]+']['+nullArray[i][2]+']'].style.display = '';\n }\n }\n"; } if (!empty($noneArray)) { $js .= "var noneArray = ["; $elements = array(); $seen = array(); foreach ($noneArray as $element) { $key = "{$element[0]}, {$element[1]}, {$element[2]}"; if (!isset($seen[$key])) { $elements[] = "[{$key}]"; $seen[$key] = 1; } } $js .= implode(', ', $elements); $js .= "]"; $js .= "\n for (var i=0;i<noneArray.length;i++) {\n if ( {$formName}['mapper['+noneArray[i][0]+']['+noneArray[i][1]+']['+noneArray[i][2]+']'] ) {\n {$formName}['mapper['+noneArray[i][0]+']['+noneArray[i][1]+']['+noneArray[i][2]+']'].style.display = 'none';\n }\n }\n"; } $js .= "</script>\n"; $form->assign('initHideBoxes', $js); $form->assign('columnCount', $columnCount); $form->assign('blockCount', $blockCount); $form->setDefaults($defaults); $form->setDefaultAction('refresh'); }