bcad6fcf03c1d071d6f0ae55d55b6b761c5719e6
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourFour.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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
30 * @copyright CiviCRM LLC (c) 2004-2014
31 * $Id$
32 *
33 */
34 class CRM_Upgrade_Incremental_php_FourFour {
35 const BATCH_SIZE = 5000;
36
37 const MAX_WORD_REPLACEMENT_SIZE = 255;
38
39 /**
40 * @param $errors
41 *
42 * @return bool
43 */
44 function verifyPreDBstate(&$errors) {
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 *
54 * @param $preUpgradeMessage
55 * @param $rev string, a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'
56 * @param null $currentVer
57 *
58 * @internal param string $postUpgradeMessage , alterable
59 * @return void
60 */
61 function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
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(
72 1 => $oversizedEntries
73 ));
74 }
75 }
76 }
77
78 /**
79 * Compute any messages which should be displayed after upgrade
80 *
81 * @param $postUpgradeMessage string, alterable
82 * @param $rev string, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs
83 * @return void
84 */
85 function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
86 if ($rev == '4.4.1') {
87 $config = CRM_Core_Config::singleton();
88 if (!empty($config->useIDS)) {
89 $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.");
90 }
91 }
92 if ($rev == '4.4.3') {
93 $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).');
94 }
95 if ($rev == '4.4.3') {
96 $query = "SELECT cft.id financial_trxn
97 FROM civicrm_financial_trxn cft
98 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.financial_trxn_id = cft.id
99 LEFT JOIN civicrm_contribution cc ON ceft.entity_id = cc.id
100 WHERE ceft.entity_table = 'civicrm_contribution' AND cft.payment_instrument_id IS NULL;";
101 $dao = CRM_Core_DAO::executeQuery($query);
102 if ($dao->N) {
103 $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>';
104 }
105 }
106 if ($rev == '4.4.6'){
107 $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.');
108 }
109 }
110
111 /**
112 * @param $rev
113 *
114 * @return bool
115 */
116 function upgrade_4_4_alpha1($rev) {
117 // task to process sql
118 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.alpha1')), 'task_4_4_x_runSql', $rev);
119
120 // Consolidate activity contacts CRM-12274.
121 $this->addTask('Consolidate activity contacts', 'activityContacts');
122
123 return TRUE;
124 }
125
126 /**
127 * @param $rev
128 */
129 function upgrade_4_4_beta1($rev) {
130 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.beta1')), 'task_4_4_x_runSql', $rev);
131
132 // add new 'data' column in civicrm_batch
133 $query = 'ALTER TABLE civicrm_batch ADD data LONGTEXT NULL COMMENT "cache entered data"';
134 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
135
136 // check if batch entry data exists in civicrm_cache table
137 $query = 'SELECT path, data FROM civicrm_cache WHERE group_name = "batch entry"';
138 $dao = CRM_Core_DAO::executeQuery($query);
139 while ($dao->fetch()) {
140 // get batch id $batchId[2]
141 $batchId = explode('-', $dao->path);
142 $data = unserialize($dao->data);
143
144 // move the data to civicrm_batch table
145 CRM_Core_DAO::setFieldValue('CRM_Batch_DAO_Batch', $batchId[2], 'data', json_encode(array('values' => $data)));
146 }
147
148 // delete entries from civicrm_cache table
149 $query = 'DELETE FROM civicrm_cache WHERE group_name = "batch entry"';
150 CRM_Core_DAO::executeQuery($query);
151
152 $this->addTask('Migrate custom word-replacements', 'wordReplacements');
153 }
154
155 /**
156 * @param $rev
157 */
158 function upgrade_4_4_1($rev) {
159 $config = CRM_Core_Config::singleton();
160 // CRM-13327 upgrade handling for the newly added name badges
161 $ogID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'name_badge', 'id', 'name');
162 $nameBadges = array_flip(array_values(CRM_Core_BAO_OptionValue::getOptionValuesAssocArrayFromName('name_badge')));
163 unset($nameBadges['Avery 5395']);
164 if (!empty($nameBadges)) {
165 $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}';
166 $query = "UPDATE civicrm_option_value
167 SET value = '{$dimension}'
168 WHERE option_group_id = %1 AND name = 'Fattorini Name Badge 100x65'";
169
170 CRM_Core_DAO::executeQuery($query, array(1 => array($ogID, 'Integer')));
171 }
172 else {
173 $dimensions = array(
174 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}',
175 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}',
176 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}',
177 );
178 $insertStatements = array(
179 1 => "($ogID, %1, '{$dimensions[1]}', %1, NULL, 0, NULL, 2, NULL, 0, 0, 1, NULL, NULL)",
180 2 => "($ogID, %2, '{$dimensions[2]}', %2, NULL, 0, NULL, 3, NULL, 0, 0, 1, NULL, NULL)",
181 3 => "($ogID, %3, '{$dimensions[3]}', %3, NULL, 0, NULL, 4, NULL, 0, 0, 1, NULL, NULL)",
182 );
183
184 $queryParams = array(
185 1 => array('A6 Badge Portrait 150x106', 'String'),
186 2 => array('Fattorini Name Badge 100x65', 'String'),
187 3 => array('Hanging Badge 3-3/4" x 4-3"/4', 'String'),
188 );
189
190 foreach ($insertStatements as $values) {
191 $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;
192 CRM_Core_DAO::executeQuery($query, $queryParams);
193 }
194 }
195
196 // CRM-12578 - Prior to this version a CSS file under drupal would disable core css
197 if (!empty($config->customCSSURL) && strpos($config->userFramework, 'Drupal') === 0) {
198 // The new setting doesn't exist yet - need to create it first
199 CRM_Core_BAO_Setting::updateSettingsFromMetaData();
200 CRM_Core_BAO_Setting::setItem('1', CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'disable_core_css');
201 }
202
203 // CRM-13701 - Fix $config->timeInputFormat
204 $sql = "
205 SELECT time_format
206 FROM civicrm_preferences_date
207 WHERE time_format IS NOT NULL
208 AND time_format <> ''
209 LIMIT 1
210 ";
211 $timeInputFormat = CRM_Core_DAO::singleValueQuery($sql);
212 if ($timeInputFormat && $timeInputFormat != $config->timeInputFormat) {
213 $params = array('timeInputFormat' => $timeInputFormat);
214 CRM_Core_BAO_ConfigSetting::add($params);
215 }
216
217 // CRM-13698 - add 'Available' and 'No-show' activity statuses
218 $insertStatus = array();
219 $nsinc = $avinc = $inc = 0;
220 if (!CRM_Core_OptionGroup::getValue('activity_status', 'Available', 'name')) {
221 $insertStatus[] = "(%1, 'Available', %2, 'Available', NULL, 0, NULL, %3, 0, 0, 1, NULL, NULL)";
222 $avinc = $inc = 1;
223 }
224 if (!CRM_Core_OptionGroup::getValue('activity_status', 'No_show', 'name')) {
225 $insertStatus[] = "(%1, 'No-show', %4, 'No_show', NULL, 0, NULL, %5, 0, 0, 1, NULL, NULL)";
226 $nsinc = $inc + 1;
227 }
228 if (!empty($insertStatus)) {
229 $acOptionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_status', 'id', 'name');
230 $maxVal = CRM_Core_DAO::singleValueQuery("SELECT MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = $acOptionGroupID");
231 $maxWeight = CRM_Core_DAO::singleValueQuery("SELECT MAX(weight) FROM civicrm_option_value WHERE option_group_id = $acOptionGroupID");
232
233 $p[1] = array($acOptionGroupID, 'Integer');
234 if ($avinc) {
235 $p[2] = array($avinc+$maxVal, 'Integer');
236 $p[3] = array($avinc+$maxWeight, 'Integer');
237 }
238 if ($nsinc) {
239 $p[4] = array($nsinc+$maxVal, 'Integer');
240 $p[5] = array($nsinc+$maxWeight, 'Integer');
241 }
242 $insertStatus = implode(',', $insertStatus);
243
244 $sql = "
245 INSERT INTO
246 civicrm_option_value (`option_group_id`, label, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`)
247 VALUES {$insertStatus}";
248 CRM_Core_DAO::executeQuery($sql, $p);
249 }
250
251 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.1')), 'task_4_4_x_runSql', $rev);
252 $this->addTask('Patch word-replacement schema', 'wordReplacements_patch', $rev);
253 }
254
255 /**
256 * @param $rev
257 *
258 * @return bool
259 */
260 function upgrade_4_4_4($rev) {
261 $fkConstraint = array();
262 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'activity_id')) {
263 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_activity_id` FOREIGN KEY (`activity_id`) REFERENCES `civicrm_activity` (`id`) ON DELETE CASCADE";
264 }
265 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'contact_id')) {
266 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;
267 ";
268 }
269
270 if (!empty($fkConstraint)) {
271 $fkConstraint = implode(',', $fkConstraint);
272 $sql = "ALTER TABLE `civicrm_activity_contact`
273 {$fkConstraint}
274 ";
275 // CRM-14036 : delete entries of un-mapped contacts
276 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
277 LEFT JOIN civicrm_contact c
278 ON c.id = ac.contact_id
279 WHERE c.id IS NULL;
280 ");
281 // delete entries of un-mapped activities
282 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
283 LEFT JOIN civicrm_activity a
284 ON a.id = ac.activity_id
285 WHERE a.id IS NULL;
286 ");
287
288 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=0;");
289 CRM_Core_DAO::executeQuery($sql);
290 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=1;");
291 }
292
293 // task to process sql
294 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.4')), 'task_4_4_x_runSql', $rev);
295
296 // CRM-13892 : add `name` column to dashboard schema
297 $query = "
298 ALTER TABLE civicrm_dashboard
299 ADD name varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Internal name of dashlet.' AFTER domain_id ";
300 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
301
302 $dashboard = new CRM_Core_DAO_Dashboard();
303 $dashboard->find();
304 while ($dashboard->fetch()) {
305 $urlElements = explode('/', $dashboard->url);
306 if ($urlElements[1] == 'dashlet') {
307 $url = explode('&', $urlElements[2]);
308 $name = $url[0];
309 }
310 elseif ($urlElements[1] == 'report') {
311 $url = explode('&', $urlElements[3]);
312 $name = 'report/' .$url[0];
313 }
314 $values .= "
315 WHEN {$dashboard->id} THEN '{$name}'
316 ";
317 }
318
319 $query = "
320 UPDATE civicrm_dashboard
321 SET name = CASE id
322 {$values}
323 END;
324 ";
325 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
326
327 // CRM-13998 : missing alter statements for civicrm_report_instance
328 $this->addTask(ts('Confirm civicrm_report_instance sql table for upgrades'), 'updateReportInstanceTable');
329
330
331 return TRUE;
332 }
333
334 /**
335 * @param $rev
336 */
337 function upgrade_4_4_6($rev){
338 $sql = "SELECT count(*) AS count FROM INFORMATION_SCHEMA.STATISTICS where ".
339 "TABLE_SCHEMA = database() AND INDEX_NAME = 'index_image_url' AND TABLE_NAME = 'civicrm_contact';";
340 $dao = CRM_Core_DAO::executeQuery($sql);
341 $dao->fetch();
342 if ($dao->count < 1) {
343 $sql = "CREATE INDEX index_image_url ON civicrm_contact (image_url);";
344 $dao = CRM_Core_DAO::executeQuery($sql);
345 }
346 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
347 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
348 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
349 $endId = $startId + self::BATCH_SIZE - 1;
350 $title = ts('Upgrade image_urls (%1 => %2)', array(1 => $startId, 2 => $endId));
351 $this->addTask($title, 'upgradeImageUrls', $startId, $endId);
352 }
353 }
354
355 /**
356 * @param CRM_Queue_TaskContext $ctx
357 * @param $startId
358 * @param $endId
359 *
360 * @return bool
361 */
362 static function upgradeImageUrls(CRM_Queue_TaskContext $ctx, $startId, $endId){
363 $sql = "
364 SELECT id, image_url
365 FROM civicrm_contact
366 WHERE 1
367 AND id BETWEEN %1 AND %2
368 AND image_URL IS NOT NULL
369 ";
370 $params = array(
371 1 => array($startId, 'Integer'),
372 2 => array($endId, 'Integer'),
373 );
374 $dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, NULL, FALSE, FALSE);
375 $failures = array();
376 while ($dao->fetch()){
377 $imageURL = $dao->image_url;
378 $baseurl = CIVICRM_UF_BASEURL;
379 $baselen = strlen($baseurl);
380 if (substr($imageURL, 0, $baselen)==$baseurl){
381 $photo = basename($dao->image_url);
382 $config = CRM_Core_Config::singleton();
383 $fullpath = $config->customFileUploadDir.$photo;
384 if (file_exists($fullpath)){
385 $newimageurl = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo='.$photo, TRUE);
386 $sql = 'UPDATE civicrm_contact SET image_url=%1 WHERE id=%2';
387 $params = array(
388 1 => array($newimageurl, 'String'),
389 2 => array($dao->id, 'Integer'),
390 );
391 $updatedao = CRM_Core_DAO::executeQuery($sql, $params);
392 }
393 else{
394 $failures[$dao->id] = $dao->image_url;
395 }
396 }
397 else{
398 $failures[$dao->id] = $dao->image_url;
399 }
400 }
401 CRM_Core_Error::debug_var('imageUrlsNotUpgraded', $failures);
402 return TRUE;
403 }
404
405 /**
406 * Update activity contacts CRM-12274
407 *
408 * @param CRM_Queue_TaskContext $ctx
409 *
410 * @return bool TRUE for success
411 */
412 static function activityContacts(CRM_Queue_TaskContext $ctx) {
413 $upgrade = new CRM_Upgrade_Form();
414
415 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
416 $ovValue[] = $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
417 $ovValue[] = $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
418 $ovValue[] = $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
419
420 $optionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_contacts', 'id', 'name');
421 if (!empty($ovValue)) {
422 $ovValues = implode(', ', $ovValue);
423 $query = "
424 UPDATE civicrm_option_value
425 SET is_reserved = 1
426 WHERE option_group_id = {$optionGroupID} AND value IN ($ovValues)";
427
428 $dao = CRM_Core_DAO::executeQuery($query);
429 }
430
431 if (!$assigneeID) {
432 $assigneeID = 1;
433 $value[] = "({$optionGroupID}, 'Activity Assignees', 1, 'Activity Assignees', 1, 1, 1)";
434 }
435 if (!$sourceID) {
436 $sourceID = 2;
437 $value[] = "({$optionGroupID}, 'Activity Source', 2, 'Activity Source', 2, 1, 1)";
438 }
439 if (!$targetID) {
440 $targetID = 3;
441 $value[] = "({$optionGroupID}, 'Activity Targets', 3, 'Activity Targets', 3, 1, 1)";
442 }
443
444 if (!$assigneeID || !$sourceID || !$targetID ) {
445 $insert = "
446 INSERT INTO civicrm_option_value
447 (option_group_id, label, value, name, weight, is_reserved, is_active)
448 VALUES
449
450 ";
451 $values = implode(', ', $value);
452 $query = $insert . $values;
453 $dao = CRM_Core_DAO::executeQuery($query);
454 }
455
456 // sometimes an user does not make a clean backup and the above table
457 // already exists, so lets delete this table - CRM-13665
458 $query = "DROP TABLE IF EXISTS civicrm_activity_contact";
459 $dao = CRM_Core_DAO::executeQuery($query);
460
461 $query = "
462 CREATE TABLE IF NOT EXISTS civicrm_activity_contact (
463 id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Activity contact id',
464 activity_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the activity for this record.',
465 contact_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the contact for this record.',
466 record_type_id int(10) unsigned DEFAULT NULL COMMENT 'The record type id for this row',
467 PRIMARY KEY (id),
468 UNIQUE KEY UI_activity_contact (contact_id,activity_id,record_type_id),
469 KEY FK_civicrm_activity_contact_activity_id (activity_id)
470 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
471 ";
472
473 $dao = CRM_Core_DAO::executeQuery($query);
474
475
476 $query = "
477 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
478 SELECT activity_id, target_contact_id, {$targetID} as record_type_id
479 FROM civicrm_activity_target";
480
481 $dao = CRM_Core_DAO::executeQuery($query);
482
483 $query = "
484 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
485 SELECT activity_id, assignee_contact_id, {$assigneeID} as record_type_id
486 FROM civicrm_activity_assignment";
487 $dao = CRM_Core_DAO::executeQuery($query);
488
489 $query = "
490 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
491 SELECT id, source_contact_id, {$sourceID} as record_type_id
492 FROM civicrm_activity
493 WHERE source_contact_id IS NOT NULL";
494
495 $dao = CRM_Core_DAO::executeQuery($query);
496
497 $query = "DROP TABLE civicrm_activity_target";
498 $dao = CRM_Core_DAO::executeQuery($query);
499
500 $query = "DROP TABLE civicrm_activity_assignment";
501 $dao = CRM_Core_DAO::executeQuery($query);
502
503 $query = "ALTER TABLE civicrm_activity
504 DROP FOREIGN KEY FK_civicrm_activity_source_contact_id";
505
506 $dao = CRM_Core_DAO::executeQuery($query);
507
508 $query = "ALTER TABLE civicrm_activity DROP COLUMN source_contact_id";
509 $dao = CRM_Core_DAO::executeQuery($query);
510
511 return TRUE;
512 }
513
514 /**
515 * Migrate word-replacements from $config to civicrm_word_replacement
516 *
517 * @param CRM_Queue_TaskContext $ctx
518 *
519 * @return bool TRUE for success
520 * @see http://issues.civicrm.org/jira/browse/CRM-13187
521 */
522 static function wordReplacements(CRM_Queue_TaskContext $ctx) {
523 $query = "
524 CREATE TABLE IF NOT EXISTS `civicrm_word_replacement` (
525 `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Word replacement ID',
526 `find_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which need to be replaced',
527 `replace_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which will replace the word in find',
528 `is_active` tinyint COMMENT 'Is this entry active?',
529 `match_type` enum('wildcardMatch', 'exactMatch') DEFAULT 'wildcardMatch',
530 `domain_id` int unsigned COMMENT 'FK to Domain ID. This is for Domain specific word replacement',
531 PRIMARY KEY ( `id` ),
532 UNIQUE INDEX `UI_domain_find` (domain_id, find_word),
533 CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain`(`id`)
534 ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
535 ";
536 $dao = CRM_Core_DAO::executeQuery($query);
537
538 self::rebuildWordReplacementTable();
539 return TRUE;
540 }
541
542 /**
543 * Fix misconfigured constraints created in 4.4.0. To distinguish the good
544 * and bad configurations, we change the constraint name from "UI_find"
545 * (the original name in 4.4.0) to "UI_domain_find" (the new name in
546 * 4.4.1).
547 *
548 * @param CRM_Queue_TaskContext $ctx
549 * @param $rev
550 *
551 * @return bool TRUE for success
552 * @see http://issues.civicrm.org/jira/browse/CRM-13655
553 */
554 static function wordReplacements_patch(CRM_Queue_TaskContext $ctx, $rev) {
555 if (CRM_Core_DAO::checkConstraintExists('civicrm_word_replacement', 'UI_find')) {
556 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP FOREIGN KEY FK_civicrm_word_replacement_domain_id;");
557 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY FK_civicrm_word_replacement_domain_id;");
558 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY UI_find;");
559 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';");
560 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';");
561 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT UI_domain_find UNIQUE KEY `UI_domain_find` (`domain_id`,`find_word`);");
562 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`);");
563 }
564 return TRUE;
565 }
566
567 /**
568 * (Queue Task Callback)
569 */
570 static function task_4_4_x_runSql(CRM_Queue_TaskContext $ctx, $rev) {
571 $upgrade = new CRM_Upgrade_Form();
572 $upgrade->processSQL($rev);
573
574 return TRUE;
575 }
576
577 /**
578 * Syntatic sugar for adding a task which (a) is in this class and (b) has
579 * a high priority.
580 *
581 * After passing the $funcName, you can also pass parameters that will go to
582 * the function. Note that all params must be serializable.
583 */
584 protected function addTask($title, $funcName) {
585 $queue = CRM_Queue_Service::singleton()->load(array(
586 'type' => 'Sql',
587 'name' => CRM_Upgrade_Form::QUEUE_NAME,
588 ));
589
590 $args = func_get_args();
591 $title = array_shift($args);
592 $funcName = array_shift($args);
593 $task = new CRM_Queue_Task(
594 array(get_class($this), $funcName),
595 $args,
596 $title
597 );
598 $queue->createItem($task, array('weight' => -1));
599 }
600
601 /**
602 * Get all the word-replacements stored in config-arrays
603 * and convert them to params for the WordReplacement.create API.
604 *
605 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
606 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
607 * step behaves consistently even as the BAO evolves in future versions.
608 * However, if there's a bug in here prior to 4.4.0, we should apply the
609 * bugfix in both places.
610 *
611 * @param bool $rebuildEach whether to perform rebuild after each individual API call
612 * @return array Each item is $params for WordReplacement.create
613 * @see CRM_Core_BAO_WordReplacement::convertConfigArraysToAPIParams
614 */
615 static function getConfigArraysAsAPIParams($rebuildEach) {
616 $wordReplacementCreateParams = array();
617 // get all domains
618 $result = civicrm_api3('domain', 'get', array(
619 'return' => array('locale_custom_strings'),
620 ));
621 if (!empty($result["values"])) {
622 foreach ($result["values"] as $value) {
623 $params = array();
624 $params["domain_id"] = $value["id"];
625 $params["options"] = array('wp-rebuild' => $rebuildEach);
626 // unserialize word match string
627 $localeCustomArray = array();
628 if (!empty($value["locale_custom_strings"])) {
629 $localeCustomArray = unserialize($value["locale_custom_strings"]);
630 }
631 if (!empty($localeCustomArray)) {
632 $wordMatchArray = array();
633 // Traverse Language array
634 foreach ($localeCustomArray as $localCustomData) {
635 // Traverse status array "enabled" "disabled"
636 foreach ($localCustomData as $status => $matchTypes) {
637 $params["is_active"] = ($status == "enabled")?TRUE:FALSE;
638 // Traverse Match Type array "wildcardMatch" "exactMatch"
639 foreach ($matchTypes as $matchType => $words) {
640 $params["match_type"] = $matchType;
641 foreach ($words as $word => $replace) {
642 $params["find_word"] = $word;
643 $params["replace_word"] = $replace;
644 $wordReplacementCreateParams[] = $params;
645 }
646 }
647 }
648 }
649 }
650 }
651 }
652 return $wordReplacementCreateParams;
653 }
654
655 /**
656 * Get all the word-replacements stored in config-arrays
657 * and write them out as records in civicrm_word_replacement.
658 *
659 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
660 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
661 * step behaves consistently even as the BAO evolves in future versions.
662 * However, if there's a bug in here prior to 4.4.0, we should apply the
663 * bugfix in both places.
664 */
665 public static function rebuildWordReplacementTable() {
666 civicrm_api3('word_replacement', 'replace', array(
667 'options' => array('match' => array('domain_id', 'find_word')),
668 'values' => array_filter(self::getConfigArraysAsAPIParams(FALSE), array(__CLASS__, 'isValidWordReplacement')),
669 ));
670 CRM_Core_BAO_WordReplacement::rebuild();
671 }
672
673
674 /***
675 * CRM-13998 missing alter statements for civicrm_report_instance
676 ***/
677 public function updateReportInstanceTable() {
678
679 // add civicrm_report_instance.name
680
681 $sql = "SELECT count(*) FROM information_schema.columns "
682 . "WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'name' ";
683
684 $res = CRM_Core_DAO::singleValueQuery($sql);
685
686 if ($res <= 0 ) {
687 $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'";
688 $res = CRM_Core_DAO::executeQuery($sql);
689 }
690
691 // add civicrm_report_instance args
692
693 $sql = "SELECT count(*) FROM information_schema.columns WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'args' ";
694
695 $res = CRM_Core_DAO::singleValueQuery($sql);
696
697 if ($res <= 0 ) {
698 $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'";
699
700 $res = CRM_Core_DAO::executeQuery($sql);
701 }
702
703 return TRUE;
704 }
705
706 /**
707 * @param array $params
708 * @return bool TRUE if $params is valid
709 */
710 static function isValidWordReplacement($params) {
711 $result = strlen($params['find_word']) <= self::MAX_WORD_REPLACEMENT_SIZE && strlen($params['replace_word']) > self::MAX_WORD_REPLACEMENT_SIZE;
712 if (!$result) {
713 CRM_Core_Error::debug_var('invalidWordReplacement', $params);
714 }
715 return $result;
716 }
717 }