Merge pull request #20561 from WeMoveEU/fix/double-autosave
[civicrm-core.git] / CRM / Report / Form / Mailing / Clicks.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17class CRM_Report_Form_Mailing_Clicks extends CRM_Report_Form {
18
19 protected $_summary = NULL;
20
21 protected $_emailField = FALSE;
22
23 protected $_phoneField = FALSE;
24
be2fb01f 25 protected $_customGroupExtends = [
9d72cede
EM
26 'Contact',
27 'Individual',
28 'Household',
21dfd5f5 29 'Organization',
be2fb01f 30 ];
6a488035 31
74cf4551 32 /**
1728e9a0 33 * This report has not been optimised for group filtering.
34 *
35 * The functionality for group filtering has been improved but not
36 * all reports have been adjusted to take care of it. This report has not
37 * and will run an inefficient query until fixed.
38 *
1728e9a0 39 * @var bool
0e480632 40 * @see https://issues.civicrm.org/jira/browse/CRM-19170
74cf4551 41 */
1728e9a0 42 protected $groupFilterNotOptimised = TRUE;
43
74cf4551 44 /**
1728e9a0 45 * Class constructor.
74cf4551 46 */
00be9182 47 public function __construct() {
be2fb01f 48 $this->_columns = [];
6a488035 49
be2fb01f 50 $this->_columns['civicrm_contact'] = [
6a488035 51 'dao' => 'CRM_Contact_DAO_Contact',
be2fb01f
CW
52 'fields' => [
53 'id' => [
6a488035
TO
54 'title' => ts('Contact ID'),
55 'required' => TRUE,
be2fb01f
CW
56 ],
57 'sort_name' => [
6a488035
TO
58 'title' => ts('Contact Name'),
59 'required' => TRUE,
be2fb01f
CW
60 ],
61 ],
62 'filters' => [
63 'sort_name' => [
6a488035 64 'title' => ts('Contact Name'),
be2fb01f
CW
65 ],
66 'source' => [
6a488035
TO
67 'title' => ts('Contact Source'),
68 'type' => CRM_Utils_Type::T_STRING,
be2fb01f
CW
69 ],
70 'id' => [
6a488035
TO
71 'title' => ts('Contact ID'),
72 'no_display' => TRUE,
be2fb01f
CW
73 ],
74 ],
75 'order_bys' => [
76 'sort_name' => [
9d72cede
EM
77 'title' => ts('Contact Name'),
78 'default' => TRUE,
21dfd5f5 79 'default_order' => 'ASC',
be2fb01f
CW
80 ],
81 ],
6a488035 82 'grouping' => 'contact-fields',
be2fb01f 83 ];
6a488035 84
be2fb01f 85 $this->_columns['civicrm_mailing'] = [
6a488035 86 'dao' => 'CRM_Mailing_DAO_Mailing',
be2fb01f
CW
87 'fields' => [
88 'mailing_name' => [
6a488035 89 'name' => 'name',
4e474ab5 90 'title' => ts('Mailing Name'),
6a488035 91 'default' => TRUE,
be2fb01f
CW
92 ],
93 'mailing_name_alias' => [
6a488035
TO
94 'name' => 'name',
95 'required' => TRUE,
96 'no_display' => TRUE,
be2fb01f
CW
97 ],
98 'mailing_subject' => [
4e474ab5
BS
99 'name' => 'subject',
100 'title' => ts('Mailing Subject'),
df28e44e 101 'default' => TRUE,
be2fb01f
CW
102 ],
103 ],
104 'filters' => [
105 'mailing_id' => [
6a488035 106 'name' => 'id',
4e474ab5 107 'title' => ts('Mailing Name'),
6a488035
TO
108 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
109 'type' => CRM_Utils_Type::T_INT,
110 'options' => CRM_Mailing_BAO_Mailing::getMailingsList(),
111 'operator' => 'like',
be2fb01f
CW
112 ],
113 'mailing_subject' => [
4e474ab5
BS
114 'name' => 'subject',
115 'title' => ts('Mailing Subject'),
df28e44e 116 'type' => CRM_Utils_Type::T_STRING,
4e474ab5 117 'operator' => 'like',
be2fb01f
CW
118 ],
119 ],
120 'order_bys' => [
121 'mailing_name' => [
6a488035 122 'name' => 'name',
4e474ab5 123 'title' => ts('Mailing Name'),
be2fb01f
CW
124 ],
125 'mailing_subject' => [
4e474ab5 126 'name' => 'subject',
df28e44e 127 'title' => ts('Mailing Subject'),
be2fb01f
CW
128 ],
129 ],
6a488035 130 'grouping' => 'mailing-fields',
be2fb01f 131 ];
6a488035 132
be2fb01f 133 $this->_columns['civicrm_email'] = [
6a488035 134 'dao' => 'CRM_Core_DAO_Email',
be2fb01f
CW
135 'fields' => [
136 'email' => [
6a488035
TO
137 'title' => ts('Email'),
138 'no_repeat' => TRUE,
be2fb01f
CW
139 ],
140 ],
6a488035 141 'grouping' => 'contact-fields',
be2fb01f 142 ];
6a488035 143
be2fb01f 144 $this->_columns['civicrm_phone'] = [
6a488035 145 'dao' => 'CRM_Core_DAO_Phone',
be2fb01f 146 'fields' => ['phone' => NULL],
6a488035 147 'grouping' => 'contact-fields',
be2fb01f 148 ];
6a488035 149
be2fb01f 150 $this->_columns['civicrm_mailing_trackable_url'] = [
6a488035 151 'dao' => 'CRM_Mailing_DAO_TrackableURL',
be2fb01f
CW
152 'fields' => [
153 'url' => [
6a488035 154 'title' => ts('Click through URL'),
be2fb01f
CW
155 ],
156 ],
54e50437
SL
157 // To do this filter should really be like mailing id filter a multi select, However
158 // Not clear on how to make filter dependant on selected mailings at this stage so have set a
54a07edd 159 // text filter which works for now
be2fb01f
CW
160 'filters' => [
161 'url' => [
54a07edd
SL
162 'title' => ts('URL'),
163 'type' => CRM_Utils_Type::T_STRING,
164 'operator' => 'like',
be2fb01f
CW
165 ],
166 ],
167 'order_bys' => [
168 'url' => ['title' => ts('Click through URL')],
169 ],
6a488035 170 'grouping' => 'mailing-fields',
be2fb01f 171 ];
6a488035 172
be2fb01f 173 $this->_columns['civicrm_mailing_event_trackable_url_open'] = [
22d79c85 174 'dao' => 'CRM_Mailing_Event_DAO_TrackableURLOpen',
be2fb01f
CW
175 'fields' => [
176 'time_stamp' => [
22d79c85
BS
177 'title' => ts('Click Date'),
178 'default' => TRUE,
be2fb01f
CW
179 ],
180 ],
181 'filters' => [
182 'time_stamp' => [
22d79c85
BS
183 'title' => ts('Click Date'),
184 'operatorType' => CRM_Report_Form::OP_DATE,
185 'type' => CRM_Utils_Type::T_DATE,
be2fb01f
CW
186 ],
187 ],
188 'order_bys' => [
189 'time_stamp' => [
22d79c85 190 'title' => ts('Click Date'),
be2fb01f
CW
191 ],
192 ],
22d79c85 193 'grouping' => 'mailing-fields',
be2fb01f 194 ];
22d79c85 195
f787b3c4
BT
196 // Add charts support
197 $this->_charts = [
198 '' => ts('Tabular'),
199 'barChart' => ts('Bar Chart'),
200 'pieChart' => ts('Pie Chart'),
201 ];
202
16e2e80c 203 $this->_groupFilter = TRUE;
6a488035
TO
204 $this->_tagFilter = TRUE;
205 parent::__construct();
206 }
207
00be9182 208 public function preProcess() {
6a488035
TO
209 $this->assign('chartSupported', TRUE);
210 parent::preProcess();
211 }
212
00be9182 213 public function select() {
be2fb01f
CW
214 $select = [];
215 $this->_columnHeaders = [];
6a488035
TO
216 foreach ($this->_columns as $tableName => $table) {
217 if (array_key_exists('fields', $table)) {
218 foreach ($table['fields'] as $fieldName => $field) {
9d72cede
EM
219 if (!empty($field['required']) ||
220 !empty($this->_params['fields'][$fieldName])
221 ) {
6a488035
TO
222 if ($tableName == 'civicrm_email') {
223 $this->_emailField = TRUE;
224 }
225 elseif ($tableName == 'civicrm_phone') {
226 $this->_phoneField = TRUE;
227 }
228
229 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
9c1bc317
CW
230 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = $field['type'] ?? NULL;
231 $this->_columnHeaders["{$tableName}_{$fieldName}"]['no_display'] = $field['no_display'] ?? NULL;
232 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'] ?? NULL;
6a488035
TO
233 }
234 }
235 }
236 }
237
a7488080 238 if (!empty($this->_params['charts'])) {
94dd9f6f 239 $select[] = "COUNT({$this->_aliases['civicrm_mailing_event_trackable_url_open']}.id) as civicrm_mailing_click_count";
6a488035
TO
240 $this->_columnHeaders["civicrm_mailing_click_count"]['title'] = ts('Click Count');
241 }
242
d1641c51 243 $this->_selectClauses = $select;
6a488035
TO
244 $this->_select = "SELECT " . implode(', ', $select) . " ";
245 }
246
74cf4551
EM
247 /**
248 * @param $fields
249 * @param $files
250 * @param $self
251 *
252 * @return array
253 */
00be9182 254 public static function formRule($fields, $files, $self) {
be2fb01f 255 $errors = $grouping = [];
6a488035
TO
256 return $errors;
257 }
258
00be9182 259 public function from() {
6a488035 260 $this->_from = "
22d79c85 261 FROM civicrm_contact {$this->_aliases['civicrm_contact']} {$this->_aclFrom}";
6a488035
TO
262
263 $this->_from .= "
a789061e 264 INNER JOIN civicrm_mailing_event_queue
265 ON civicrm_mailing_event_queue.contact_id = {$this->_aliases['civicrm_contact']}.id
22d79c85 266 LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
a789061e 267 ON civicrm_mailing_event_queue.email_id = {$this->_aliases['civicrm_email']}.id
22d79c85 268 INNER JOIN civicrm_mailing_event_trackable_url_open {$this->_aliases['civicrm_mailing_event_trackable_url_open']}
a789061e 269 ON {$this->_aliases['civicrm_mailing_event_trackable_url_open']}.event_queue_id = civicrm_mailing_event_queue.id
22d79c85
BS
270 INNER JOIN civicrm_mailing_trackable_url {$this->_aliases['civicrm_mailing_trackable_url']}
271 ON {$this->_aliases['civicrm_mailing_event_trackable_url_open']}.trackable_url_id = {$this->_aliases['civicrm_mailing_trackable_url']}.id
a789061e 272 INNER JOIN civicrm_mailing_job
273 ON civicrm_mailing_event_queue.job_id = civicrm_mailing_job.id
22d79c85 274 INNER JOIN civicrm_mailing {$this->_aliases['civicrm_mailing']}
a789061e 275 ON civicrm_mailing_job.mailing_id = {$this->_aliases['civicrm_mailing']}.id
276 AND civicrm_mailing_job.is_test = 0
22d79c85 277 ";
2a5bea53 278 $this->joinPhoneFromContact();
6a488035
TO
279 }
280
00be9182 281 public function where() {
6a488035
TO
282 parent::where();
283 $this->_where .= " AND {$this->_aliases['civicrm_mailing']}.sms_provider_id IS NULL";
284 }
285
00be9182 286 public function groupBy() {
6a488035 287 $this->_groupBy = '';
a7488080 288 if (!empty($this->_params['charts'])) {
d1641c51 289 $groupBy = "{$this->_aliases['civicrm_mailing']}.id";
6a488035
TO
290 }
291 else {
22d79c85 292 $groupBy = "{$this->_aliases['civicrm_mailing_event_trackable_url_open']}.id";
6a488035 293 }
b708c08d 294 $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, $groupBy);
6a488035
TO
295 }
296
00be9182 297 public function postProcess() {
6a488035
TO
298
299 $this->beginPostProcess();
300
301 // get the acl clauses built before we assemble the query
302 $this->buildACLClause($this->_aliases['civicrm_contact']);
303
304 $sql = $this->buildQuery(TRUE);
305
be2fb01f 306 $rows = $graphRows = [];
6a488035
TO
307 $this->buildRows($sql, $rows);
308
309 $this->formatDisplay($rows);
310 $this->doTemplateAssignment($rows);
311 $this->endPostProcess($rows);
312 }
313
74cf4551
EM
314 /**
315 * @param $rows
316 */
00be9182 317 public function buildChart(&$rows) {
6a488035
TO
318 if (empty($rows)) {
319 return;
320 }
321
be2fb01f 322 $chartInfo = [
7a39e5e9 323 'legend' => ts('Mail Click-Through Report'),
6a488035
TO
324 'xname' => ts('Mailing'),
325 'yname' => ts('Clicks'),
326 'xLabelAngle' => 20,
be2fb01f
CW
327 'tip' => ts('Clicks: %1', [1 => '#val#']),
328 ];
6a488035
TO
329 foreach ($rows as $row) {
330 $chartInfo['values'][$row['civicrm_mailing_mailing_name_alias']] = $row['civicrm_mailing_click_count'];
331 }
332
333 // build the chart.
dc61ee93 334 CRM_Utils_Chart::buildChart($chartInfo, $this->_params['charts']);
6a488035
TO
335 $this->assign('chartType', $this->_params['charts']);
336 }
337
74cf4551 338 /**
ced9bfed
EM
339 * Alter display of rows.
340 *
341 * Iterate through the rows retrieved via SQL and make changes for display purposes,
342 * such as rendering contacts as links.
343 *
344 * @param array $rows
345 * Rows generated by SQL, with an array for each row.
74cf4551 346 */
00be9182 347 public function alterDisplay(&$rows) {
6a488035
TO
348 $entryFound = FALSE;
349 foreach ($rows as $rowNum => $row) {
d2c742e9
J
350
351 // If the email address has been deleted
352 if (array_key_exists('civicrm_email_email', $row)) {
353 if (empty($rows[$rowNum]['civicrm_email_email'])) {
81ca3560 354 $rows[$rowNum]['civicrm_email_email'] = '<del>' . ts('Email address deleted.') . '</del>';
d2c742e9
J
355 }
356 $entryFound = TRUE;
357 }
358
6a488035
TO
359 // make count columns point to detail report
360 // convert display name to links
361 if (array_key_exists('civicrm_contact_sort_name', $row) &&
362 array_key_exists('civicrm_contact_id', $row)
363 ) {
364 $url = CRM_Utils_System::url('civicrm/contact/view',
365 'reset=1&cid=' . $row['civicrm_contact_id'],
366 $this->_absoluteUrl
367 );
368 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
369 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts("View Contact details for this contact.");
370 $entryFound = TRUE;
371 }
372
373 // skip looking further in rows, if first row itself doesn't
374 // have the column we need
375 if (!$entryFound) {
376 break;
377 }
378 }
379 }
96025800 380
6a488035 381}