Merge pull request #1590 from ravishnair/webtestfix
[civicrm-core.git] / CRM / Logging / ReportDetail.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35 class CRM_Logging_ReportDetail extends CRM_Report_Form {
36 protected $cid;
37 protected $db;
38 protected $log_conn_id;
39 protected $log_date;
40 protected $raw;
41 protected $tables = array();
42 protected $interval = '10 SECOND';
43
44 // detail/summary report ids
45 protected $detail;
46 protected $summary;
47
48 function __construct() {
49 // don’t display the ‘Add these Contacts to Group’ button
50 $this->_add2groupSupported = FALSE;
51
52 $dsn = defined('CIVICRM_LOGGING_DSN') ? DB::parseDSN(CIVICRM_LOGGING_DSN) : DB::parseDSN(CIVICRM_DSN);
53 $this->db = $dsn['database'];
54
55 $this->log_conn_id = CRM_Utils_Request::retrieve('log_conn_id', 'Integer', CRM_Core_DAO::$_nullObject);
56 $this->log_date = CRM_Utils_Request::retrieve('log_date', 'String', CRM_Core_DAO::$_nullObject);
57 $this->cid = CRM_Utils_Request::retrieve('cid', 'Integer', CRM_Core_DAO::$_nullObject);
58 $this->raw = CRM_Utils_Request::retrieve('raw', 'Boolean', CRM_Core_DAO::$_nullObject);
59
60 parent::__construct();
61
62 CRM_Utils_System::resetBreadCrumb();
63 $breadcrumb =
64 array(
65 array('title' => ts('Home'),
66 'url' => CRM_Utils_System::url()),
67 array('title' => ts('CiviCRM'),
68 'url' => CRM_Utils_System::url('civicrm', 'reset=1')),
69 array('title' => ts('View Contact'),
70 'url' => CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->cid}")),
71 array('title' => ts('Search Results'),
72 'url' => CRM_Utils_System::url('civicrm/contact/search', "force=1")),
73 );
74 CRM_Utils_System::appendBreadCrumb($breadcrumb);
75
76 if (CRM_Utils_Request::retrieve('revert', 'Boolean', CRM_Core_DAO::$_nullObject)) {
77 $reverter = new CRM_Logging_Reverter($this->log_conn_id, $this->log_date);
78 $reverter->revert($this->tables);
79 CRM_Core_Session::setStatus(ts('The changes have been reverted.'), ts('Reverted'), 'success');
80 if ($this->cid) {
81 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view', "reset=1&selectedChild=log&cid={$this->cid}", FALSE, NULL, FALSE));
82 }
83 else {
84 CRM_Utils_System::redirect(CRM_Report_Utils_Report::getNextUrl($this->summary, 'reset=1', FALSE, TRUE));
85 }
86 }
87
88 // make sure the report works even without the params
89 if (!$this->log_conn_id or !$this->log_date) {
90 $dao = new CRM_Core_DAO;
91 $dao->query("SELECT log_conn_id, log_date FROM `{$this->db}`.log_{$this->tables[0]} WHERE log_action = 'Update' ORDER BY log_date DESC LIMIT 1");
92 $dao->fetch();
93 $this->log_conn_id = $dao->log_conn_id;
94 $this->log_date = $dao->log_date;
95 }
96
97 $this->_columnHeaders = array(
98 'field' => array('title' => ts('Field')),
99 'from' => array('title' => ts('Changed From')),
100 'to' => array('title' => ts('Changed To')),
101 );
102 }
103
104 function buildQuery($applyLimit = TRUE) {}
105
106 function buildRows($sql, &$rows) {
107 // safeguard for when there aren’t any log entries yet
108 if (!$this->log_conn_id or !$this->log_date) {
109 return;
110 }
111
112 if (empty($rows)) {
113
114 $rows = array();
115
116 }
117
118 foreach ($this->tables as $table) {
119 $rows = array_merge($rows, $this->diffsInTable($table));
120 }
121 }
122
123 protected function diffsInTable($table) {
124 $rows = array();
125
126 $differ = new CRM_Logging_Differ($this->log_conn_id, $this->log_date, $this->interval);
127 $diffs = $differ->diffsInTable($table, $this->cid);
128
129 // return early if nothing found
130 if (empty($diffs)) {
131 return $rows;
132 }
133
134 list($titles, $values) = $differ->titlesAndValuesForTable($table);
135
136 // populate $rows with only the differences between $changed and $original (skipping certain columns and NULL ↔ empty changes unless raw requested)
137 $skipped = array('contact_id', 'entity_id', 'id');
138 foreach ($diffs as $diff) {
139 $field = $diff['field'];
140 $from = $diff['from'];
141 $to = $diff['to'];
142
143 if ($this->raw) {
144 $field = "$table.$field";
145 }
146 else {
147 if (in_array($field, $skipped)) {
148 continue;
149 }
150 // $differ filters out === values; for presentation hide changes like 42 → '42'
151 if ($from == $to) {
152 continue;
153 }
154
155 // special-case for multiple values. Also works for CRM-7251: preferred_communication_method
156 if ((substr($from, 0, 1) == CRM_Core_DAO::VALUE_SEPARATOR &&
157 substr($from, -1, 1) == CRM_Core_DAO::VALUE_SEPARATOR) ||
158 (substr($to, 0, 1) == CRM_Core_DAO::VALUE_SEPARATOR &&
159 substr($to, -1, 1) == CRM_Core_DAO::VALUE_SEPARATOR)) {
160 $froms = $tos = array();
161 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($from, CRM_Core_DAO::VALUE_SEPARATOR)) as $val) {
162 $froms[] = CRM_Utils_Array::value($val, $values[$field]);
163 }
164 foreach (explode(CRM_Core_DAO::VALUE_SEPARATOR, trim($to, CRM_Core_DAO::VALUE_SEPARATOR)) as $val) {
165 $tos[] = CRM_Utils_Array::value($val, $values[$field]);
166 }
167 $from = implode(', ', array_filter($froms));
168 $to = implode(', ', array_filter($tos));
169 }
170
171 if (isset($values[$field][$from])) {
172 $from = $values[$field][$from];
173 }
174 if (isset($values[$field][$to])) {
175 $to = $values[$field][$to];
176 }
177 if (isset($titles[$field])) {
178 $field = $titles[$field];
179 }
180 if ($diff['action'] == 'Insert') {
181 $from = '';
182 }
183 if ($diff['action'] == 'Delete') {
184 $to = '';
185 }
186 }
187
188 $rows[] = array('field' => $field . " (id: {$diff['id']})", 'from' => $from, 'to' => $to);
189 }
190
191 return $rows;
192 }
193
194 function buildQuickForm() {
195 parent::buildQuickForm();
196
197 $params = array(
198 1 => array($this->log_conn_id, 'Integer'),
199 2 => array($this->log_date, 'String'),
200 );
201
202 // let the template know who updated whom when
203 $dao = CRM_Core_DAO::executeQuery($this->whoWhomWhenSql(), $params);
204 if ($dao->fetch()) {
205 $this->assign('who_url', CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->who_id}"));
206 $this->assign('whom_url', CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->whom_id}"));
207 $this->assign('who_name', $dao->who_name);
208 $this->assign('whom_name', $dao->whom_name);
209 }
210 $this->assign('log_date', CRM_Utils_Date::mysqlToIso($this->log_date));
211
212 $q = "reset=1&log_conn_id={$this->log_conn_id}&log_date={$this->log_date}";
213 $this->assign('revertURL', CRM_Report_Utils_Report::getNextUrl($this->detail, "$q&revert=1", FALSE, TRUE));
214 $this->assign('revertConfirm', ts('Are you sure you want to revert all these changes?'));
215 }
216
217 // redefine this accordingly in ancestors for buildQuickForm()’s sake
218 protected function whoWhomWhenSql() {}
219 }
220