/** * Return the SQL query for getting only the interesting results out of the dedupe table. * * @$checkPermission boolean $params a flag to indicate if permission should be considered. * default is to always check permissioning but public pages for example might not want * permission to be checked for anonymous users. Refer CRM-6211. We might be beaking * Multi-Site dedupe for public pages. * * @param bool $checkPermission * * @return string */ public function thresholdQuery($checkPermission = TRUE) { $this->_aclFrom = ''; // CRM-6603: anonymous dupechecks side-step ACLs $this->_aclWhere = ' AND is_deleted = 0 '; if ($this->params && !$this->noRules) { if ($checkPermission) { list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause('civicrm_contact'); $this->_aclWhere = $this->_aclWhere ? "AND {$this->_aclWhere}" : ''; } $query = "SELECT dedupe.id1 as id\n FROM dedupe JOIN civicrm_contact ON dedupe.id1 = civicrm_contact.id {$this->_aclFrom}\n WHERE contact_type = '{$this->contact_type}' {$this->_aclWhere}\n AND weight >= {$this->threshold}"; } else { $this->_aclWhere = ' AND c1.is_deleted = 0 AND c2.is_deleted = 0'; if ($checkPermission) { list($this->_aclFrom, $this->_aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause(array('c1', 'c2')); $this->_aclWhere = $this->_aclWhere ? "AND {$this->_aclWhere}" : ''; } $query = "SELECT dedupe.id1, dedupe.id2, dedupe.weight\n FROM dedupe JOIN civicrm_contact c1 ON dedupe.id1 = c1.id\n JOIN civicrm_contact c2 ON dedupe.id2 = c2.id {$this->_aclFrom}\n LEFT JOIN civicrm_dedupe_exception exc ON dedupe.id1 = exc.contact_id1 AND dedupe.id2 = exc.contact_id2\n WHERE c1.contact_type = '{$this->contact_type}' AND\n c2.contact_type = '{$this->contact_type}' {$this->_aclWhere}\n AND weight >= {$this->threshold} AND exc.contact_id1 IS NULL"; } CRM_Utils_Hook::dupeQuery($this, 'threshold', $query); return $query; }
/** * Process the form submission. * * * @return void */ public function postProcess() { $values = $this->exportValues(); //FIXME: Handle logic to replace is_default column by usage // reset used column to General (since there can only // be one 'Supervised' or 'Unsupervised' rule) if ($values['used'] != 'General') { $query = "\nUPDATE civicrm_dedupe_rule_group\n SET used = 'General'\n WHERE contact_type = %1\n AND used = %2"; $queryParams = array(1 => array($this->_contactType, 'String'), 2 => array($values['used'], 'String')); CRM_Core_DAO::executeQuery($query, $queryParams); } $rgDao = new CRM_Dedupe_DAO_RuleGroup(); if ($this->_action & CRM_Core_Action::UPDATE) { $rgDao->id = $this->_rgid; } $rgDao->title = $values['title']; $rgDao->is_reserved = CRM_Utils_Array::value('is_reserved', $values, FALSE); $rgDao->used = $values['used']; $rgDao->contact_type = $this->_contactType; $rgDao->threshold = $values['threshold']; $rgDao->save(); // make sure name is set only during insert if ($this->_action & CRM_Core_Action::ADD) { // generate name based on title $rgDao->name = CRM_Utils_String::titleToVar($values['title']) . "_{$rgDao->id}"; $rgDao->save(); } // lets skip updating of fields for reserved dedupe group if ($rgDao->is_reserved) { CRM_Core_Session::setStatus(ts("The rule '%1' has been saved.", array(1 => $rgDao->title)), ts('Saved'), 'success'); return; } $ruleDao = new CRM_Dedupe_DAO_Rule(); $ruleDao->dedupe_rule_group_id = $rgDao->id; $ruleDao->delete(); $ruleDao->free(); $substrLenghts = array(); $tables = array(); $daoObj = new CRM_Core_DAO(); $database = $daoObj->database(); for ($count = 0; $count < self::RULES_COUNT; $count++) { if (empty($values["where_{$count}"])) { continue; } list($table, $field) = explode('.', CRM_Utils_Array::value("where_{$count}", $values)); $length = !empty($values["length_{$count}"]) ? CRM_Utils_Array::value("length_{$count}", $values) : NULL; $weight = $values["weight_{$count}"]; if ($table and $field) { $ruleDao = new CRM_Dedupe_DAO_Rule(); $ruleDao->dedupe_rule_group_id = $rgDao->id; $ruleDao->rule_table = $table; $ruleDao->rule_field = $field; $ruleDao->rule_length = $length; $ruleDao->rule_weight = $weight; $ruleDao->save(); $ruleDao->free(); if (!array_key_exists($table, $tables)) { $tables[$table] = array(); } $tables[$table][] = $field; } // CRM-6245: we must pass table/field/length triples to the createIndexes() call below if ($length) { if (!isset($substrLenghts[$table])) { $substrLenghts[$table] = array(); } //CRM-13417 to avoid fatal error "Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys, 1089" $schemaQuery = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS\n WHERE TABLE_SCHEMA = '{$database}' AND\n TABLE_NAME = '{$table}' AND COLUMN_NAME = '{$field}';"; $dao = CRM_Core_DAO::executeQuery($schemaQuery); if ($dao->fetch()) { // set the length to null for all the fields where prefix length is not supported. eg. int,tinyint,date,enum etc dataTypes. if ($dao->COLUMN_NAME == $field && !in_array($dao->DATA_TYPE, array('char', 'varchar', 'binary', 'varbinary', 'text', 'blob'))) { $length = NULL; } elseif ($dao->COLUMN_NAME == $field && !empty($dao->CHARACTER_MAXIMUM_LENGTH) && $length > $dao->CHARACTER_MAXIMUM_LENGTH) { //set the length to CHARACTER_MAXIMUM_LENGTH in case the length provided by the user is greater than the limit $length = $dao->CHARACTER_MAXIMUM_LENGTH; } } $substrLenghts[$table][$field] = $length; } } // also create an index for this dedupe rule // CRM-3837 CRM_Utils_Hook::dupeQuery($ruleDao, 'dedupeIndexes', $tables); CRM_Core_BAO_SchemaHandler::createIndexes($tables, 'dedupe_index', $substrLenghts); //need to clear cache of deduped contacts //based on the previous rule $cacheKey = "merge {$this->_contactType}_{$this->_rgid}_%"; CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey); CRM_Core_Session::setStatus(ts("The rule '%1' has been saved.", array(1 => $rgDao->title)), ts('Saved'), 'success'); }