X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=CRM%2FLogging%2FReportDetail.php;h=e026f3d4adb03b611967cafd4626487983ff1a47;hb=2b4ed181a658c1959ff66f5c9cd16b4475638121;hp=fdbd92216a895882e7e64861f067e6119585fb40;hpb=67f82bf8bd97e3dc88351b45a472e5eb8a356874;p=civicrm-core.git diff --git a/CRM/Logging/ReportDetail.php b/CRM/Logging/ReportDetail.php index fdbd92216a..e026f3d4ad 100644 --- a/CRM/Logging/ReportDetail.php +++ b/CRM/Logging/ReportDetail.php @@ -15,6 +15,8 @@ * @copyright CiviCRM LLC https://civicrm.org/licensing */ class CRM_Logging_ReportDetail extends CRM_Report_Form { + + const ROW_COUNT_LIMIT = 50; protected $cid; /** @@ -101,9 +103,9 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { } $this->_columnHeaders = [ - 'field' => ['title' => ts('Field')], - 'from' => ['title' => ts('Changed From')], - 'to' => ['title' => ts('Changed To')], + 'field' => ['title' => ts('Field'), 'type' => CRM_Utils_Type::T_STRING], + 'from' => ['title' => ts('Changed From'), 'type' => CRM_Utils_Type::T_STRING], + 'to' => ['title' => ts('Changed To'), 'type' => CRM_Utils_Type::T_STRING], ]; } @@ -172,6 +174,7 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { // populate $rows with only the differences between $changed and $original (skipping certain columns and NULL ↔ empty changes unless raw requested) $skipped = ['id']; + $nRows = $rows = []; foreach ($this->diffs as $diff) { $table = $diff['table']; if (empty($metadata[$table])) { @@ -212,12 +215,25 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { $to = implode(', ', array_filter($tos)); } + $tableDAOClass = CRM_Core_DAO_AllCoreTables::getClassForTable($table); + if (!empty($tableDAOClass)) { + $tableDAOFields = (new $tableDAOClass())->fields(); + // If this field is a foreign key, then we can later use the foreign + // class to translate the id into something more useful for display. + $fkClassName = $tableDAOFields[$field]['FKClassName'] ?? NULL; + } if (isset($values[$field][$from])) { $from = $values[$field][$from]; } + elseif (!empty($from) && !empty($fkClassName)) { + $from = $this->convertForeignKeyValuesToLabels($fkClassName, $field, $from); + } if (isset($values[$field][$to])) { $to = $values[$field][$to]; } + elseif (!empty($to) && !empty($fkClassName)) { + $to = $this->convertForeignKeyValuesToLabels($fkClassName, $field, $to); + } if (isset($titles[$field])) { $field = $titles[$field]; } @@ -228,10 +244,31 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { $to = ''; } } - - $rows[] = ['field' => $field . " (id: {$diff['id']})", 'from' => $from, 'to' => $to]; + // Rework the results to provide grouping based on the ID + // We don't need that field displayed so we will output empty + if ($field == 'Modified Date') { + $nRows[$diff['id']][] = ['field' => '', 'from' => $from, 'to' => $to]; + } + else { + $nRows[$diff['id']][] = ['field' => $field . " (id: {$diff['id']})", 'from' => $from, 'to' => $to]; + } } + // Transform the output so that we can compact the changes into the proper amount of rows IF trData is holding more than 1 array + foreach ($nRows as $trData) { + if (count($trData) > 1) { + $keys = array_intersect(...array_map('array_keys', $trData)); + $mergedRes = array_combine($keys, array_map(function ($key) use ($trData) { + // If more than 1 entry is found, we are assigning them as subarrays, then the tpls will be responsible for concatenating the results + return array_column($trData, $key); + }, $keys)); + $rows[] = $mergedRes; + } + else { + // We always need the first row of that array + $rows[] = $trData[0]; + } + } return $rows; } @@ -251,6 +288,7 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { } $this->assign('revertURL', CRM_Report_Utils_Report::getNextUrl($this->detail, "$q&revert=1", FALSE, TRUE)); $this->assign('revertConfirm', ts('Are you sure you want to revert all changes?')); + $this->assign('sections', []); } /** @@ -266,6 +304,9 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { * Calculate all the contact related diffs for the change. */ protected function calculateContactDiffs() { + $this->_rowsFound = $this->getCountOfAllContactChangesForConnection(); + // Apply some limits before asking for all contact changes + $this->getLimit(); $this->diffs = $this->getAllContactChangesForConnection(); } @@ -280,10 +321,28 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { } $this->setDiffer(); try { - return $this->differ->getAllChangesForConnection($this->tables); + return $this->differ->getAllChangesForConnection($this->tables, $this->dblimit, $this->dboffset); } catch (CRM_Core_Exception $e) { - CRM_Core_Error::statusBounce(ts($e->getMessage())); + CRM_Core_Error::statusBounce($e->getMessage()); + } + } + + /** + * Get an count of contacts with changes. + * + * @return mixed + */ + public function getCountOfAllContactChangesForConnection() { + if (empty($this->log_conn_id)) { + return []; + } + $this->setDiffer(); + try { + return $this->differ->getCountOfAllContactChangesForConnection($this->tables); + } + catch (CRM_Core_Exception $e) { + CRM_Core_Error::statusBounce($e->getMessage()); } } @@ -347,6 +406,83 @@ class CRM_Logging_ReportDetail extends CRM_Report_Form { $this->altered_name = CRM_Utils_Request::retrieve('alteredName', 'String'); $this->altered_by = CRM_Utils_Request::retrieve('alteredBy', 'String'); $this->altered_by_id = CRM_Utils_Request::retrieve('alteredById', 'Integer'); + $this->layout = CRM_Utils_Request::retrieve('layout', 'String'); + } + + /** + * Override to set limit + * @param int $rowCount + */ + public function limit($rowCount = self::ROW_COUNT_LIMIT) { + parent::limit($rowCount); + } + + /** + * Override to set pager with limit + * @param int $rowCount + */ + public function setPager($rowCount = self::ROW_COUNT_LIMIT) { + // We should not be rendering the pager in overlay mode + if (!isset($this->layout)) { + $this->_dashBoardRowCount = $rowCount; + $this->_limit = TRUE; + parent::setPager($rowCount); + } + } + + /** + * This is a function similar to limit, in fact we copied it as-is and removed + * some `set` statements + * + */ + public function getLimit($rowCount = self::ROW_COUNT_LIMIT) { + if ($this->addPaging) { + + $pageId = CRM_Utils_Request::retrieve('crmPID', 'Integer'); + + // @todo all http vars should be extracted in the preProcess + // - not randomly in the class + if (!$pageId && !empty($_POST)) { + if (isset($_POST['PagerBottomButton']) && isset($_POST['crmPID_B'])) { + $pageId = max((int) $_POST['crmPID_B'], 1); + } + elseif (isset($_POST['PagerTopButton']) && isset($_POST['crmPID'])) { + $pageId = max((int) $_POST['crmPID'], 1); + } + unset($_POST['crmPID_B'], $_POST['crmPID']); + } + + $pageId = $pageId ? $pageId : 1; + $offset = ($pageId - 1) * $rowCount; + + $offset = CRM_Utils_Type::escape($offset, 'Int'); + $rowCount = CRM_Utils_Type::escape($rowCount, 'Int'); + $this->_limit = " LIMIT $offset, $rowCount"; + $this->dblimit = $rowCount; + $this->dboffset = $offset; + } + } + + /** + * Given a key value that we know is a foreign key to another table, return + * what the DAO thinks is the "label" for the foreign entity. For example + * if it's referencing a contact then return the contact name, or if it's an + * activity then return the activity subject. + * If it's the type of DAO that doesn't have such a thing, just echo back + * what we were given. + * + * @param string $fkClassName + * @param string $field + * @param int $keyval + * @return string + */ + private function convertForeignKeyValuesToLabels(string $fkClassName, string $field, int $keyval): string { + if ($fkClassName::$_labelField) { + $labelValue = CRM_Core_DAO::getFieldValue($fkClassName, $keyval, $fkClassName::$_labelField); + // Not sure if this should use ts - there's not a lot of context (`%1 (id: %2)`) - and also the similar field labels above don't use ts. + return "{$labelValue} (id: {$keyval})"; + } + return (string) $keyval; } }