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