366 lines
11 KiB
PHP
366 lines
11 KiB
PHP
<?php
|
||
/*
|
||
+--------------------------------------------------------------------+
|
||
| CiviCRM version 4.7 |
|
||
+--------------------------------------------------------------------+
|
||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||
+--------------------------------------------------------------------+
|
||
| This file is a part of CiviCRM. |
|
||
| |
|
||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||
| under the terms of the GNU Affero General Public License |
|
||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||
| |
|
||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||
| See the GNU Affero General Public License for more details. |
|
||
| |
|
||
| You should have received a copy of the GNU Affero General Public |
|
||
| License and the CiviCRM Licensing Exception along |
|
||
| with this program; if not, contact CiviCRM LLC |
|
||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||
+--------------------------------------------------------------------+
|
||
*/
|
||
|
||
/**
|
||
*
|
||
* @package CRM
|
||
* @copyright CiviCRM LLC (c) 2004-2017
|
||
*/
|
||
class CRM_Logging_ReportDetail extends CRM_Report_Form {
|
||
protected $cid;
|
||
|
||
/**
|
||
* Other contact ID.
|
||
*
|
||
* This would be set if we are viewing a merge of 2 contacts.
|
||
*
|
||
* @var int
|
||
*/
|
||
protected $oid;
|
||
protected $db;
|
||
protected $log_conn_id;
|
||
protected $log_date;
|
||
protected $raw;
|
||
protected $tables = array();
|
||
protected $interval = '10 SECOND';
|
||
|
||
protected $altered_name;
|
||
protected $altered_by;
|
||
protected $altered_by_id;
|
||
|
||
// detail/summary report ids
|
||
protected $detail;
|
||
protected $summary;
|
||
|
||
/**
|
||
* Instance of Differ.
|
||
*
|
||
* @var CRM_Logging_Differ
|
||
*/
|
||
protected $differ;
|
||
|
||
/**
|
||
* Array of changes made.
|
||
*
|
||
* @var array
|
||
*/
|
||
protected $diffs = array();
|
||
|
||
/**
|
||
* Don't display the Add these contacts to Group button.
|
||
*
|
||
* @var bool
|
||
*/
|
||
protected $_add2groupSupported = FALSE;
|
||
|
||
/**
|
||
* Class constructor.
|
||
*/
|
||
public function __construct() {
|
||
|
||
$this->storeDB();
|
||
|
||
$this->parsePropertiesFromUrl();
|
||
|
||
parent::__construct();
|
||
|
||
CRM_Utils_System::resetBreadCrumb();
|
||
$breadcrumb = array(
|
||
array(
|
||
'title' => ts('Home'),
|
||
'url' => CRM_Utils_System::url(),
|
||
),
|
||
array(
|
||
'title' => ts('CiviCRM'),
|
||
'url' => CRM_Utils_System::url('civicrm', 'reset=1'),
|
||
),
|
||
array(
|
||
'title' => ts('View Contact'),
|
||
'url' => CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->cid}"),
|
||
),
|
||
array(
|
||
'title' => ts('Search Results'),
|
||
'url' => CRM_Utils_System::url('civicrm/contact/search', "force=1"),
|
||
),
|
||
);
|
||
CRM_Utils_System::appendBreadCrumb($breadcrumb);
|
||
|
||
if (CRM_Utils_Request::retrieve('revert', 'Boolean')) {
|
||
$this->revert();
|
||
}
|
||
|
||
$this->_columnHeaders = array(
|
||
'field' => array('title' => ts('Field')),
|
||
'from' => array('title' => ts('Changed From')),
|
||
'to' => array('title' => ts('Changed To')),
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Build query for report.
|
||
*
|
||
* We override this to be empty & calculate the rows in the buildRows function.
|
||
*
|
||
* @param bool $applyLimit
|
||
*/
|
||
public function buildQuery($applyLimit = TRUE) {
|
||
}
|
||
|
||
/**
|
||
* Build rows from query.
|
||
*
|
||
* @param string $sql
|
||
* @param array $rows
|
||
*/
|
||
public function buildRows($sql, &$rows) {
|
||
// safeguard for when there aren’t any log entries yet
|
||
if (!$this->log_conn_id && !$this->log_date) {
|
||
return;
|
||
}
|
||
$this->getDiffs();
|
||
$rows = $this->convertDiffsToRows();
|
||
}
|
||
|
||
/**
|
||
* Get the diffs for the report, calculating them if not already done.
|
||
*
|
||
* Note that contact details report now uses a more comprehensive method but
|
||
* the contribution logging details report still uses this.
|
||
*
|
||
* @return array
|
||
*/
|
||
protected function getDiffs() {
|
||
if (empty($this->diffs)) {
|
||
foreach ($this->tables as $table) {
|
||
$this->diffs = array_merge($this->diffs, $this->diffsInTable($table));
|
||
}
|
||
}
|
||
return $this->diffs;
|
||
}
|
||
|
||
/**
|
||
* @param $table
|
||
*
|
||
* @return array
|
||
*/
|
||
protected function diffsInTable($table) {
|
||
$this->setDiffer();
|
||
return $this->differ->diffsInTable($table, $this->cid);
|
||
}
|
||
|
||
/**
|
||
* Convert the diffs to row format.
|
||
*
|
||
* @return array
|
||
*/
|
||
protected function convertDiffsToRows() {
|
||
// return early if nothing found
|
||
if (empty($this->diffs)) {
|
||
return array();
|
||
}
|
||
|
||
// populate $rows with only the differences between $changed and $original (skipping certain columns and NULL ↔ empty changes unless raw requested)
|
||
$skipped = array('id');
|
||
foreach ($this->diffs as $diff) {
|
||
$table = $diff['table'];
|
||
if (empty($metadata[$table])) {
|
||
list($metadata[$table]['titles'], $metadata[$table]['values']) = $this->differ->titlesAndValuesForTable($table, $diff['log_date']);
|
||
}
|
||
$values = CRM_Utils_Array::value('values', $metadata[$diff['table']], array());
|
||
$titles = $metadata[$diff['table']]['titles'];
|
||
$field = $diff['field'];
|
||
$from = $diff['from'];
|
||
$to = $diff['to'];
|
||
|
||
if ($this->raw) {
|
||
$field = "$table.$field";
|
||
}
|
||
else {
|
||
if (in_array($field, $skipped)) {
|
||
continue;
|
||
}
|
||
// $differ filters out === values; for presentation hide changes like 42 → '42'
|
||
if ($from == $to) {
|
||
continue;
|
||
}
|
||
|
||
// special-case for multiple values. Also works for CRM-7251: preferred_communication_method
|
||
if ((substr($from, 0, 1) == CRM_Core_DAO::VALUE_SEPARATOR &&
|
||
substr($from, -1, 1) == CRM_Core_DAO::VALUE_SEPARATOR) ||
|
||
(substr($to, 0, 1) == CRM_Core_DAO::VALUE_SEPARATOR &&
|
||
substr($to, -1, 1) == CRM_Core_DAO::VALUE_SEPARATOR)
|
||
) {
|
||
$froms = $tos = array();
|
||
foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($from, CRM_Core_DAO::VALUE_SEPARATOR)) as $val) {
|
||
$froms[] = CRM_Utils_Array::value($val, $values[$field]);
|
||
}
|
||
foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($to, CRM_Core_DAO::VALUE_SEPARATOR)) as $val) {
|
||
$tos[] = CRM_Utils_Array::value($val, $values[$field]);
|
||
}
|
||
$from = implode(', ', array_filter($froms));
|
||
$to = implode(', ', array_filter($tos));
|
||
}
|
||
|
||
if (isset($values[$field][$from])) {
|
||
$from = $values[$field][$from];
|
||
}
|
||
if (isset($values[$field][$to])) {
|
||
$to = $values[$field][$to];
|
||
}
|
||
if (isset($titles[$field])) {
|
||
$field = $titles[$field];
|
||
}
|
||
if ($diff['action'] == 'Insert') {
|
||
$from = '';
|
||
}
|
||
if ($diff['action'] == 'Delete') {
|
||
$to = '';
|
||
}
|
||
}
|
||
|
||
$rows[] = array('field' => $field . " (id: {$diff['id']})", 'from' => $from, 'to' => $to);
|
||
}
|
||
|
||
return $rows;
|
||
}
|
||
|
||
public function buildQuickForm() {
|
||
parent::buildQuickForm();
|
||
|
||
$this->assign('whom_url', CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->cid}"));
|
||
$this->assign('who_url', CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->altered_by_id}"));
|
||
$this->assign('whom_name', $this->altered_name);
|
||
$this->assign('who_name', $this->altered_by);
|
||
|
||
$this->assign('log_date', CRM_Utils_Date::mysqlToIso($this->log_date));
|
||
|
||
$q = "reset=1&log_conn_id={$this->log_conn_id}&log_date={$this->log_date}";
|
||
if ($this->oid) {
|
||
$q .= '&oid=' . $this->oid;
|
||
}
|
||
$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?'));
|
||
}
|
||
|
||
/**
|
||
* Store the dsn for the logging database in $this->db.
|
||
*/
|
||
protected function storeDB() {
|
||
$dsn = defined('CIVICRM_LOGGING_DSN') ? DB::parseDSN(CIVICRM_LOGGING_DSN) : DB::parseDSN(CIVICRM_DSN);
|
||
$this->db = $dsn['database'];
|
||
}
|
||
|
||
/**
|
||
* Calculate all the contact related diffs for the change.
|
||
*/
|
||
protected function calculateContactDiffs() {
|
||
$this->diffs = $this->getAllContactChangesForConnection();
|
||
}
|
||
|
||
|
||
/**
|
||
* Get an array of changes made in the mysql connection.
|
||
*
|
||
* @return mixed
|
||
*/
|
||
public function getAllContactChangesForConnection() {
|
||
if (empty($this->log_conn_id)) {
|
||
return array();
|
||
}
|
||
$this->setDiffer();
|
||
try {
|
||
return $this->differ->getAllChangesForConnection($this->tables);
|
||
}
|
||
catch (CRM_Core_Exception $e) {
|
||
CRM_Core_Error::statusBounce(ts($e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Make sure the differ is defined.
|
||
*/
|
||
protected function setDiffer() {
|
||
if (empty($this->differ)) {
|
||
$this->differ = new CRM_Logging_Differ($this->log_conn_id, $this->log_date, $this->interval);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set this tables to reflect tables changed in a merge.
|
||
*/
|
||
protected function setTablesToContactRelatedTables() {
|
||
$schema = new CRM_Logging_Schema();
|
||
$this->tables = $schema->getLogTablesForContact();
|
||
// allow tables to be extended by report hook query objects.
|
||
// This is a report specific hook. It's unclear how it interacts to / overlaps the main one.
|
||
// It probably precedes the main one and was never reconciled with it....
|
||
CRM_Report_BAO_Hook::singleton()->alterLogTables($this, $this->tables);
|
||
}
|
||
|
||
/**
|
||
* Revert the changes defined by the parameters.
|
||
*/
|
||
protected function revert() {
|
||
$reverter = new CRM_Logging_Reverter($this->log_conn_id, $this->log_date);
|
||
$reverter->calculateDiffsFromLogConnAndDate($this->tables);
|
||
$reverter->revert();
|
||
CRM_Core_Session::setStatus(ts('The changes have been reverted.'), ts('Reverted'), 'success');
|
||
if ($this->cid) {
|
||
if ($this->oid) {
|
||
CRM_Utils_System::redirect(CRM_Utils_System::url(
|
||
'civicrm/contact/merge',
|
||
"reset=1&cid={$this->cid}&oid={$this->oid}",
|
||
FALSE,
|
||
NULL,
|
||
FALSE)
|
||
);
|
||
}
|
||
else {
|
||
CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view', "reset=1&selectedChild=log&cid={$this->cid}", FALSE, NULL, FALSE));
|
||
}
|
||
}
|
||
else {
|
||
CRM_Utils_System::redirect(CRM_Report_Utils_Report::getNextUrl($this->summary, 'reset=1', FALSE, TRUE));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get the properties that might be in the URL.
|
||
*/
|
||
protected function parsePropertiesFromUrl() {
|
||
$this->log_conn_id = CRM_Utils_Request::retrieve('log_conn_id', 'String');
|
||
$this->log_date = CRM_Utils_Request::retrieve('log_date', 'String');
|
||
$this->cid = CRM_Utils_Request::retrieve('cid', 'Integer');
|
||
$this->raw = CRM_Utils_Request::retrieve('raw', 'Boolean');
|
||
|
||
$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');
|
||
}
|
||
|
||
}
|