Fix upgrade for multilingual and have strings as string rather than array
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourSeven.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2016 |
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 * Upgrade logic for 4.7
29 */
30 class CRM_Upgrade_Incremental_php_FourSeven extends CRM_Upgrade_Incremental_Base {
31
32 /**
33 * Compute any messages which should be displayed beforeupgrade.
34 *
35 * Note: This function is called iteratively for each upcoming
36 * revision to the database.
37 *
38 * @param string $preUpgradeMessage
39 * @param string $rev
40 * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
41 * @param null $currentVer
42 */
43 public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
44 if ($rev == '4.7.alpha1') {
45 // CRM-16478 Remove custom fatal error template path option
46 $config = CRM_Core_Config::singleton();
47 if (!empty($config->fatalErrorTemplate) && $config->fatalErrorTemplate != 'CRM/common/fatal.tpl') {
48 $preUpgradeMessage .= '<p>' . ts('The custom fatal error template setting will be removed during the upgrade. You are currently using this custom template: %1 . Following the upgrade you will need to use the standard approach to overriding template files, as described in the documentation.', array(1 => $config->fatalErrorTemplate)) . '</p>';
49 }
50 }
51 if ($rev == '4.7.alpha4') {
52 // CRM-17004 Warn of Moneris removal
53 $count = 1;
54 // Query only works in 4.3+
55 if (version_compare($currentVer, "4.3.0") > 0) {
56 $count = CRM_Core_DAO::singleValueQuery("SELECT COUNT(id) FROM civicrm_payment_processor WHERE payment_processor_type_id IN (SELECT id FROM civicrm_payment_processor_type WHERE name = 'Moneris')");
57 }
58 if ($count && !function_exists('moneris_civicrm_managed')) {
59 $preUpgradeMessage .= '<p>' . ts('The %1 payment processor is no longer bundled with CiviCRM. After upgrading you will need to install the extension to continue using it.', array(1 => 'Moneris')) . '</p>';
60 }
61 }
62 }
63
64 /**
65 * Compute any messages which should be displayed after upgrade.
66 *
67 * @param string $postUpgradeMessage
68 * alterable.
69 * @param string $rev
70 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
71 */
72 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
73 if ($rev == '4.7.alpha1') {
74 $config = CRM_Core_Config::singleton();
75 // FIXME: Performing an upgrade step during postUpgrade message phase is probably bad
76 $editor_id = self::updateWysiwyg();
77 $msg = NULL;
78 $ext_href = 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"';
79 $dsp_href = 'href="' . CRM_Utils_System::url('civicrm/admin/setting/preferences/display', 'reset=1') . '"';
80 $blog_href = 'href="https://civicrm.org/blogs/colemanw/big-changes-wysiwyg-editing-47"';
81 switch ($editor_id) {
82 // TinyMCE
83 case 1:
84 $msg = ts('Your configured editor "TinyMCE" is no longer part of the main CiviCRM download. To continue using it, visit the <a %1>Manage Extensions</a> page to download and install the TinyMCE extension.', array(1 => $ext_href));
85 break;
86
87 // Drupal/Joomla editor
88 case 3:
89 case 4:
90 $msg = ts('CiviCRM no longer integrates with the "%1 Default Editor." Your wysiwyg setting has been reset to the built-in CKEditor. <a %2>Learn more...</a>', array(1 => $config->userFramework, 2 => $blog_href));
91 break;
92 }
93 if ($msg) {
94 $postUpgradeMessage .= '<p>' . $msg . '</p>';
95 }
96 $postUpgradeMessage .= '<p>' . ts('CiviCRM now includes the easy-to-use CKEditor Configurator. To customize the features and display of your wysiwyg editor, visit the <a %1>Display Preferences</a> page. <a %2>Learn more...</a>', array(1 => $dsp_href, 2 => $blog_href)) . '</p>';
97
98 $postUpgradeMessage .= '<br /><br />' . ts('Default version of the following System Workflow Message Templates have been modified: <ul><li>Personal Campaign Pages - Owner Notification</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).');
99
100 $postUpgradeMessage .= '<p>' . ts('The custom fatal error template setting has been removed.') . '</p>';
101 }
102 //if ($rev == '4.7.11') {
103 // $postUpgradeMessage .= '<br /><br />' . ts("WARNING: For increased security, profile submissions embedded in remote sites are no longer allowed to create or edit data by default. If you need to allow users to submit profiles from external sites, you can restore this at Administer > System Settings > Misc (Undelete, PDFs, Limits, Logging, Captcha, etc.) > 'Accept profile submissions from external sites'");
104 //}
105 if ($rev == '4.7.11') {
106 $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly fro SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
107 }
108 }
109
110 /**
111 * Upgrade function.
112 *
113 * @param string $rev
114 */
115 public function upgrade_4_7_alpha1($rev) {
116 $this->addTask('Migrate \'on behalf of\' information to module_data', 'migrateOnBehalfOfInfo');
117 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
118 $this->addTask(ts('Migrate Settings to %1', array(1 => $rev)), 'migrateSettings', $rev);
119 $this->addTask('Add Getting Started dashlet', 'addGettingStartedDashlet', $rev);
120 }
121
122 /**
123 * Upgrade function.
124 *
125 * @param string $rev
126 */
127 public function upgrade_4_7_alpha4($rev) {
128 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
129 $this->addTask(ts('Remove %1', array(1 => 'Moneris')), 'removePaymentProcessorType', 'Moneris');
130 $this->addTask('Update Smart Groups', 'fixContactTypeInSmartGroups');
131 }
132
133 /**
134 * Upgrade function.
135 *
136 * @param string $rev
137 */
138 public function upgrade_4_7_beta2($rev) {
139 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
140 $this->addTask('Delete unused file', 'deleteVersionCheckCacheFile');
141 }
142
143 /**
144 * Upgrade function.
145 *
146 * @param string $rev
147 */
148 public function upgrade_4_7_beta6($rev) {
149 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
150 $this->addTask('Disable flexible jobs extension', 'disableFlexibleJobsExtension');
151 $this->addTask('Add Index to financial_trxn trxn_id field', 'addIndexFinancialTrxnTrxnID');
152 }
153
154 /**
155 * Upgrade function.
156 *
157 * @param string $rev
158 */
159 public function upgrade_4_7_1($rev) {
160 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
161 $this->addTask('Add Index to civicrm_contribution creditnote_id field', 'addIndexContributionCreditNoteID');
162 }
163
164 /**
165 * Upgrade function.
166 *
167 * @param string $rev
168 */
169 public function upgrade_4_7_2($rev) {
170 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
171 $this->addTask('Fix Index on civicrm_financial_item combined entity_id + entity_table', 'addCombinedIndexFinancialItemEntityIDEntityType');
172 $this->addTask('enable financial account relationships for chargeback & refund', 'addRefundAndChargeBackAccountsIfNotExist');
173 $this->addTask('Add Index to civicrm_contribution.source', 'addIndexContributionSource');
174 }
175
176 /**
177 * Upgrade function.
178 *
179 * @param string $rev
180 */
181 public function upgrade_4_7_3($rev) {
182 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
183 $this->addTask('Add Index to civicrm_contribution.total_amount', 'addIndexContributionAmount');
184 }
185
186 /**
187 * Upgrade function.
188 *
189 * @param string $rev
190 */
191 public function upgrade_4_7_4($rev) {
192 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
193 $this->addTask('Add Contact Deleted by Merge Activity Type', 'addDeletedByMergeActivityType');
194 }
195
196 /**
197 * Upgrade function.
198 *
199 * @param string $rev
200 */
201 public function upgrade_4_7_7($rev) {
202 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
203 // https://issues.civicrm.org/jira/browse/CRM-18006
204 if (CRM_Core_DAO::checkTableExists('civicrm_install_canary')) {
205 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_install_canary ENGINE=InnoDB');
206 }
207 }
208
209 /**
210 * Upgrade function.
211 *
212 * @param string $rev
213 */
214 public function upgrade_4_7_8($rev) {
215 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
216 $this->addTask('Upgrade mailing foreign key constraints', 'upgradeMailingFKs');
217 }
218
219 /**
220 * Upgrade function.
221 *
222 * @param string $rev
223 */
224 public function upgrade_4_7_10($rev) {
225 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
226 $this->addTask(ts('Upgrade Add Help Pre and Post Fields to price value table'), 'addHelpPreAndHelpPostFieldsPriceFieldValue');
227 $this->addTask(ts('Alter index and type for image URL'), 'alterIndexAndTypeForImageURL');
228 }
229
230 /**
231 * Upgrade function.
232 *
233 * @param string $rev
234 */
235 public function upgrade_4_7_11($rev) {
236 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
237 $this->addTask('Dashboard schema updates', 'dashboardSchemaUpdate');
238 $this->addTask(ts('Fill in setting "remote_profile_submissions"'), 'migrateRemoteSubmissionsSetting');
239 }
240
241 /**
242 * Upgrade function.
243 *
244 * @param string $rev
245 */
246 public function upgrade_4_7_12($rev) {
247 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
248 $this->addTask(ts('Add Data Type column to civicrm_option_group'), 'addDataTypeColumnToOptionGroupTable');
249 }
250
251 /*
252 * Important! All upgrade functions MUST call the 'runSql' task.
253 * Uncomment and use the following template for a new upgrade version
254 * (change the x in the function name):
255 */
256
257 // /**
258 // * Upgrade function.
259 // *
260 // * @param string $rev
261 // */
262 // public function upgrade_4_7_x($rev) {
263 // $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
264 // // Additional tasks here...
265 // }
266
267 /**
268 * CRM-16354
269 *
270 * @return int
271 */
272 public static function updateWysiwyg() {
273 $editorID = Civi::settings()->get('editor_id');
274 // Previously a numeric value indicated one of 4 wysiwyg editors shipped in core, and no value indicated 'Textarea'
275 // Now the options are "Textarea", "CKEditor", and the rest have been dropped from core.
276 $newEditor = $editorID ? "CKEditor" : "Textarea";
277 Civi::settings()->set('editor_id', $newEditor);
278
279 return $editorID;
280 }
281
282 /**
283 * Migrate any last remaining options from `civicrm_domain.config_backend` to `civicrm_setting`.
284 * Cleanup setting schema.
285 *
286 * @param CRM_Queue_TaskContext $ctx
287 * @return bool
288 */
289 public function migrateSettings(CRM_Queue_TaskContext $ctx) {
290 // Tip: If there are problems with adding the new uniqueness index, try inspecting:
291 // SELECT name, domain_id, contact_id, count(*) AS dupes FROM civicrm_setting cs GROUP BY name, domain_id, contact_id HAVING dupes > 1;
292
293 // Nav records are expendable. https://forum.civicrm.org/index.php?topic=36933.0
294 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE contact_id IS NOT NULL AND name = "navigation"');
295
296 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP INDEX index_group_name');
297 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP COLUMN group_name');
298
299 // Handle Strange activity_tab_filter settings.
300 CRM_Core_DAO::executeQuery('CREATE TABLE civicrm_activity_setting LIKE civicrm_setting');
301 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_activity_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
302 CRM_Core_DAO::executeQuery('INSERT INTO civicrm_activity_setting (name, contact_id, domain_id, value)
303 SELECT DISTINCT name, contact_id, domain_id, value
304 FROM civicrm_setting
305 WHERE name = "activity_tab_filter"
306 AND value is not NULL');
307 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE name = "activity_tab_filter"');
308
309 $date = CRM_Utils_Time::getTime('Y-m-d H:i:s');
310 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
311 CRM_Core_DAO::executeQuery("INSERT INTO civicrm_setting (name, contact_id, domain_id, value, is_domain, created_id, created_date)
312 SELECT name, contact_id, domain_id, value, 0, contact_id,'$date'
313 FROM civicrm_activity_setting
314 WHERE name = 'activity_tab_filter'
315 AND value is not NULL"
316 );
317 CRM_Core_DAO::executeQuery('DROP TABLE civicrm_activity_setting');
318
319 $domainDao = CRM_Core_DAO::executeQuery('SELECT id, config_backend FROM civicrm_domain');
320 while ($domainDao->fetch()) {
321 $settings = CRM_Upgrade_Incremental_php_FourSeven::convertBackendToSettings($domainDao->id, $domainDao->config_backend);
322 CRM_Core_Error::debug_var('convertBackendToSettings', array(
323 'domainId' => $domainDao->id,
324 'backend' => $domainDao->config_backend,
325 'settings' => $settings,
326 ));
327
328 foreach ($settings as $name => $value) {
329 $rowParams = array(
330 1 => array($domainDao->id, 'Positive'),
331 2 => array($name, 'String'),
332 3 => array(serialize($value), 'String'),
333 );
334 $settingId = CRM_Core_DAO::singleValueQuery(
335 'SELECT id FROM civicrm_setting WHERE domain_id = %1 AND name = %2',
336 $rowParams);
337 if (!$settingId) {
338 CRM_Core_DAO::executeQuery(
339 'INSERT INTO civicrm_setting (domain_id, name, value, is_domain) VALUES (%1,%2,%3,1)',
340 $rowParams);
341 }
342 }
343 }
344
345 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_domain DROP COLUMN config_backend');
346
347 return TRUE;
348 }
349
350 /**
351 * Take a config_backend blob and produce an equivalent list of settings.
352 *
353 * @param int $domainId
354 * Domain ID.
355 * @param string $config_backend
356 * Serialized blob.
357 * @return array
358 */
359 public static function convertBackendToSettings($domainId, $config_backend) {
360 if (!$config_backend) {
361 return array();
362 }
363
364 $backend = unserialize($config_backend);
365 if (!$backend) {
366 return array();
367 }
368
369 $mappings = \CRM_Core_Config_MagicMerge::getPropertyMap();
370 $settings = array();
371 foreach ($backend as $propertyName => $propertyValue) {
372 if (isset($mappings[$propertyName][0]) && preg_match('/^setting/', $mappings[$propertyName][0])) {
373 // $mapping format: $propertyName => Array(0 => $type, 1 => $setting|NULL).
374 $settingName = isset($mappings[$propertyName][1]) ? $mappings[$propertyName][1] : $propertyName;
375 $settings[$settingName] = $propertyValue;
376 }
377 }
378
379 return $settings;
380 }
381
382 /**
383 * Add Getting Started dashlet to dashboard
384 *
385 * @param \CRM_Queue_TaskContext $ctx
386 *
387 * @return bool
388 */
389 public function addGettingStartedDashlet(CRM_Queue_TaskContext $ctx) {
390 $sql = "SELECT count(*) FROM civicrm_dashboard WHERE name='getting-started'";
391 $res = CRM_Core_DAO::singleValueQuery($sql);
392 $domainId = CRM_Core_Config::domainID();
393 if ($res <= 0) {
394 $sql = "INSERT INTO `civicrm_dashboard`
395 ( `domain_id`, `name`, `label`, `url`, `permission`, `permission_operator`, `column_no`, `is_minimized`, `is_active`, `weight`, `fullscreen_url`, `is_fullscreen`, `is_reserved`) VALUES ( {$domainId}, 'getting-started', 'Getting Started', 'civicrm/dashlet/getting-started?reset=1&snippet=5', 'access CiviCRM', NULL, 0, 0, 1, 0, 'civicrm/dashlet/getting-started?reset=1&snippet=5&context=dashletFullscreen', 1, 1)";
396 CRM_Core_DAO::executeQuery($sql);
397 // Add default position for Getting Started Dashlet ( left column)
398 $sql = "INSERT INTO `civicrm_dashboard_contact` (dashboard_id, contact_id, column_no, is_active)
399 SELECT (SELECT MAX(id) FROM `civicrm_dashboard`), contact_id, 0, IF (SUM(is_active) > 0, 1, 0)
400 FROM `civicrm_dashboard_contact` JOIN `civicrm_contact` WHERE civicrm_dashboard_contact.contact_id = civicrm_contact.id GROUP BY contact_id";
401 CRM_Core_DAO::executeQuery($sql);
402 }
403 return TRUE;
404 }
405
406 /**
407 * Migrate on-behalf information to uf_join.module_data as on-behalf columns will be dropped
408 * on DB upgrade
409 *
410 * @param CRM_Queue_TaskContext $ctx
411 *
412 * @return bool
413 * TRUE for success
414 */
415 public static function migrateOnBehalfOfInfo(CRM_Queue_TaskContext $ctx) {
416 $domain = new CRM_Core_DAO_Domain();
417 $domain->find(TRUE);
418
419 // fetch onBehalf entry in UFJoin table
420 $ufGroupDAO = new CRM_Core_DAO_UFJoin();
421 $ufGroupDAO->module = 'OnBehalf';
422 $ufGroupDAO->find(TRUE);
423
424 $forOrgColums = array();
425 if ($domain->locales) {
426 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
427 foreach ($locales as $locale) {
428 $forOrgColums[] = "for_organization_{$locale}";
429 }
430 }
431 else {
432 $forOrgColums[] = "for_organization";
433 }
434
435 $query = "
436 SELECT " . implode(", ", $forOrgColums) . ", uj.id as join_id, uj.uf_group_id as uf_group_id
437 FROM civicrm_contribution_page cp
438 INNER JOIN civicrm_uf_join uj ON uj.entity_id = cp.id AND uj.module = 'OnBehalf'";
439 $dao = CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
440
441 if ($dao->N) {
442 while ($dao->fetch()) {
443 $onBehalfParams['on_behalf'] = array('is_for_organization' => $dao->is_for_organization);
444 if ($domain->locales) {
445 foreach ($locales as $locale) {
446 $for_organization = "for_organization_{$locale}";
447 $onBehalfParams['on_behalf'] += array(
448 $locale => array(
449 'for_organization' => $dao->$for_organization,
450 ),
451 );
452 }
453 }
454 else {
455 $onBehalfParams['on_behalf'] += array(
456 'default' => array(
457 'for_organization' => $dao->for_organization,
458 ),
459 );
460 }
461 $ufJoinParam = array(
462 'id' => $dao->join_id,
463 'module' => 'on_behalf',
464 'uf_group_id' => $dao->uf_group_id,
465 'module_data' => json_encode($onBehalfParams),
466 );
467 CRM_Core_BAO_UFJoin::create($ufJoinParam);
468 }
469 }
470
471 return TRUE;
472 }
473
474 /**
475 * v4.7.11 adds a new setting "remote_profile_submissions". This is
476 * long-standing feature that existing sites may be using; however, it's
477 * a bit prone to abuse. For new sites, the default is to disable it
478 * (since that is more secure). For existing sites, the default is to
479 * enable it (since that is more compatible).
480 *
481 * @param \CRM_Queue_TaskContext $ctx
482 *
483 * @return bool
484 */
485 public function migrateRemoteSubmissionsSetting(CRM_Queue_TaskContext $ctx) {
486 $domains = CRM_Core_DAO::executeQuery("SELECT DISTINCT d.id FROM civicrm_domain d LEFT JOIN civicrm_setting s ON d.id=s.domain_id AND s.name = 'remote_profile_submissions' WHERE s.id IS NULL");
487 while ($domains->fetch()) {
488 CRM_Core_DAO::executeQuery(
489 "INSERT INTO civicrm_setting (`name`, `value`, `domain_id`, `is_domain`, `contact_id`, `component_id`, `created_date`, `created_id`)
490 VALUES (%2, %3, %4, %5, NULL, NULL, %6, NULL)",
491 array(
492 2 => array('remote_profile_submissions', 'String'),
493 3 => array('s:1:"1";', 'String'),
494 4 => array($domains->id, 'Integer'),
495 5 => array(1, 'Integer'),
496 6 => array(date('Y-m-d H:i:s'), 'String'),
497 )
498 );
499 }
500 return TRUE;
501 }
502
503 /**
504 * CRM-11782 - Get rid of VALUE_SEPARATOR character in saved search form values
505 *
506 * @param \CRM_Queue_TaskContext $ctx
507 *
508 * @return bool
509 */
510 public function fixContactTypeInSmartGroups(CRM_Queue_TaskContext $ctx) {
511 $sep = CRM_Core_DAO::VALUE_SEPARATOR;
512 $dao = CRM_Core_DAO::executeQuery("SELECT id, form_values FROM civicrm_saved_search WHERE form_values LIKE '%$sep%'");
513 while ($dao->fetch()) {
514 $formValues = unserialize($dao->form_values);
515 if (isset($formValues['contact_type']) && is_array($formValues['contact_type'])) {
516 $newVals = array();
517 foreach ($formValues['contact_type'] as $key => $val) {
518 $newVals[str_replace($sep, '__', $key)] = is_string($val) ? str_replace($sep, '__', $val) : $val;
519 }
520 $formValues['contact_type'] = $newVals;
521 }
522 CRM_Core_DAO::executeQuery("UPDATE civicrm_saved_search SET form_values = %1 WHERE id = {$dao->id}", array(1 => array(serialize($formValues), 'String')));
523 }
524
525 return TRUE;
526 }
527
528 /**
529 * CRM-17637 - Ths file location has been moved; delete the old one
530 *
531 * @param \CRM_Queue_TaskContext $ctx
532 *
533 * @return bool
534 */
535 public function deleteVersionCheckCacheFile(CRM_Queue_TaskContext $ctx) {
536 $config = CRM_Core_Config::singleton();
537 $cacheFile = $config->uploadDir . 'version-info-cache.json';
538 if (file_exists($cacheFile)) {
539 unlink($cacheFile);
540 }
541 return TRUE;
542 }
543
544 /**
545 * CRM-17669 and CRM-17686, make scheduled jobs more flexible, disable the 4.6 extension if installed
546 *
547 * @param \CRM_Queue_TaskContext $ctx
548 *
549 * @return bool
550 */
551 public function disableFlexibleJobsExtension(CRM_Queue_TaskContext $ctx) {
552 try {
553 civicrm_api3('Extension', 'disable', array('key' => 'com.klangsoft.flexiblejobs'));
554 }
555 catch (CiviCRM_API3_Exception $e) {
556 // just ignore if the extension isn't installed
557 }
558
559 return TRUE;
560 }
561
562 /**
563 * CRM-17752 add index to civicrm_financial_trxn.trxn_id (deliberately non-unique).
564 *
565 * @param \CRM_Queue_TaskContext $ctx
566 *
567 * @return bool
568 */
569 public function addIndexFinancialTrxnTrxnID(CRM_Queue_TaskContext $ctx) {
570 $tables = array('civicrm_financial_trxn' => array('trxn_id'));
571 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
572 return TRUE;
573 }
574
575 /**
576 * CRM-17882 Add index to civicrm_contribution.credit_note_id.
577 *
578 * @param \CRM_Queue_TaskContext $ctx
579 *
580 * @return bool
581 */
582 public function addIndexContributionCreditNoteID(CRM_Queue_TaskContext $ctx) {
583 $tables = array('civicrm_contribution' => array('creditnote_id'));
584 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
585 return TRUE;
586 }
587
588 /**
589 * CRM-17775 Add correct index for table civicrm_financial_item.
590 *
591 * Note that the entity ID should always precede the entity_table as
592 * it is more unique. This is better for performance and does not cause fallback
593 * to no index if table it omitted.
594 *
595 * @return bool
596 */
597 public function addCombinedIndexFinancialItemEntityIDEntityType() {
598 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'UI_id');
599 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'IX_Entity');
600 CRM_Core_BAO_SchemaHandler::createIndexes(array(
601 'civicrm_financial_item' => array(array('entity_id', 'entity_table')),
602 ));
603 return TRUE;
604 }
605
606 /**
607 * CRM-17951 Add accounts option values for refund and chargeback.
608 *
609 * Add Chargeback contribution status and Chargeback and Contra account relationships,
610 * checking first if one exists.
611 */
612 public function addRefundAndChargeBackAccountsIfNotExist() {
613 // First we enable and edit the record for Credit contra - this exists but is disabled for most sites.
614 // Using the ensure function (below) will not enabled a disabled option (by design).
615 CRM_Core_DAO::executeQuery("UPDATE civicrm_option_value v
616 INNER JOIN civicrm_option_group g on v.option_group_id=g.id and g.name='account_relationship'
617 SET v.is_active=1, v.label='Credit/Contra Revenue Account is', v.name='Credit/Contra Revenue Account is', v.description='Credit/Contra Revenue Account is'
618 WHERE v.name = 'Credit/Contra Account is';");
619
620 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
621 'option_group_id' => 'account_relationship',
622 'name' => 'Chargeback Account is',
623 'label' => ts('Chargeback Account is'),
624 'is_active' => TRUE,
625 'component_id' => 'CiviContribute',
626 ));
627
628 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
629 'option_group_id' => 'contribution_status',
630 'name' => 'Chargeback',
631 'label' => ts('Chargeback'),
632 'is_active' => TRUE,
633 'component_id' => 'CiviContribute',
634 ));
635 return TRUE;
636 }
637
638 /**
639 * CRM-17999 Add index to civicrm_contribution.source.
640 *
641 * @param \CRM_Queue_TaskContext $ctx
642 *
643 * @return bool
644 */
645 public function addIndexContributionSource(CRM_Queue_TaskContext $ctx) {
646 CRM_Core_BAO_SchemaHandler::createIndexes(array('civicrm_contribution' => array('source')));
647 return TRUE;
648 }
649
650 /**
651 * CRM-18124 Add index to civicrm_contribution.total_amount.
652 *
653 * Note that I made this a combined index with receive_date because the issue included
654 * both criteria and they seemed likely to be used in conjunction to me in other cases.
655 *
656 * @param \CRM_Queue_TaskContext $ctx
657 *
658 * @return bool
659 */
660 public function addIndexContributionAmount(CRM_Queue_TaskContext $ctx) {
661 CRM_Core_BAO_SchemaHandler::createIndexes(array(
662 'civicrm_contribution' => array(array('total_amount', 'receive_date')),
663 ));
664 return TRUE;
665 }
666
667 /**
668 * CRM-18124 Add index to civicrm_contribution.total_amount.
669 *
670 * Note that I made this a combined index with receive_date because the issue included
671 * both criteria and they seemed likely to be used in conjunction to me in other cases.
672 *
673 * @param \CRM_Queue_TaskContext $ctx
674 *
675 * @return bool
676 */
677 public function addDeletedByMergeActivityType(CRM_Queue_TaskContext $ctx) {
678 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
679 'option_group_id' => 'activity_type',
680 'name' => 'Contact Deleted by Merge',
681 'label' => ts('Contact Deleted by Merge'),
682 'description' => ts('Contact was merged into another contact'),
683 'is_active' => TRUE,
684 'filter' => 1,
685 ));
686 return TRUE;
687 }
688
689 /**
690 * CRM-12252 Add Help Pre and Help Post Fields for Price Field Value Table.
691 *
692 * @param \CRM_Queue_TaskContext $ctx
693 *
694 * @return bool
695 */
696 public function addHelpPreAndHelpPostFieldsPriceFieldValue(CRM_Queue_TaskContext $ctx) {
697 $domain = new CRM_Core_DAO_Domain();
698 $domain->find(TRUE);
699 if ($domain->locales) {
700 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
701 foreach ($locales as $locale) {
702 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_pre_{$locale}")) {
703 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
704 ADD COLUMN `help_pre_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'", array(), TRUE, NULL, FALSE, FALSE);
705 }
706 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_post_{$locale}")) {
707 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
708 ADD COLUMN `help_post_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'", array(), TRUE, NULL, FALSE, FALSE);
709 }
710 }
711 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL);
712 }
713 else {
714 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_pre')) {
715 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
716 ADD COLUMN `help_pre` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'");
717 }
718 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_post')) {
719 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
720 ADD COLUMN `help_post` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'");
721 }
722 }
723 return TRUE;
724 }
725
726 /**
727 * CRM-18345 Don't delete mailing data on email/phone deletion
728 * Implemented here in CRM-18526
729 *
730 * @param \CRM_Queue_TaskContext $ctx
731 *
732 * @return bool
733 */
734 public function upgradeMailingFKs(CRM_Queue_TaskContext $ctx) {
735
736 // Safely drop the foreign keys
737 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_email_id');
738 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_phone_id');
739 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_email_id');
740 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_phone_id');
741
742 // Set up the new foreign keys
743 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 0;");
744
745 CRM_Core_DAO::executeQuery("
746 ALTER TABLE `civicrm_mailing_event_queue`
747 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_email_id`
748 FOREIGN KEY (`email_id`)
749 REFERENCES `civicrm_email`(`id`)
750 ON DELETE SET NULL
751 ON UPDATE RESTRICT;
752 ");
753
754 CRM_Core_DAO::executeQuery("
755 ALTER TABLE `civicrm_mailing_event_queue`
756 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_phone_id`
757 FOREIGN KEY (`phone_id`)
758 REFERENCES `civicrm_phone`(`id`)
759 ON DELETE SET NULL
760 ON UPDATE RESTRICT;
761 ");
762
763 CRM_Core_DAO::executeQuery("
764 ALTER TABLE `civicrm_mailing_recipients`
765 ADD CONSTRAINT `FK_civicrm_mailing_recipients_email_id`
766 FOREIGN KEY (`email_id`)
767 REFERENCES `civicrm_email`(`id`)
768 ON DELETE SET NULL
769 ON UPDATE RESTRICT;
770 ");
771
772 CRM_Core_DAO::executeQuery("
773 ALTER TABLE `civicrm_mailing_recipients`
774 ADD CONSTRAINT `FK_civicrm_mailing_recipients_phone_id`
775 FOREIGN KEY (`phone_id`)
776 REFERENCES `civicrm_phone`(`id`)
777 ON DELETE SET NULL
778 ON UPDATE RESTRICT;
779 ");
780
781 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;");
782
783 return TRUE;
784 }
785
786 /**
787 * CRM-17663 - Dashboard schema changes
788 *
789 * @param \CRM_Queue_TaskContext $ctx
790 *
791 * @return bool
792 */
793 public function dashboardSchemaUpdate(CRM_Queue_TaskContext $ctx) {
794 if (!CRM_Core_BAO_SchemaHandler::checkIfIndexExists('civicrm_dashboard_contact', 'index_dashboard_id_contact_id')) {
795 // Delete any stray duplicate rows and add unique index to prevent new dupes and enable INSERT/UPDATE combo query
796 CRM_Core_DAO::executeQuery('DELETE c1 FROM civicrm_dashboard_contact c1, civicrm_dashboard_contact c2 WHERE c1.contact_id = c2.contact_id AND c1.dashboard_id = c2.dashboard_id AND c1.id > c2.id');
797 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dashboard_contact ADD UNIQUE INDEX index_dashboard_id_contact_id (dashboard_id, contact_id);');
798 }
799 $domain = new CRM_Core_DAO_Domain();
800 $domain->find(TRUE);
801 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'content');
802 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_minimized');
803 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_fullscreen');
804 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'created_date');
805 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_fullscreen');
806 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_minimized');
807 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'column_no');
808 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'weight');
809
810 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET url = REPLACE(url, "&snippet=5", ""), fullscreen_url = REPLACE(fullscreen_url, "&snippet=5", "")');
811
812 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dashboard', 'cache_minutes')) {
813 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dashboard ADD COLUMN cache_minutes int unsigned NOT NULL DEFAULT 60 COMMENT "Number of minutes to cache dashlet content in browser localStorage."',
814 array(), TRUE, NULL, FALSE, FALSE);
815 }
816 if ($domain->locales) {
817 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
818 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL);
819 }
820
821 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 1440 WHERE name = "blog"');
822 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 7200 WHERE name IN ("activity","getting-started")');
823 return TRUE;
824 }
825
826 /**
827 * CRM-19100 - Alter Index and Type for Image URL
828 * @return bool
829 */
830 public static function alterIndexAndTypeForImageURL() {
831 $length = array();
832 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_contact', 'index_image_url');
833 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_contact` CHANGE `image_URL` `image_URL` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT 'optional URL for preferred image (photo, logo, etc.) to display for this contact.'");
834
835 $length['civicrm_contact']['image_URL'] = 128;
836 CRM_Core_BAO_SchemaHandler::createIndexes(array('civicrm_contact' => array('image_URL')), 'index', $length);
837
838 return TRUE;
839 }
840
841 /**
842 * CRM-18651 Add DataType column to Option Group Table
843 * @return bool
844 */
845 public static function addDataTypeColumnToOptionGroupTable() {
846 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_option_group', 'data_type')) {
847 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_option_group` ADD COLUMN `data_type` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL comment 'Data Type of Option Group.'",
848 array(), TRUE, NULL, FALSE, FALSE);
849 }
850 $domain = new CRM_Core_DAO_Domain();
851 $domain->find(TRUE);
852 if ($domain->locales) {
853 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
854 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL);
855 }
856
857 CRM_Core_DAO::executeQuery("UPDATE `civicrm_option_group` SET `data_type` = 'Integer'
858 WHERE name IN ('activity_type', 'gender', 'payment_instrument', 'participant_role', 'event_type')");
859 return TRUE;
860 }
861
862 }