Merge pull request #16074 from civicrm/5.21
[civicrm-core.git] / CRM / Upgrade / Incremental / SmartGroups.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 *
17 * Class to handled upgrading any saved searches with changed patterns.
18 */
19 class CRM_Upgrade_Incremental_SmartGroups {
20
21 /**
22 * Perform updates specified by upgrade function.
23 */
24 public function updateGroups($actions) {
25 foreach ($actions as $func => $fields) {
26 if ($func == 'renameField') {
27 foreach ($fields as $fieldConversion) {
28 $this->{$func}($fieldConversion['old'], $fieldConversion['new']);
29 }
30 }
31 else {
32 $this->{$func}($fields);
33 }
34 }
35 }
36
37 /**
38 * Convert any
39 * @param array $fields
40 */
41 public function datePickerConversion($fields) {
42 $fieldPossibilities = $relativeFieldNames = [];
43 $relativeDateMappings = [
44 'activity_date_time' => 'activity',
45 'participant_register_date' => 'participant',
46 'receive_date' => 'contribution',
47 'contribution_cancel_date' => 'contribution_cancel',
48 'membership_join_date' => 'member_join',
49 'membership_start_date' => 'member_start',
50 'membership_end_date' => 'member_end',
51 'pledge_payment_scheduled_date' => 'pledge_payment',
52 'pledge_create_date' => 'pledge_create',
53 'pledge_end_date' => 'pledge_end',
54 'pledge_start_date' => 'pledge_start',
55 'case_start_date' => 'case_from',
56 'case_end_date' => 'case_to',
57 'mailing_job_start_date' => 'mailing_date',
58 'relationship_start_date' => 'relation_start',
59 'relationship_end_date' => 'relation_end',
60 'event' => 'event',
61 'created_date' => 'log',
62 'modified_date' => 'log',
63 ];
64
65 foreach ($fields as $field) {
66 foreach ($this->getSearchesWithField($field) as $savedSearch) {
67 // Only populate field possibilities as we go to convert each field
68 $fieldPossibilities[] = $field;
69 $fieldPossibilities[] = $field . '_high';
70 $fieldPossibilities[] = $field . '_low';
71 $formValues = $savedSearch['form_values'];
72 $isRelative = $hasRelative = FALSE;
73 $relativeFieldName = $field . '_relative';
74
75 if (!empty($relativeDateMappings[$field]) && isset($formValues['relative_dates'])) {
76 if (!empty($formValues['relative_dates'][$relativeDateMappings[$field]])) {
77 $formValues[] = [$relativeFieldName, '=', $savedSearch['form_values']['relative_dates'][$relativeDateMappings[$field]]];
78 unset($formValues['relative_dates'][$relativeDateMappings[$field]]);
79 $isRelative = TRUE;
80 }
81 }
82 foreach ($formValues as $index => $formValue) {
83 if (!is_array($formValue)) {
84 if ($index === $relativeFieldName) {
85 $hasRelative = TRUE;
86 if (!empty($formValue)) {
87 $isRelative = TRUE;
88 }
89 continue;
90 }
91 elseif ($index === 'event_low' || $index === 'event_high') {
92 if ($isRelative || (!$isRelative && $formValue === '')) {
93 unset($formValues[$index]);
94 }
95 else {
96 $isHigh = substr($index, -5, 5) === '_high';
97 $formValues[$index] = $this->getConvertedDateValue($formValue, $isHigh);
98 }
99 }
100 continue;
101 }
102 if (!isset($formValue[0])) {
103 // Any actual criteria will have this key set but skip any weird lines
104 continue;
105 }
106 if ($formValue[0] === $relativeFieldName && !empty($formValue[2])) {
107 $hasRelative = TRUE;
108 }
109 if ($formValue[0] === $relativeFieldName && empty($formValue[2])) {
110 unset($formValues[$index]);
111 }
112 elseif (in_array($formValue[0], $fieldPossibilities)) {
113 if ($isRelative) {
114 unset($formValues[$index]);
115 }
116 else {
117 $isHigh = substr($formValue[0], -5, 5) === '_high';
118 $formValues[$index][2] = $this->getConvertedDateValue($formValue[2], $isHigh);
119 }
120 }
121 }
122 if (!$isRelative) {
123 if (!in_array($relativeFieldName, $relativeFieldNames)) {
124 $relativeFieldNames[] = $relativeFieldName;
125 $formValues[] = [$relativeFieldName, '=', 0];
126 }
127 elseif (!$hasRelative) {
128 $formValues[] = [$relativeFieldName, '=', 0];
129 }
130 }
131 if ($formValues !== $savedSearch['form_values']) {
132 civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $formValues]);
133 }
134 }
135 }
136 }
137
138 /**
139 * Conversion routine for a form change change from = string to IN array.
140 *
141 * For example a checkbox expected [$fieldName, '=', 1]
142 * whereas select expects [$fieldName, 'IN', [1]]
143 *
144 * @param string $field
145 */
146 public function convertEqualsStringToInArray($field) {
147 foreach ($this->getSearchesWithField($field) as $savedSearch) {
148 $formValues = $savedSearch['form_values'];
149 foreach ($formValues as $index => $formValue) {
150 if ($formValue[0] === $field && !is_array($formValue[2]) && $formValue[1] === '=') {
151 $formValues[$index][1] = 'IN';
152 $formValues[$index][2] = [$formValue[2]];
153 }
154 }
155
156 if ($formValues !== $savedSearch['form_values']) {
157 civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $formValues]);
158 }
159 }
160 }
161
162 /**
163 * Get converted date value.
164 *
165 * @param string $dateValue
166 * @param bool $isEndOfDay
167 * Is this the upper value in a search range? If so alter the time to
168 * get the end of day if none set.
169 *
170 * @return string
171 * $dateValue
172 */
173 protected function getConvertedDateValue($dateValue, $isEndOfDay) {
174 if (date('Y-m-d', strtotime($dateValue)) !== $dateValue
175 && date('Y-m-d H:i:s', strtotime($dateValue)) !== $dateValue
176 ) {
177 $dateValue = date('Y-m-d H:i:s', strtotime(CRM_Utils_Date::processDate($dateValue)));
178 if ($isEndOfDay) {
179 $dateValue = str_replace('00:00:00', '23:59:59', $dateValue);
180 }
181 }
182 return $dateValue;
183 }
184
185 /**
186 * Rename a smartgroup field.
187 *
188 * @param string $oldName
189 * @param string $newName
190 */
191 public function renameField($oldName, $newName) {
192 foreach ($this->getSearchesWithField($oldName) as $savedSearch) {
193 $formValues = $savedSearch['form_values'];
194 foreach ($formValues as $index => $formValue) {
195 if (is_array($formValue)) {
196 if (isset($formValue[0]) && $formValue[0] === $oldName) {
197 $formValues[$index][0] = $newName;
198 }
199 }
200 elseif ($index === $oldName) {
201 $formValues[$newName] = $formValue;
202 unset($formValues[$oldName]);
203 }
204 }
205
206 if ($formValues !== $savedSearch['form_values']) {
207 civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $formValues]);
208 }
209 }
210 }
211
212 /**
213 * Rename pairs of fields
214 *
215 * @param array $pairs
216 * Array or arrays of pairs - e.g
217 * [
218 * ['old' => 'activity_date', 'new' => 'activity_date_time'],
219 * ['old' => 'activity_date_low', 'new' => 'activity_date_time_low'],
220 * ['old' => 'activity_date_high', 'new' => 'activity_date_time_high'],
221 * ['old' => 'activity_date_relative', 'new' => 'activity_date_time_relative'],
222 * ]
223 */
224 public function renameFields($pairs) {
225 foreach ($pairs as $pair) {
226 $this->renameField($pair['old'], $pair['new']);
227 }
228 }
229
230 /**
231 * @param $field
232 * @return mixed
233 */
234 protected function getSearchesWithField($field) {
235 $savedSearches = civicrm_api3('SavedSearch', 'get', [
236 'options' => ['limit' => 0],
237 'form_values' => ['LIKE' => "%{$field}%"],
238 ])['values'];
239 return $savedSearches;
240
241 }
242
243 /**
244 * Convert the log_date saved search date fields to their correct name
245 * default to switching to created_date as that is what the code did originally
246 */
247 public function renameLogFields() {
248 $addedDate = TRUE;
249 foreach ($this->getSearchesWithField('log_date') as $savedSearch) {
250 $formValues = $savedSearch['form_values'];
251 foreach ($formValues as $index => $formValue) {
252 if (isset($formValue[0]) && $formValue[0] === 'log_date') {
253 if ($formValue[2] == 2) {
254 $addedDate = FALSE;
255 }
256 }
257 if (isset($formValue[0]) && ($formValue[0] === 'log_date_high' || $formValue[0] === 'log_date_low')) {
258 $isHigh = substr($index, -5, 5) === '_high';
259 if ($addedDate) {
260 $fieldName = 'created_date';
261 }
262 else {
263 $fieldName = 'modified_date';
264 }
265 if ($isHigh) {
266 $fieldName .= '_high';
267 }
268 else {
269 $fieldName .= '_low';
270 }
271 $formValues[$index][0] = $fieldName;
272 }
273 }
274 if ($formValues !== $savedSearch['form_values']) {
275 civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $formValues]);
276 }
277 }
278 }
279
280 /**
281 * Convert Custom date fields in smart groups
282 */
283 public function convertCustomSmartGroups() {
284 $custom_date_fields = CRM_Core_DAO::executeQuery("SELECT id FROM civicrm_custom_field WHERE data_type = 'Date' AND is_search_range = 1");
285 while ($custom_date_fields->fetch()) {
286 $savedSearches = $this->getSearchesWithField('custom_' . $custom_date_fields->id);
287 foreach ($savedSearches as $savedSearch) {
288 $form_values = $savedSearch['form_values'];
289 foreach ($form_values as $index => $formValues) {
290 if ($formValues[0] === 'custom_' . $custom_date_fields->id && is_array($formValues[2])) {
291 if (isset($formValues[2]['BETWEEN'])) {
292 $form_values[] = ['custom_' . $custom_date_fields->id . '_low', '=', $this->getConvertedDateValue($formValues[2]['BETWEEN'][0], FALSE)];
293 $form_values[] = ['custom_' . $custom_date_fields->id . '_high', '=', $this->getConvertedDateValue($formValues[2]['BETWEEN'][1], TRUE)];
294 unset($form_values[$index]);
295 }
296 if (isset($formValues[2]['>='])) {
297 $form_values[] = ['custom_' . $custom_date_fields->id . '_low', '=', $this->getConvertedDateValue($formValues[2]['>='], FALSE)];
298 unset($form_values[$index]);
299 }
300 if (isset($formValues[2]['<='])) {
301 $form_values[] = ['custom_' . $custom_date_fields->id . '_high', '=', $this->getConvertedDateValue($formValues[2]['<='], TRUE)];
302 unset($form_values[$index]);
303 }
304 }
305 }
306 if ($form_values !== $savedSearch['form_values']) {
307 civicrm_api3('SavedSearch', 'create', ['id' => $savedSearch['id'], 'form_values' => $form_values]);
308 }
309 }
310 }
311 }
312
313 }