value to be used in the WHERE. * @param string $weightField * Field which contains the weight value,. * defaults to 'weight' * * @return bool */ public static function correctDuplicateWeights($daoName, $fieldValues = NULL, $weightField = 'weight') { $selectField = "MIN(id) AS dupeId, count(id) as dupeCount, $weightField as dupeWeight"; $groupBy = "$weightField having dupeCount>1"; $minDupeID = CRM_Utils_Weight::query('SELECT', $daoName, $fieldValues, $selectField, NULL, NULL, $groupBy); // return early if query returned empty // CRM-8043 if (!$minDupeID->fetch()) { return TRUE; } if ($minDupeID->dupeId) { $additionalWhere = "id !=" . $minDupeID->dupeId . " AND $weightField >= " . $minDupeID->dupeWeight; $update = "$weightField = $weightField + 1"; $status = CRM_Utils_Weight::query('UPDATE', $daoName, $fieldValues, $update, $additionalWhere); } if ($minDupeID->dupeId && $status) { //recursive call to correct all duplicate weight entries. return CRM_Utils_Weight::correctDuplicateWeights($daoName, $fieldValues, $weightField); } elseif (!$minDupeID->dupeId) { // case when no duplicate records are found. return TRUE; } elseif (!$status) { // case when duplicate records are found but update status is false. return FALSE; } } /** * Remove a row from the specified weight, and shift all rows below it up * * @param string $daoName * Full name of the DAO. * $param integer $weight the weight to be removed * @param int $fieldID * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $weightField * Field which contains the weight value,. * defaults to 'weight' * * @return bool */ public static function delWeight($daoName, $fieldID, $fieldValues = NULL, $weightField = 'weight') { $object = new $daoName(); $object->id = $fieldID; if (!$object->find(TRUE)) { return FALSE; } $weight = (int) $object->weight; if ($weight < 1) { return FALSE; } // fill the gap $additionalWhere = "$weightField > $weight"; $update = "$weightField = $weightField - 1"; $status = CRM_Utils_Weight::query('UPDATE', $daoName, $fieldValues, $update, $additionalWhere); return $status; } /** * Updates the weight fields of other rows according to the new and old weight passed in. * And returns the new weight be used. If old-weight not present, Creates a gap for a new row to be inserted * at the specified new weight * * @param string $daoName * Full name of the DAO. * @param int $oldWeight * @param int $newWeight * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $weightField * Field which contains the weight value,. * defaults to 'weight' * * @return int */ public static function updateOtherWeights($daoName, $oldWeight, $newWeight, $fieldValues = NULL, $weightField = 'weight') { $oldWeight = (int ) $oldWeight; $newWeight = (int ) $newWeight; // max weight is the highest current weight $maxWeight = CRM_Utils_Weight::getMax($daoName, $fieldValues, $weightField); if (!$maxWeight) { $maxWeight = 1; } if ($newWeight > $maxWeight) { //calculate new weight, CRM-4133 $calNewWeight = CRM_Utils_Weight::getNewWeight($daoName, $fieldValues, $weightField); //no need to update weight for other fields. if ($calNewWeight > $maxWeight) { return $calNewWeight; } $newWeight = $maxWeight; if (!$oldWeight) { return $newWeight + 1; } } elseif ($newWeight < 1) { $newWeight = 1; } // if they're the same, nothing to do if ($oldWeight == $newWeight) { return $newWeight; } // if oldWeight not present, indicates new weight is to be added. So create a gap for a new row to be inserted. if (!$oldWeight) { $additionalWhere = "$weightField >= $newWeight"; $update = "$weightField = ($weightField + 1)"; CRM_Utils_Weight::query('UPDATE', $daoName, $fieldValues, $update, $additionalWhere); return $newWeight; } else { if ($newWeight > $oldWeight) { $additionalWhere = "$weightField > $oldWeight AND $weightField <= $newWeight"; $update = "$weightField = ($weightField - 1)"; } elseif ($newWeight < $oldWeight) { $additionalWhere = "$weightField >= $newWeight AND $weightField < $oldWeight"; $update = "$weightField = ($weightField + 1)"; } CRM_Utils_Weight::query('UPDATE', $daoName, $fieldValues, $update, $additionalWhere); return $newWeight; } } /** * Returns the new calculated weight. * * @param string $daoName * Full name of the DAO. * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $weightField * Field which used to get the wt, default to 'weight'. * * @return int */ public static function getNewWeight($daoName, $fieldValues = NULL, $weightField = 'weight') { $selectField = "id AS fieldID, $weightField AS weight"; $field = CRM_Utils_Weight::query('SELECT', $daoName, $fieldValues, $selectField); $sameWeightCount = 0; $weights = array(); while ($field->fetch()) { if (in_array($field->weight, $weights)) { $sameWeightCount++; } $weights[$field->fieldID] = $field->weight; } $newWeight = 1; if ($sameWeightCount) { $newWeight = max($weights) + 1; //check for max wt should not greater than cal max wt. $calMaxWt = min($weights) + count($weights) - 1; if ($newWeight > $calMaxWt) { $newWeight = $calMaxWt; } } elseif (!empty($weights)) { $newWeight = max($weights); } return $newWeight; } /** * Returns the highest weight. * * @param string $daoName * Full name of the DAO. * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $weightField * Field which contains the weight value,. * defaults to 'weight' * * @return int */ public static function getMax($daoName, $fieldValues = NULL, $weightField = 'weight') { $selectField = "MAX(ROUND($weightField)) AS max_weight"; $weightDAO = CRM_Utils_Weight::query('SELECT', $daoName, $fieldValues, $selectField); $weightDAO->fetch(); if ($weightDAO->max_weight) { return $weightDAO->max_weight; } return 0; } /** * Returns the default weight ( highest weight + 1 ) to be used. * * @param string $daoName * Full name of the DAO. * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $weightField * Field which contains the weight value,. * defaults to 'weight' * * @return int */ public static function getDefaultWeight($daoName, $fieldValues = NULL, $weightField = 'weight') { $maxWeight = CRM_Utils_Weight::getMax($daoName, $fieldValues, $weightField); return $maxWeight + 1; } /** * Execute a weight-related query * * @param string $queryType * SELECT, UPDATE, DELETE. * @param string $daoName * Full name of the DAO. * @param array $fieldValues * Field => value to be used in the WHERE. * @param string $queryData * Data to be used, dependent on the query type. * @param null $additionalWhere * @param string $orderBy * Optional ORDER BY field. * * @param null $groupBy * * @return CRM_Core_DAO * objet that holds the results of the query */ public static function &query( $queryType, $daoName, $fieldValues = NULL, $queryData, $additionalWhere = NULL, $orderBy = NULL, $groupBy = NULL ) { require_once str_replace('_', DIRECTORY_SEPARATOR, $daoName) . ".php"; $dao = new $daoName(); $table = $dao->getTablename(); $fields = &$dao->fields(); $fieldlist = array_keys($fields); $whereConditions = array(); if ($additionalWhere) { $whereConditions[] = $additionalWhere; } $params = array(); $fieldNum = 0; if (is_array($fieldValues)) { foreach ($fieldValues as $fieldName => $value) { if (!in_array($fieldName, $fieldlist)) { // invalid field specified. abort. return FALSE; } $fieldNum++; $whereConditions[] = "$fieldName = %$fieldNum"; $fieldType = $fields[$fieldName]['type']; $params[$fieldNum] = array($value, CRM_Utils_Type::typeToString($fieldType)); } } $where = implode(' AND ', $whereConditions); switch ($queryType) { case 'SELECT': $query = "SELECT $queryData FROM $table"; if ($where) { $query .= " WHERE $where"; } if ($groupBy) { $query .= " GROUP BY $groupBy"; } if ($orderBy) { $query .= " ORDER BY $orderBy"; } break; case 'UPDATE': $query = "UPDATE $table SET $queryData"; if ($where) { $query .= " WHERE $where"; } break; case 'DELETE': $query = "DELETE FROM $table WHERE $where AND $queryData"; break; default: return FALSE; } $resultDAO = CRM_Core_DAO::executeQuery($query, $params); return $resultDAO; } /** * @param $rows * @param string $daoName * @param string $idName * @param $returnURL * @param null $filter */ public static function addOrder(&$rows, $daoName, $idName, $returnURL, $filter = NULL) { if (empty($rows)) { return; } $ids = array_keys($rows); $numIDs = count($ids); array_unshift($ids, 0); $ids[] = 0; $firstID = $ids[1]; $lastID = $ids[$numIDs]; if ($firstID == $lastID) { $rows[$firstID]['order'] = NULL; return; } $config = CRM_Core_Config::singleton(); $imageURL = $config->userFrameworkResourceURL . 'i/arrow'; $queryParams = array( 'reset' => 1, 'dao' => $daoName, 'idName' => $idName, 'url' => $returnURL, 'filter' => $filter, ); $signer = new CRM_Utils_Signer(CRM_Core_Key::privateKey(), self::$SIGNABLE_FIELDS); $queryParams['_sgn'] = $signer->sign($queryParams); $baseURL = CRM_Utils_System::url('civicrm/admin/weight', $queryParams); for ($i = 1; $i <= $numIDs; $i++) { $id = $ids[$i]; $prevID = $ids[$i - 1]; $nextID = $ids[$i + 1]; $links = array(); $url = "{$baseURL}&src=$id"; if ($prevID != 0) { $alt = ts('Move to top'); $links[] = "\"$alt\""; $alt = ts('Move up one row'); $links[] = "\"$alt\""; } else { $links[] = ""; $links[] = ""; } if ($nextID != 0) { $alt = ts('Move down one row'); $links[] = "\"$alt\""; $alt = ts('Move to bottom'); $links[] = "\"$alt\""; } else { $links[] = ""; $links[] = ""; } $rows[$id]['weight'] = implode(' ', $links); } } public static function fixOrder() { $signature = CRM_Utils_Request::retrieve('_sgn', 'String', CRM_Core_DAO::$_nullObject); $signer = new CRM_Utils_Signer(CRM_Core_Key::privateKey(), self::$SIGNABLE_FIELDS); // Validate $_GET values b/c subsequent code reads $_GET (via CRM_Utils_Request::retrieve) if (!$signer->validate($signature, $_GET)) { CRM_Core_Error::fatal('Request signature is invalid'); } // Note: Ensure this list matches self::$SIGNABLE_FIELDS $daoName = CRM_Utils_Request::retrieve('dao', 'String', CRM_Core_DAO::$_nullObject); $id = CRM_Utils_Request::retrieve('id', 'Integer', CRM_Core_DAO::$_nullObject); $idName = CRM_Utils_Request::retrieve('idName', 'String', CRM_Core_DAO::$_nullObject); $url = CRM_Utils_Request::retrieve('url', 'String', CRM_Core_DAO::$_nullObject); $filter = CRM_Utils_Request::retrieve('filter', 'String', CRM_Core_DAO::$_nullObject); $src = CRM_Utils_Request::retrieve('src', 'Integer', CRM_Core_DAO::$_nullObject); $dst = CRM_Utils_Request::retrieve('dst', 'Integer', CRM_Core_DAO::$_nullObject); $dir = CRM_Utils_Request::retrieve('dir', 'String', CRM_Core_DAO::$_nullObject); $object = new $daoName(); $srcWeight = CRM_Core_DAO::getFieldValue($daoName, $src, 'weight', $idName); $dstWeight = CRM_Core_DAO::getFieldValue($daoName, $dst, 'weight', $idName); if ($srcWeight == $dstWeight) { self::fixOrderOutput($url); } $tableName = $object->tableName(); $query = "UPDATE $tableName SET weight = %1 WHERE $idName = %2"; $params = array( 1 => array($dstWeight, 'Integer'), 2 => array($src, 'Integer'), ); CRM_Core_DAO::executeQuery($query, $params); if ($dir == 'swap') { $params = array( 1 => array($srcWeight, 'Integer'), 2 => array($dst, 'Integer'), ); CRM_Core_DAO::executeQuery($query, $params); } elseif ($dir == 'first') { // increment the rest by one $query = "UPDATE $tableName SET weight = weight + 1 WHERE $idName != %1 AND weight < %2"; if ($filter) { $query .= " AND $filter"; } $params = array( 1 => array($src, 'Integer'), 2 => array($srcWeight, 'Integer'), ); CRM_Core_DAO::executeQuery($query, $params); } elseif ($dir == 'last') { // increment the rest by one $query = "UPDATE $tableName SET weight = weight - 1 WHERE $idName != %1 AND weight > %2"; if ($filter) { $query .= " AND $filter"; } $params = array( 1 => array($src, 'Integer'), 2 => array($srcWeight, 'Integer'), ); CRM_Core_DAO::executeQuery($query, $params); } self::fixOrderOutput($url); } /** * @param $url */ public static function fixOrderOutput($url) { if (empty($_GET['snippet']) || $_GET['snippet'] !== 'json') { CRM_Utils_System::redirect($url); } CRM_Core_Page_AJAX::returnJsonResponse(array( 'userContext' => $url, )); } }