Merge pull request #4875 from civicrm/minor-fix
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourFour.php
CommitLineData
a47a2f90 1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
a47a2f90 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
a47a2f90 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. |
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 along with this program; if not, contact CiviCRM LLC |
21 | at info[AT]civicrm[DOT]org. If you have questions about the |
22 | GNU Affero General Public License or the licensing of CiviCRM, |
23 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
24 +--------------------------------------------------------------------+
25*/
26
27/**
28 *
29 * @package CRM
06b69b18 30 * @copyright CiviCRM LLC (c) 2004-2014
a47a2f90 31 * $Id$
32 *
33 */
34class CRM_Upgrade_Incremental_php_FourFour {
35 const BATCH_SIZE = 5000;
36
52592398
TO
37 const MAX_WORD_REPLACEMENT_SIZE = 255;
38
624e56fa
EM
39 /**
40 * @param $errors
41 *
42 * @return bool
43 */
00be9182 44 public function verifyPreDBstate(&$errors) {
a47a2f90 45 return TRUE;
46 }
47
48 /**
49 * Compute any messages which should be displayed beforeupgrade
50 *
51 * Note: This function is called iteratively for each upcoming
52 * revision to the database.
53 *
d0f74b53 54 * @param $preUpgradeMessage
5a4f6742
CW
55 * @param string $rev
56 * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
d0f74b53
EM
57 * @param null $currentVer
58 *
a47a2f90 59 * @return void
60 */
00be9182 61 public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
52592398
TO
62 if ($rev == '4.4.beta1') {
63 $apiCalls = self::getConfigArraysAsAPIParams(FALSE);
64 $oversizedEntries = 0;
65 foreach ($apiCalls as $params) {
66 if (!self::isValidWordReplacement($params)) {
67 $oversizedEntries++;
68 }
69 }
70 if ($oversizedEntries > 0) {
71 $preUpgradeMessage .= '<br/>' . ts("WARNING: There are %1 word-replacement entries which will not be valid in v4.4+ (eg with over 255 characters). They will be dropped during upgrade. For details, consult the CiviCRM log.", array(
353ffa53
TO
72 1 => $oversizedEntries,
73 ));
52592398
TO
74 }
75 }
a47a2f90 76 }
77
78 /**
79 * Compute any messages which should be displayed after upgrade
80 *
5a4f6742
CW
81 * @param string $postUpgradeMessage
82 * alterable.
83 * @param string $rev
84 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
a47a2f90 85 * @return void
86 */
00be9182 87 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
61320313 88 if ($rev == '4.4.1') {
634e1a1a
DL
89 $config = CRM_Core_Config::singleton();
90 if (!empty($config->useIDS)) {
61320313 91 $postUpgradeMessage .= '<br />' . ts("The setting to skip IDS check has been removed. Your site has this configured in civicrm.settings.php but it will no longer work. Instead, use the new permission 'skip IDS check' to bypass the IDS system.");
634e1a1a
DL
92 }
93 }
9e58e6ff 94 if ($rev == '4.4.3') {
09163e8a 95 $postUpgradeMessage .= '<br /><br />' . ts('Default versions of the following System Workflow Message Templates have been modified to handle new functionality: <ul><li>Events - Registration Confirmation and Receipt (on-line)</li></ul> If you have modified these templates, please review the new default versions and implement updates as needed to your copies (Administer > Communications > Message Templates > System Workflow Messages).');
9e58e6ff 96 }
1543f800
DG
97 if ($rev == '4.4.3') {
98 $query = "SELECT cft.id financial_trxn
99FROM civicrm_financial_trxn cft
100LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.financial_trxn_id = cft.id
101LEFT JOIN civicrm_contribution cc ON ceft.entity_id = cc.id
102WHERE ceft.entity_table = 'civicrm_contribution' AND cft.payment_instrument_id IS NULL;";
103 $dao = CRM_Core_DAO::executeQuery($query);
104 if ($dao->N) {
353ffa53
TO
105 $postUpgradeMessage .= '<br /><br /><strong>' . ts('Your database contains %1 financial transaction records with no payment instrument (Paid By is empty). If you use the Accounting Batches feature this may result in unbalanced transactions. If you do not use this feature, you can ignore the condition (although you will be required to select a Paid By value for new transactions). <a href="%2" target="_blank">You can review steps to correct transactions with missing payment instruments on the wiki.</a>', array(
106 1 => $dao->N,
107 2 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Fixing+Transactions+Missing+a+Payment+Instrument+-+4.4.3+Upgrades'
108 )) . '</strong>';
1543f800
DG
109 }
110 }
9b873358 111 if ($rev == '4.4.6') {
86bfa4f6 112 $postUpgradeMessage .= '<br /><br /><strong>' . ts('Your contact image urls have been upgraded. If your contact image urls did not follow the standard format for image Urls they have not been upgraded. Please check the log to see image urls that were not upgraded.');
5da97e99 113 }
a47a2f90 114 }
115
624e56fa
EM
116 /**
117 * @param $rev
118 *
119 * @return bool
120 */
00be9182 121 public function upgrade_4_4_alpha1($rev) {
634e1a1a 122 // task to process sql
d1401e86 123 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.alpha1')), 'task_4_4_x_runSql', $rev);
a47a2f90 124
125 // Consolidate activity contacts CRM-12274.
d1401e86 126 $this->addTask('Consolidate activity contacts', 'activityContacts');
a47a2f90 127
128 return TRUE;
129 }
130
624e56fa
EM
131 /**
132 * @param $rev
133 */
00be9182 134 public function upgrade_4_4_beta1($rev) {
d1401e86 135 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.beta1')), 'task_4_4_x_runSql', $rev);
7ee2786a 136
56d4e0ab 137 // add new 'data' column in civicrm_batch
138 $query = 'ALTER TABLE civicrm_batch ADD data LONGTEXT NULL COMMENT "cache entered data"';
d427e40e 139 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
56d4e0ab 140
7ee2786a 141 // check if batch entry data exists in civicrm_cache table
f1811020 142 $query = 'SELECT path, data FROM civicrm_cache WHERE group_name = "batch entry"';
7ee2786a 143 $dao = CRM_Core_DAO::executeQuery($query);
144 while ($dao->fetch()) {
145 // get batch id $batchId[2]
146 $batchId = explode('-', $dao->path);
147 $data = unserialize($dao->data);
148
149 // move the data to civicrm_batch table
150 CRM_Core_DAO::setFieldValue('CRM_Batch_DAO_Batch', $batchId[2], 'data', json_encode(array('values' => $data)));
151 }
152
153 // delete entries from civicrm_cache table
f1811020 154 $query = 'DELETE FROM civicrm_cache WHERE group_name = "batch entry"';
7ee2786a 155 CRM_Core_DAO::executeQuery($query);
ba457d64 156
d1401e86 157 $this->addTask('Migrate custom word-replacements', 'wordReplacements');
7ee2786a 158 }
159
624e56fa
EM
160 /**
161 * @param $rev
162 */
00be9182 163 public function upgrade_4_4_1($rev) {
95c0a77c 164 $config = CRM_Core_Config::singleton();
6b12405a
RN
165 // CRM-13327 upgrade handling for the newly added name badges
166 $ogID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'name_badge', 'id', 'name');
167 $nameBadges = array_flip(array_values(CRM_Core_BAO_OptionValue::getOptionValuesAssocArrayFromName('name_badge')));
168 unset($nameBadges['Avery 5395']);
169 if (!empty($nameBadges)) {
170 $dimension = '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":4,"metric":"mm","lMargin":6,"tMargin":19,"SpaceX":0,"SpaceY":0,"width":100,"height":65,"lPadding":0,"tPadding":0}';
171 $query = "UPDATE civicrm_option_value
172 SET value = '{$dimension}'
173 WHERE option_group_id = %1 AND name = 'Fattorini Name Badge 100x65'";
174
175 CRM_Core_DAO::executeQuery($query, array(1 => array($ogID, 'Integer')));
176 }
177 else {
178 $dimensions = array(
179 1 => '{"paper-size":"a4","orientation":"landscape","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":1,"metric":"mm","lMargin":25,"tMargin":27,"SpaceX":0,"SpaceY":35,"width":106,"height":150,"lPadding":5,"tPadding":5}',
180 2 => '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":4,"metric":"mm","lMargin":6,"tMargin":19,"SpaceX":0,"SpaceY":0,"width":100,"height":65,"lPadding":0,"tPadding":0}',
181 3 => '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":2,"metric":"mm","lMargin":10,"tMargin":28,"SpaceX":0,"SpaceY":0,"width":96,"height":121,"lPadding":5,"tPadding":5}',
182 );
183 $insertStatements = array(
184 1 => "($ogID, %1, '{$dimensions[1]}', %1, NULL, 0, NULL, 2, NULL, 0, 0, 1, NULL, NULL)",
185 2 => "($ogID, %2, '{$dimensions[2]}', %2, NULL, 0, NULL, 3, NULL, 0, 0, 1, NULL, NULL)",
186 3 => "($ogID, %3, '{$dimensions[3]}', %3, NULL, 0, NULL, 4, NULL, 0, 0, 1, NULL, NULL)",
187 );
188
189 $queryParams = array(
190 1 => array('A6 Badge Portrait 150x106', 'String'),
191 2 => array('Fattorini Name Badge 100x65', 'String'),
192 3 => array('Hanging Badge 3-3/4" x 4-3"/4', 'String'),
193 );
3a88e331 194
6b12405a
RN
195 foreach ($insertStatements as $values) {
196 $query = 'INSERT INTO civicrm_option_value (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`) VALUES' . $values;
197 CRM_Core_DAO::executeQuery($query, $queryParams);
198 }
199 }
200
95c0a77c
CW
201 // CRM-12578 - Prior to this version a CSS file under drupal would disable core css
202 if (!empty($config->customCSSURL) && strpos($config->userFramework, 'Drupal') === 0) {
203 // The new setting doesn't exist yet - need to create it first
204 CRM_Core_BAO_Setting::updateSettingsFromMetaData();
205 CRM_Core_BAO_Setting::setItem('1', CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'disable_core_css');
206 }
207
fcab62b4
CW
208 // CRM-13701 - Fix $config->timeInputFormat
209 $sql = "
210 SELECT time_format
211 FROM civicrm_preferences_date
212 WHERE time_format IS NOT NULL
213 AND time_format <> ''
214 LIMIT 1
215 ";
216 $timeInputFormat = CRM_Core_DAO::singleValueQuery($sql);
217 if ($timeInputFormat && $timeInputFormat != $config->timeInputFormat) {
218 $params = array('timeInputFormat' => $timeInputFormat);
219 CRM_Core_BAO_ConfigSetting::add($params);
220 }
221
187e382a
PJ
222 // CRM-13698 - add 'Available' and 'No-show' activity statuses
223 $insertStatus = array();
224 $nsinc = $avinc = $inc = 0;
225 if (!CRM_Core_OptionGroup::getValue('activity_status', 'Available', 'name')) {
226 $insertStatus[] = "(%1, 'Available', %2, 'Available', NULL, 0, NULL, %3, 0, 0, 1, NULL, NULL)";
227 $avinc = $inc = 1;
228 }
5b8e40ab
CW
229 if (!CRM_Core_OptionGroup::getValue('activity_status', 'No_show', 'name')) {
230 $insertStatus[] = "(%1, 'No-show', %4, 'No_show', NULL, 0, NULL, %5, 0, 0, 1, NULL, NULL)";
187e382a
PJ
231 $nsinc = $inc + 1;
232 }
233 if (!empty($insertStatus)) {
234 $acOptionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_status', 'id', 'name');
235 $maxVal = CRM_Core_DAO::singleValueQuery("SELECT MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = $acOptionGroupID");
236 $maxWeight = CRM_Core_DAO::singleValueQuery("SELECT MAX(weight) FROM civicrm_option_value WHERE option_group_id = $acOptionGroupID");
237
238 $p[1] = array($acOptionGroupID, 'Integer');
239 if ($avinc) {
e418776c
TO
240 $p[2] = array($avinc + $maxVal, 'Integer');
241 $p[3] = array($avinc + $maxWeight, 'Integer');
187e382a
PJ
242 }
243 if ($nsinc) {
e418776c
TO
244 $p[4] = array($nsinc + $maxVal, 'Integer');
245 $p[5] = array($nsinc + $maxWeight, 'Integer');
187e382a
PJ
246 }
247 $insertStatus = implode(',', $insertStatus);
248
249 $sql = "
250INSERT INTO
251 civicrm_option_value (`option_group_id`, label, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`)
252VALUES {$insertStatus}";
253 CRM_Core_DAO::executeQuery($sql, $p);
254 }
255
6b12405a 256 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.1')), 'task_4_4_x_runSql', $rev);
44379fac 257 $this->addTask('Patch word-replacement schema', 'wordReplacements_patch', $rev);
6b12405a
RN
258 }
259
624e56fa
EM
260 /**
261 * @param $rev
262 *
263 * @return bool
264 */
00be9182 265 public function upgrade_4_4_4($rev) {
23e300df
PJ
266 $fkConstraint = array();
267 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'activity_id')) {
268 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_activity_id` FOREIGN KEY (`activity_id`) REFERENCES `civicrm_activity` (`id`) ON DELETE CASCADE";
269 }
270 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'contact_id')) {
271 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;
272";
273 }
274
275 if (!empty($fkConstraint)) {
276 $fkConstraint = implode(',', $fkConstraint);
277 $sql = "ALTER TABLE `civicrm_activity_contact`
278{$fkConstraint}
279";
280 // CRM-14036 : delete entries of un-mapped contacts
e418776c 281 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
23e300df
PJ
282LEFT JOIN civicrm_contact c
283ON c.id = ac.contact_id
284WHERE c.id IS NULL;
285");
e418776c
TO
286 // delete entries of un-mapped activities
287 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
23e300df
PJ
288LEFT JOIN civicrm_activity a
289ON a.id = ac.activity_id
290WHERE a.id IS NULL;
291");
292
293 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=0;");
294 CRM_Core_DAO::executeQuery($sql);
295 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=1;");
296 }
297
fa4916a4 298 // task to process sql
299 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.4')), 'task_4_4_x_runSql', $rev);
300
7bfaef22 301 // CRM-13892 : add `name` column to dashboard schema
fa4916a4 302 $query = "
303ALTER TABLE civicrm_dashboard
304 ADD name varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Internal name of dashlet.' AFTER domain_id ";
9359d28c 305 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
fa4916a4 306
307 $dashboard = new CRM_Core_DAO_Dashboard();
308 $dashboard->find();
309 while ($dashboard->fetch()) {
310 $urlElements = explode('/', $dashboard->url);
311 if ($urlElements[1] == 'dashlet') {
312 $url = explode('&', $urlElements[2]);
313 $name = $url[0];
314 }
315 elseif ($urlElements[1] == 'report') {
316 $url = explode('&', $urlElements[3]);
86bfa4f6 317 $name = 'report/' . $url[0];
fa4916a4 318 }
319 $values .= "
320 WHEN {$dashboard->id} THEN '{$name}'
321 ";
322 }
323
324 $query = "
325 UPDATE civicrm_dashboard
326 SET name = CASE id
327 {$values}
328 END;
329 ";
9359d28c 330 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
d0f74b53 331
52df1bbd
DG
332 // CRM-13998 : missing alter statements for civicrm_report_instance
333 $this->addTask(ts('Confirm civicrm_report_instance sql table for upgrades'), 'updateReportInstanceTable');
334
f15ec728 335 return TRUE;
fa4916a4 336 }
337
624e56fa
EM
338 /**
339 * @param $rev
340 */
9b873358 341 public function upgrade_4_4_6($rev) {
92fcb95f 342 $sql = "SELECT count(*) AS count FROM INFORMATION_SCHEMA.STATISTICS where " .
92fae7a2 343 "TABLE_SCHEMA = database() AND INDEX_NAME = 'index_image_url' AND TABLE_NAME = 'civicrm_contact';";
e71693e1
JM
344 $dao = CRM_Core_DAO::executeQuery($sql);
345 $dao->fetch();
4014394e 346 if ($dao->count < 1) {
e71693e1
JM
347 $sql = "CREATE INDEX index_image_url ON civicrm_contact (image_url);";
348 $dao = CRM_Core_DAO::executeQuery($sql);
349 }
350 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
351 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
5da97e99
M
352 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
353 $endId = $startId + self::BATCH_SIZE - 1;
354 $title = ts('Upgrade image_urls (%1 => %2)', array(1 => $startId, 2 => $endId));
355 $this->addTask($title, 'upgradeImageUrls', $startId, $endId);
356 }
357 }
358
624e56fa
EM
359 /**
360 * @param CRM_Queue_TaskContext $ctx
100fef9d
CW
361 * @param int $startId
362 * @param int $endId
624e56fa
EM
363 *
364 * @return bool
365 */
00be9182 366 public function upgrade_4_4_7($rev, $originalVer, $latestVer) {
0e19dab5
TO
367 // For WordPress/Joomla(?), cleanup broken image_URL from 4.4.6 upgrades - https://issues.civicrm.org/jira/browse/CRM-14971
368 $exBackendUrl = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=XXX', TRUE); // URL formula from 4.4.6 upgrade
369 $exFrontendUrl = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=XXX', TRUE, NULL, TRUE, TRUE);
370 if ($originalVer == '4.4.6' && $exBackendUrl != $exFrontendUrl) {
371 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
372 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
373 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
374 $endId = $startId + self::BATCH_SIZE - 1;
375 $title = ts('Upgrade image_urls (%1 => %2)', array(1 => $startId, 2 => $endId));
376 $this->addTask($title, 'cleanupBackendImageUrls', $startId, $endId);
377 }
378 }
97f4ef9c 379 $this->addTask(ts('Update saved search information'), 'changeSavedSearch');
0e19dab5
TO
380 }
381
9b873358 382 public static function upgradeImageUrls(CRM_Queue_TaskContext $ctx, $startId, $endId) {
0e19dab5 383 $dao = self::findContactImageUrls($startId, $endId);
5da97e99 384 $failures = array();
9b873358 385 while ($dao->fetch()) {
5da97e99
M
386 $imageURL = $dao->image_url;
387 $baseurl = CIVICRM_UF_BASEURL;
388 $baselen = strlen($baseurl);
9b873358 389 if (substr($imageURL, 0, $baselen) == $baseurl) {
94fbf0d0
ME
390 $photo = basename($dao->image_url);
391 $config = CRM_Core_Config::singleton();
92fcb95f 392 $fullpath = $config->customFileUploadDir . $photo;
9b873358 393 if (file_exists($fullpath)) {
e418776c
TO
394 // For anyone who upgraded 4.4.6 release (eg 4.4.0=>4.4.6), the $newImageUrl incorrectly used backend URLs.
395 // For anyone who skipped 4.4.6 (eg 4.4.0=>4.4.7), the $newImageUrl correctly uses frontend URLs
396 self::setContactImageUrl($dao->id,
353ffa53 397 CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=' . $photo, TRUE, NULL, TRUE, TRUE));
5da97e99 398 }
92e4c2a5 399 else {
e418776c 400 $failures[$dao->id] = $dao->image_url;
94fbf0d0 401 }
5da97e99 402 }
92e4c2a5 403 else {
e418776c
TO
404 $failures[$dao->id] = $dao->image_url;
405 }
406 }
5da97e99
M
407 CRM_Core_Error::debug_var('imageUrlsNotUpgraded', $failures);
408 return TRUE;
409 }
410
00be9182 411 public static function changeSavedSearch(CRM_Queue_TaskContext $ctx) {
97f4ef9c 412 $membershipStatuses = array_flip(CRM_Member_PseudoConstant::membershipStatus());
413
414 $dao = new CRM_Contact_DAO_SavedSearch();
415 $dao->find();
416 while ($dao->fetch()) {
417 $formValues = CRM_Contact_BAO_SavedSearch::getFormValues($dao->id);
418 if (!empty($formValues['mapper'])) {
419 foreach ($formValues['mapper'] as $key => $value) {
420 foreach ($value as $k => $v) {
421 if ($v[0] == 'Membership' && in_array($v[1], array('membership_status', 'membership_status_id'))) {
422 $value = $formValues['value'][$key][$k];
423 $op = $formValues['operator'][$key][$k];
424 if ($op == 'IN') {
425 $value = trim($value);
426 $value = str_replace('(', '', $value);
427 $value = str_replace(')', '', $value);
428
429 $v = explode(',', $value);
430 $value = array();
431 foreach ($v as $k1 => $v2) {
432 if (is_numeric($v2)) {
433 break 2;
434 }
435 $value[$k1] = $membershipStatuses[$v2];
436 }
437 $formValues['value'][$key][$k] = "(" . implode(',', $value) . ")";
438 }
439 elseif (in_array($op, array('=', '!='))) {
440 if (is_numeric($value)) {
441 break;
442 }
443 $formValues['value'][$key][$k] = $membershipStatuses[$value];
444 }
445 }
446 }
447 }
448 $dao->form_values = serialize($formValues);
449 $dao->save();
450 }
451 }
452
453 return TRUE;
454 }
455
0e19dab5
TO
456 /**
457 * For WordPress/Joomla(?) sites which upgraded to 4.4.6, find back-end image_URLs
458 * (e.g. "http://example.com/wp-admin/admin.php?page=CiviCRM&amp;q=civicrm/contact/imagefile&amp;photo=123.jpg")
459 * and convert them to front-end URLs
460 * (e.g. "http://example.com/?page=CiviCRM&amp;q=civicrm/contact/imagefile&amp;photo=123.jpg").
461 *
462 * @param CRM_Queue_TaskContext $ctx
100fef9d
CW
463 * @param int $startId
464 * @param int $endId
0e19dab5
TO
465 * @return bool
466 */
00be9182 467 public static function cleanupBackendImageUrls(CRM_Queue_TaskContext $ctx, $startId, $endId) {
0e19dab5
TO
468 $dao = self::findContactImageUrls($startId, $endId);
469 while ($dao->fetch()) {
470 $imageUrl = str_replace('&amp;', '&', $dao->image_url);
471 if (preg_match(":civicrm/contact/imagefile.*photo=:", $imageUrl)) {
472 // looks like one of ours
473 $imageUrlParts = parse_url($imageUrl);
474 parse_str($imageUrlParts['query'], $imageUrlQuery);
475 self::setContactImageUrl($dao->id,
92fcb95f 476 CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=' . $imageUrlQuery['photo'], TRUE, NULL, TRUE, TRUE));
0e19dab5
TO
477 }
478 }
479 return TRUE;
480 }
481
482 /**
483 * @param int $startId
484 * @param int $endId
485 * @return CRM_Core_DAO columns include "id" and "image_URL"
486 */
487 public static function findContactImageUrls($startId, $endId) {
488 $sql = "
489SELECT id, image_url
490FROM civicrm_contact
491WHERE 1
492AND id BETWEEN %1 AND %2
493AND image_URL IS NOT NULL
494";
495
496 $params = array(
497 1 => array($startId, 'Integer'),
498 2 => array($endId, 'Integer'),
499 );
500 $dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, NULL, FALSE, FALSE);
501 return $dao;
502 }
503
504 /**
505 * @param int $cid
506 * @param string $newImageUrl
507 */
508 public static function setContactImageUrl($cid, $newImageUrl) {
509 $sql = 'UPDATE civicrm_contact SET image_url=%1 WHERE id=%2';
510 $params = array(
511 1 => array($newImageUrl, 'String'),
512 2 => array($cid, 'Integer'),
513 );
514 $updatedao = CRM_Core_DAO::executeQuery($sql, $params);
515 }
516
a47a2f90 517 /**
518 * Update activity contacts CRM-12274
519 *
77b97be7
EM
520 * @param CRM_Queue_TaskContext $ctx
521 *
a6c01b45
CW
522 * @return bool
523 * TRUE for success
a47a2f90 524 */
00be9182 525 public static function activityContacts(CRM_Queue_TaskContext $ctx) {
a47a2f90 526 $upgrade = new CRM_Upgrade_Form();
127ca309 527
e7e657f0 528 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
b95507ab 529 $ovValue[] = $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
530 $ovValue[] = $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
531 $ovValue[] = $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
634e1a1a 532
9744c42c 533 $optionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_contacts', 'id', 'name');
b95507ab 534 if (!empty($ovValue)) {
535 $ovValues = implode(', ', $ovValue);
536 $query = "
634e1a1a 537UPDATE civicrm_option_value
b95507ab 538SET is_reserved = 1
539WHERE option_group_id = {$optionGroupID} AND value IN ($ovValues)";
540
541 $dao = CRM_Core_DAO::executeQuery($query);
542 }
543
9744c42c 544 if (!$assigneeID) {
b95507ab 545 $assigneeID = 1;
9744c42c 546 $value[] = "({$optionGroupID}, 'Activity Assignees', 1, 'Activity Assignees', 1, 1, 1)";
547 }
548 if (!$sourceID) {
b95507ab 549 $sourceID = 2;
9744c42c 550 $value[] = "({$optionGroupID}, 'Activity Source', 2, 'Activity Source', 2, 1, 1)";
551 }
552 if (!$targetID) {
b95507ab 553 $targetID = 3;
9744c42c 554 $value[] = "({$optionGroupID}, 'Activity Targets', 3, 'Activity Targets', 3, 1, 1)";
555 }
556
481a74f4 557 if (!$assigneeID || !$sourceID || !$targetID) {
e418776c 558 $insert = "
9744c42c 559INSERT INTO civicrm_option_value
560(option_group_id, label, value, name, weight, is_reserved, is_active)
561VALUES
562
563";
564 $values = implode(', ', $value);
565 $query = $insert . $values;
566 $dao = CRM_Core_DAO::executeQuery($query);
567 }
568
3a88e331
DL
569 // sometimes an user does not make a clean backup and the above table
570 // already exists, so lets delete this table - CRM-13665
187e382a 571 $query = "DROP TABLE IF EXISTS civicrm_activity_contact";
3a88e331 572 $dao = CRM_Core_DAO::executeQuery($query);
9744c42c 573
a47a2f90 574 $query = "
127ca309 575CREATE TABLE IF NOT EXISTS civicrm_activity_contact (
576 id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Activity contact id',
577 activity_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the activity for this record.',
578 contact_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the contact for this record.',
579 record_type_id int(10) unsigned DEFAULT NULL COMMENT 'The record type id for this row',
580 PRIMARY KEY (id),
581 UNIQUE KEY UI_activity_contact (contact_id,activity_id,record_type_id),
582 KEY FK_civicrm_activity_contact_activity_id (activity_id)
a47a2f90 583) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
584";
585
586 $dao = CRM_Core_DAO::executeQuery($query);
634e1a1a
DL
587
588 $query = "
127ca309 589INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
590SELECT activity_id, target_contact_id, {$targetID} as record_type_id
a47a2f90 591FROM civicrm_activity_target";
592
593 $dao = CRM_Core_DAO::executeQuery($query);
594
634e1a1a 595 $query = "
127ca309 596INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
597SELECT activity_id, assignee_contact_id, {$assigneeID} as record_type_id
a47a2f90 598FROM civicrm_activity_assignment";
599 $dao = CRM_Core_DAO::executeQuery($query);
634e1a1a 600
a47a2f90 601 $query = "
127ca309 602 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
603SELECT id, source_contact_id, {$sourceID} as record_type_id
634e1a1a 604FROM civicrm_activity
a47a2f90 605WHERE source_contact_id IS NOT NULL";
606
607 $dao = CRM_Core_DAO::executeQuery($query);
608
e418776c
TO
609 $query = "DROP TABLE civicrm_activity_target";
610 $dao = CRM_Core_DAO::executeQuery($query);
a47a2f90 611
e418776c
TO
612 $query = "DROP TABLE civicrm_activity_assignment";
613 $dao = CRM_Core_DAO::executeQuery($query);
a47a2f90 614
e418776c 615 $query = "ALTER TABLE civicrm_activity
a47a2f90 616 DROP FOREIGN KEY FK_civicrm_activity_source_contact_id";
634e1a1a 617
e418776c 618 $dao = CRM_Core_DAO::executeQuery($query);
a47a2f90 619
e418776c
TO
620 $query = "ALTER TABLE civicrm_activity DROP COLUMN source_contact_id";
621 $dao = CRM_Core_DAO::executeQuery($query);
a47a2f90 622
e418776c 623 return TRUE;
ba457d64
TO
624 }
625
626 /**
627 * Migrate word-replacements from $config to civicrm_word_replacement
628 *
d0f74b53
EM
629 * @param CRM_Queue_TaskContext $ctx
630 *
a6c01b45
CW
631 * @return bool
632 * TRUE for success
ba457d64
TO
633 * @see http://issues.civicrm.org/jira/browse/CRM-13187
634 */
00be9182 635 public static function wordReplacements(CRM_Queue_TaskContext $ctx) {
ba457d64 636 $query = "
7c312eca
TO
637CREATE TABLE IF NOT EXISTS `civicrm_word_replacement` (
638 `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Word replacement ID',
02ffc0f2
TO
639 `find_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which need to be replaced',
640 `replace_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which will replace the word in find',
7c312eca
TO
641 `is_active` tinyint COMMENT 'Is this entry active?',
642 `match_type` enum('wildcardMatch', 'exactMatch') DEFAULT 'wildcardMatch',
643 `domain_id` int unsigned COMMENT 'FK to Domain ID. This is for Domain specific word replacement',
644 PRIMARY KEY ( `id` ),
44379fac 645 UNIQUE INDEX `UI_domain_find` (domain_id, find_word),
7c312eca
TO
646 CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain`(`id`)
647) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
648 ";
ba457d64
TO
649 $dao = CRM_Core_DAO::executeQuery($query);
650
daa14c0c 651 self::rebuildWordReplacementTable();
ba457d64 652 return TRUE;
a47a2f90 653 }
654
44379fac
TO
655 /**
656 * Fix misconfigured constraints created in 4.4.0. To distinguish the good
657 * and bad configurations, we change the constraint name from "UI_find"
658 * (the original name in 4.4.0) to "UI_domain_find" (the new name in
659 * 4.4.1).
660 *
d0f74b53
EM
661 * @param CRM_Queue_TaskContext $ctx
662 * @param $rev
663 *
a6c01b45
CW
664 * @return bool
665 * TRUE for success
44379fac
TO
666 * @see http://issues.civicrm.org/jira/browse/CRM-13655
667 */
00be9182 668 public static function wordReplacements_patch(CRM_Queue_TaskContext $ctx, $rev) {
44379fac
TO
669 if (CRM_Core_DAO::checkConstraintExists('civicrm_word_replacement', 'UI_find')) {
670 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP FOREIGN KEY FK_civicrm_word_replacement_domain_id;");
671 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY FK_civicrm_word_replacement_domain_id;");
672 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY UI_find;");
673 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement MODIFY COLUMN `find_word` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Word which need to be replaced';");
674 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement MODIFY COLUMN `replace_word` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Word which will replace the word in find';");
675 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT UI_domain_find UNIQUE KEY `UI_domain_find` (`domain_id`,`find_word`);");
676 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain` (`id`);");
677 }
678 return TRUE;
679 }
680
a47a2f90 681 /**
682 * (Queue Task Callback)
683 */
00be9182 684 public static function task_4_4_x_runSql(CRM_Queue_TaskContext $ctx, $rev) {
a47a2f90 685 $upgrade = new CRM_Upgrade_Form();
686 $upgrade->processSQL($rev);
687
688 return TRUE;
689 }
690
691 /**
692 * Syntatic sugar for adding a task which (a) is in this class and (b) has
693 * a high priority.
694 *
695 * After passing the $funcName, you can also pass parameters that will go to
696 * the function. Note that all params must be serializable.
697 */
698 protected function addTask($title, $funcName) {
699 $queue = CRM_Queue_Service::singleton()->load(array(
700 'type' => 'Sql',
701 'name' => CRM_Upgrade_Form::QUEUE_NAME,
702 ));
703
704 $args = func_get_args();
705 $title = array_shift($args);
706 $funcName = array_shift($args);
707 $task = new CRM_Queue_Task(
708 array(get_class($this), $funcName),
709 $args,
710 $title
711 );
712 $queue->createItem($task, array('weight' => -1));
713 }
cbe56ea6
TO
714
715 /**
daa14c0c
TO
716 * Get all the word-replacements stored in config-arrays
717 * and convert them to params for the WordReplacement.create API.
718 *
0f65e834
TO
719 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
720 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
721 * step behaves consistently even as the BAO evolves in future versions.
722 * However, if there's a bug in here prior to 4.4.0, we should apply the
723 * bugfix in both places.
724 *
c68f8bfa
TO
725 * @param bool $rebuildEach
726 * Whether to perform rebuild after each individual API call.
a6c01b45
CW
727 * @return array
728 * Each item is $params for WordReplacement.create
daa14c0c 729 * @see CRM_Core_BAO_WordReplacement::convertConfigArraysToAPIParams
cbe56ea6 730 */
00be9182 731 public static function getConfigArraysAsAPIParams($rebuildEach) {
cbe56ea6 732 $wordReplacementCreateParams = array();
cbe56ea6 733 // get all domains
daa14c0c
TO
734 $result = civicrm_api3('domain', 'get', array(
735 'return' => array('locale_custom_strings'),
736 ));
cbe56ea6
TO
737 if (!empty($result["values"])) {
738 foreach ($result["values"] as $value) {
739 $params = array();
cbe56ea6 740 $params["domain_id"] = $value["id"];
63b71ea8 741 $params["options"] = array('wp-rebuild' => $rebuildEach);
cbe56ea6 742 // unserialize word match string
8f3ccaf0
DG
743 $localeCustomArray = array();
744 if (!empty($value["locale_custom_strings"])) {
745 $localeCustomArray = unserialize($value["locale_custom_strings"]);
746 }
cbe56ea6
TO
747 if (!empty($localeCustomArray)) {
748 $wordMatchArray = array();
7c312eca 749 // Traverse Language array
cbe56ea6 750 foreach ($localeCustomArray as $localCustomData) {
7c312eca
TO
751 // Traverse status array "enabled" "disabled"
752 foreach ($localCustomData as $status => $matchTypes) {
e418776c 753 $params["is_active"] = ($status == "enabled") ? TRUE : FALSE;
7c312eca
TO
754 // Traverse Match Type array "wildcardMatch" "exactMatch"
755 foreach ($matchTypes as $matchType => $words) {
756 $params["match_type"] = $matchType;
757 foreach ($words as $word => $replace) {
758 $params["find_word"] = $word;
759 $params["replace_word"] = $replace;
760 $wordReplacementCreateParams[] = $params;
761 }
762 }
cbe56ea6
TO
763 }
764 }
765 }
766 }
767 }
768 return $wordReplacementCreateParams;
8d57c529 769 }
ba457d64 770
daa14c0c
TO
771 /**
772 * Get all the word-replacements stored in config-arrays
773 * and write them out as records in civicrm_word_replacement.
0f65e834
TO
774 *
775 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
776 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
777 * step behaves consistently even as the BAO evolves in future versions.
778 * However, if there's a bug in here prior to 4.4.0, we should apply the
779 * bugfix in both places.
daa14c0c
TO
780 */
781 public static function rebuildWordReplacementTable() {
782 civicrm_api3('word_replacement', 'replace', array(
783 'options' => array('match' => array('domain_id', 'find_word')),
52592398 784 'values' => array_filter(self::getConfigArraysAsAPIParams(FALSE), array(__CLASS__, 'isValidWordReplacement')),
daa14c0c
TO
785 ));
786 CRM_Core_BAO_WordReplacement::rebuild();
ba457d64 787 }
52df1bbd 788
d0f74b53 789
52df1bbd
DG
790 /***
791 * CRM-13998 missing alter statements for civicrm_report_instance
792 ***/
793 public function updateReportInstanceTable() {
794
d0f74b53 795 // add civicrm_report_instance.name
52df1bbd
DG
796
797 $sql = "SELECT count(*) FROM information_schema.columns "
353ffa53 798 . "WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'name' ";
52df1bbd
DG
799
800 $res = CRM_Core_DAO::singleValueQuery($sql);
801
481a74f4 802 if ($res <= 0) {
52df1bbd
DG
803 $sql = "ALTER TABLE civicrm_report_instance ADD `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'when combined with report_id/template uniquely identifies the instance'";
804 $res = CRM_Core_DAO::executeQuery($sql);
805 }
806
d0f74b53 807 // add civicrm_report_instance args
52df1bbd
DG
808
809 $sql = "SELECT count(*) FROM information_schema.columns WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'args' ";
810
811 $res = CRM_Core_DAO::singleValueQuery($sql);
812
481a74f4 813 if ($res <= 0) {
52df1bbd
DG
814 $sql = "ALTER TABLE civicrm_report_instance ADD `args` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'arguments that are passed in the url when invoking the instance'";
815
816 $res = CRM_Core_DAO::executeQuery($sql);
817 }
818
819 return TRUE;
820 }
52592398
TO
821
822 /**
823 * @param array $params
a6c01b45
CW
824 * @return bool
825 * TRUE if $params is valid
52592398 826 */
00be9182 827 public static function isValidWordReplacement($params) {
89b6dcf0 828 $result = strlen($params['find_word']) <= self::MAX_WORD_REPLACEMENT_SIZE && strlen($params['replace_word']) <= self::MAX_WORD_REPLACEMENT_SIZE;
52592398
TO
829 if (!$result) {
830 CRM_Core_Error::debug_var('invalidWordReplacement', $params);
831 }
832 return $result;
833 }
a47a2f90 834}