Rebuild localisation schema after dropping column
[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 * Important! All upgrade functions MUST call the 'runSql' task.
243 * Uncomment and use the following template for a new upgrade version
244 * (change the x in the function name):
245 */
246
247 // /**
248 // * Upgrade function.
249 // *
250 // * @param string $rev
251 // */
252 // public function upgrade_4_7_x($rev) {
253 // $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
254 // // Additional tasks here...
255 // }
256
257 /**
258 * CRM-16354
259 *
260 * @return int
261 */
262 public static function updateWysiwyg() {
263 $editorID = Civi::settings()->get('editor_id');
264 // Previously a numeric value indicated one of 4 wysiwyg editors shipped in core, and no value indicated 'Textarea'
265 // Now the options are "Textarea", "CKEditor", and the rest have been dropped from core.
266 $newEditor = $editorID ? "CKEditor" : "Textarea";
267 Civi::settings()->set('editor_id', $newEditor);
268
269 return $editorID;
270 }
271
272 /**
273 * Migrate any last remaining options from `civicrm_domain.config_backend` to `civicrm_setting`.
274 * Cleanup setting schema.
275 *
276 * @param CRM_Queue_TaskContext $ctx
277 * @return bool
278 */
279 public function migrateSettings(CRM_Queue_TaskContext $ctx) {
280 // Tip: If there are problems with adding the new uniqueness index, try inspecting:
281 // SELECT name, domain_id, contact_id, count(*) AS dupes FROM civicrm_setting cs GROUP BY name, domain_id, contact_id HAVING dupes > 1;
282
283 // Nav records are expendable. https://forum.civicrm.org/index.php?topic=36933.0
284 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE contact_id IS NOT NULL AND name = "navigation"');
285
286 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP INDEX index_group_name');
287 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP COLUMN group_name');
288
289 // Handle Strange activity_tab_filter settings.
290 CRM_Core_DAO::executeQuery('CREATE TABLE civicrm_activity_setting LIKE civicrm_setting');
291 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_activity_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
292 CRM_Core_DAO::executeQuery('INSERT INTO civicrm_activity_setting (name, contact_id, domain_id, value)
293 SELECT DISTINCT name, contact_id, domain_id, value
294 FROM civicrm_setting
295 WHERE name = "activity_tab_filter"
296 AND value is not NULL');
297 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE name = "activity_tab_filter"');
298
299 $date = CRM_Utils_Time::getTime('Y-m-d H:i:s');
300 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
301 CRM_Core_DAO::executeQuery("INSERT INTO civicrm_setting (name, contact_id, domain_id, value, is_domain, created_id, created_date)
302 SELECT name, contact_id, domain_id, value, 0, contact_id,'$date'
303 FROM civicrm_activity_setting
304 WHERE name = 'activity_tab_filter'
305 AND value is not NULL"
306 );
307 CRM_Core_DAO::executeQuery('DROP TABLE civicrm_activity_setting');
308
309 $domainDao = CRM_Core_DAO::executeQuery('SELECT id, config_backend FROM civicrm_domain');
310 while ($domainDao->fetch()) {
311 $settings = CRM_Upgrade_Incremental_php_FourSeven::convertBackendToSettings($domainDao->id, $domainDao->config_backend);
312 CRM_Core_Error::debug_var('convertBackendToSettings', array(
313 'domainId' => $domainDao->id,
314 'backend' => $domainDao->config_backend,
315 'settings' => $settings,
316 ));
317
318 foreach ($settings as $name => $value) {
319 $rowParams = array(
320 1 => array($domainDao->id, 'Positive'),
321 2 => array($name, 'String'),
322 3 => array(serialize($value), 'String'),
323 );
324 $settingId = CRM_Core_DAO::singleValueQuery(
325 'SELECT id FROM civicrm_setting WHERE domain_id = %1 AND name = %2',
326 $rowParams);
327 if (!$settingId) {
328 CRM_Core_DAO::executeQuery(
329 'INSERT INTO civicrm_setting (domain_id, name, value, is_domain) VALUES (%1,%2,%3,1)',
330 $rowParams);
331 }
332 }
333 }
334
335 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_domain DROP COLUMN config_backend');
336
337 return TRUE;
338 }
339
340 /**
341 * Take a config_backend blob and produce an equivalent list of settings.
342 *
343 * @param int $domainId
344 * Domain ID.
345 * @param string $config_backend
346 * Serialized blob.
347 * @return array
348 */
349 public static function convertBackendToSettings($domainId, $config_backend) {
350 if (!$config_backend) {
351 return array();
352 }
353
354 $backend = unserialize($config_backend);
355 if (!$backend) {
356 return array();
357 }
358
359 $mappings = \CRM_Core_Config_MagicMerge::getPropertyMap();
360 $settings = array();
361 foreach ($backend as $propertyName => $propertyValue) {
362 if (isset($mappings[$propertyName][0]) && preg_match('/^setting/', $mappings[$propertyName][0])) {
363 // $mapping format: $propertyName => Array(0 => $type, 1 => $setting|NULL).
364 $settingName = isset($mappings[$propertyName][1]) ? $mappings[$propertyName][1] : $propertyName;
365 $settings[$settingName] = $propertyValue;
366 }
367 }
368
369 return $settings;
370 }
371
372 /**
373 * Add Getting Started dashlet to dashboard
374 *
375 * @param \CRM_Queue_TaskContext $ctx
376 *
377 * @return bool
378 */
379 public function addGettingStartedDashlet(CRM_Queue_TaskContext $ctx) {
380 $sql = "SELECT count(*) FROM civicrm_dashboard WHERE name='getting-started'";
381 $res = CRM_Core_DAO::singleValueQuery($sql);
382 $domainId = CRM_Core_Config::domainID();
383 if ($res <= 0) {
384 $sql = "INSERT INTO `civicrm_dashboard`
385 ( `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)";
386 CRM_Core_DAO::executeQuery($sql);
387 // Add default position for Getting Started Dashlet ( left column)
388 $sql = "INSERT INTO `civicrm_dashboard_contact` (dashboard_id, contact_id, column_no, is_active)
389 SELECT (SELECT MAX(id) FROM `civicrm_dashboard`), contact_id, 0, IF (SUM(is_active) > 0, 1, 0)
390 FROM `civicrm_dashboard_contact` JOIN `civicrm_contact` WHERE civicrm_dashboard_contact.contact_id = civicrm_contact.id GROUP BY contact_id";
391 CRM_Core_DAO::executeQuery($sql);
392 }
393 return TRUE;
394 }
395
396 /**
397 * Migrate on-behalf information to uf_join.module_data as on-behalf columns will be dropped
398 * on DB upgrade
399 *
400 * @param CRM_Queue_TaskContext $ctx
401 *
402 * @return bool
403 * TRUE for success
404 */
405 public static function migrateOnBehalfOfInfo(CRM_Queue_TaskContext $ctx) {
406 $domain = new CRM_Core_DAO_Domain();
407 $domain->find(TRUE);
408
409 // fetch onBehalf entry in UFJoin table
410 $ufGroupDAO = new CRM_Core_DAO_UFJoin();
411 $ufGroupDAO->module = 'OnBehalf';
412 $ufGroupDAO->find(TRUE);
413
414 $forOrgColums = array();
415 if ($domain->locales) {
416 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
417 foreach ($locales as $locale) {
418 $forOrgColums[] = "for_organization_{$locale}";
419 }
420 }
421 else {
422 $forOrgColums[] = "for_organization";
423 }
424
425 $query = "
426 SELECT " . implode(", ", $forOrgColums) . ", uj.id as join_id, uj.uf_group_id as uf_group_id
427 FROM civicrm_contribution_page cp
428 INNER JOIN civicrm_uf_join uj ON uj.entity_id = cp.id AND uj.module = 'OnBehalf'";
429 $dao = CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
430
431 if ($dao->N) {
432 while ($dao->fetch()) {
433 $onBehalfParams['on_behalf'] = array('is_for_organization' => $dao->is_for_organization);
434 if ($domain->locales) {
435 foreach ($locales as $locale) {
436 $for_organization = "for_organization_{$locale}";
437 $onBehalfParams['on_behalf'] += array(
438 $locale => array(
439 'for_organization' => $dao->$for_organization,
440 ),
441 );
442 }
443 }
444 else {
445 $onBehalfParams['on_behalf'] += array(
446 'default' => array(
447 'for_organization' => $dao->for_organization,
448 ),
449 );
450 }
451 $ufJoinParam = array(
452 'id' => $dao->join_id,
453 'module' => 'on_behalf',
454 'uf_group_id' => $dao->uf_group_id,
455 'module_data' => json_encode($onBehalfParams),
456 );
457 CRM_Core_BAO_UFJoin::create($ufJoinParam);
458 }
459 }
460
461 return TRUE;
462 }
463
464 /**
465 * v4.7.11 adds a new setting "remote_profile_submissions". This is
466 * long-standing feature that existing sites may be using; however, it's
467 * a bit prone to abuse. For new sites, the default is to disable it
468 * (since that is more secure). For existing sites, the default is to
469 * enable it (since that is more compatible).
470 *
471 * @param \CRM_Queue_TaskContext $ctx
472 *
473 * @return bool
474 */
475 public function migrateRemoteSubmissionsSetting(CRM_Queue_TaskContext $ctx) {
476 $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");
477 while ($domains->fetch()) {
478 CRM_Core_DAO::executeQuery(
479 "INSERT INTO civicrm_setting (`name`, `value`, `domain_id`, `is_domain`, `contact_id`, `component_id`, `created_date`, `created_id`)
480 VALUES (%2, %3, %4, %5, NULL, NULL, %6, NULL)",
481 array(
482 2 => array('remote_profile_submissions', 'String'),
483 3 => array('s:1:"1";', 'String'),
484 4 => array($domains->id, 'Integer'),
485 5 => array(1, 'Integer'),
486 6 => array(date('Y-m-d H:i:s'), 'String'),
487 )
488 );
489 }
490 return TRUE;
491 }
492
493 /**
494 * CRM-11782 - Get rid of VALUE_SEPARATOR character in saved search form values
495 *
496 * @param \CRM_Queue_TaskContext $ctx
497 *
498 * @return bool
499 */
500 public function fixContactTypeInSmartGroups(CRM_Queue_TaskContext $ctx) {
501 $sep = CRM_Core_DAO::VALUE_SEPARATOR;
502 $dao = CRM_Core_DAO::executeQuery("SELECT id, form_values FROM civicrm_saved_search WHERE form_values LIKE '%$sep%'");
503 while ($dao->fetch()) {
504 $formValues = unserialize($dao->form_values);
505 if (isset($formValues['contact_type']) && is_array($formValues['contact_type'])) {
506 $newVals = array();
507 foreach ($formValues['contact_type'] as $key => $val) {
508 $newVals[str_replace($sep, '__', $key)] = is_string($val) ? str_replace($sep, '__', $val) : $val;
509 }
510 $formValues['contact_type'] = $newVals;
511 }
512 CRM_Core_DAO::executeQuery("UPDATE civicrm_saved_search SET form_values = %1 WHERE id = {$dao->id}", array(1 => array(serialize($formValues), 'String')));
513 }
514
515 return TRUE;
516 }
517
518 /**
519 * CRM-17637 - Ths file location has been moved; delete the old one
520 *
521 * @param \CRM_Queue_TaskContext $ctx
522 *
523 * @return bool
524 */
525 public function deleteVersionCheckCacheFile(CRM_Queue_TaskContext $ctx) {
526 $config = CRM_Core_Config::singleton();
527 $cacheFile = $config->uploadDir . 'version-info-cache.json';
528 if (file_exists($cacheFile)) {
529 unlink($cacheFile);
530 }
531 return TRUE;
532 }
533
534 /**
535 * CRM-17669 and CRM-17686, make scheduled jobs more flexible, disable the 4.6 extension if installed
536 *
537 * @param \CRM_Queue_TaskContext $ctx
538 *
539 * @return bool
540 */
541 public function disableFlexibleJobsExtension(CRM_Queue_TaskContext $ctx) {
542 try {
543 civicrm_api3('Extension', 'disable', array('key' => 'com.klangsoft.flexiblejobs'));
544 }
545 catch (CiviCRM_API3_Exception $e) {
546 // just ignore if the extension isn't installed
547 }
548
549 return TRUE;
550 }
551
552 /**
553 * CRM-17752 add index to civicrm_financial_trxn.trxn_id (deliberately non-unique).
554 *
555 * @param \CRM_Queue_TaskContext $ctx
556 *
557 * @return bool
558 */
559 public function addIndexFinancialTrxnTrxnID(CRM_Queue_TaskContext $ctx) {
560 $tables = array('civicrm_financial_trxn' => array('trxn_id'));
561 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
562 return TRUE;
563 }
564
565 /**
566 * CRM-17882 Add index to civicrm_contribution.credit_note_id.
567 *
568 * @param \CRM_Queue_TaskContext $ctx
569 *
570 * @return bool
571 */
572 public function addIndexContributionCreditNoteID(CRM_Queue_TaskContext $ctx) {
573 $tables = array('civicrm_contribution' => array('creditnote_id'));
574 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
575 return TRUE;
576 }
577
578 /**
579 * CRM-17775 Add correct index for table civicrm_financial_item.
580 *
581 * Note that the entity ID should always precede the entity_table as
582 * it is more unique. This is better for performance and does not cause fallback
583 * to no index if table it omitted.
584 *
585 * @return bool
586 */
587 public function addCombinedIndexFinancialItemEntityIDEntityType() {
588 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'UI_id');
589 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'IX_Entity');
590 CRM_Core_BAO_SchemaHandler::createIndexes(array(
591 'civicrm_financial_item' => array(array('entity_id', 'entity_table')),
592 ));
593 return TRUE;
594 }
595
596 /**
597 * CRM-17951 Add accounts option values for refund and chargeback.
598 *
599 * Add Chargeback contribution status and Chargeback and Contra account relationships,
600 * checking first if one exists.
601 */
602 public function addRefundAndChargeBackAccountsIfNotExist() {
603 // First we enable and edit the record for Credit contra - this exists but is disabled for most sites.
604 // Using the ensure function (below) will not enabled a disabled option (by design).
605 CRM_Core_DAO::executeQuery("UPDATE civicrm_option_value v
606 INNER JOIN civicrm_option_group g on v.option_group_id=g.id and g.name='account_relationship'
607 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'
608 WHERE v.name = 'Credit/Contra Account is';");
609
610 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
611 'option_group_id' => 'account_relationship',
612 'name' => 'Chargeback Account is',
613 'label' => ts('Chargeback Account is'),
614 'is_active' => TRUE,
615 'component_id' => 'CiviContribute',
616 ));
617
618 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
619 'option_group_id' => 'contribution_status',
620 'name' => 'Chargeback',
621 'label' => ts('Chargeback'),
622 'is_active' => TRUE,
623 'component_id' => 'CiviContribute',
624 ));
625 return TRUE;
626 }
627
628 /**
629 * CRM-17999 Add index to civicrm_contribution.source.
630 *
631 * @param \CRM_Queue_TaskContext $ctx
632 *
633 * @return bool
634 */
635 public function addIndexContributionSource(CRM_Queue_TaskContext $ctx) {
636 CRM_Core_BAO_SchemaHandler::createIndexes(array('civicrm_contribution' => array('source')));
637 return TRUE;
638 }
639
640 /**
641 * CRM-18124 Add index to civicrm_contribution.total_amount.
642 *
643 * Note that I made this a combined index with receive_date because the issue included
644 * both criteria and they seemed likely to be used in conjunction to me in other cases.
645 *
646 * @param \CRM_Queue_TaskContext $ctx
647 *
648 * @return bool
649 */
650 public function addIndexContributionAmount(CRM_Queue_TaskContext $ctx) {
651 CRM_Core_BAO_SchemaHandler::createIndexes(array(
652 'civicrm_contribution' => array(array('total_amount', 'receive_date')),
653 ));
654 return TRUE;
655 }
656
657 /**
658 * CRM-18124 Add index to civicrm_contribution.total_amount.
659 *
660 * Note that I made this a combined index with receive_date because the issue included
661 * both criteria and they seemed likely to be used in conjunction to me in other cases.
662 *
663 * @param \CRM_Queue_TaskContext $ctx
664 *
665 * @return bool
666 */
667 public function addDeletedByMergeActivityType(CRM_Queue_TaskContext $ctx) {
668 CRM_Core_BAO_OptionValue::ensureOptionValueExists(array(
669 'option_group_id' => 'activity_type',
670 'name' => 'Contact Deleted by Merge',
671 'label' => ts('Contact Deleted by Merge'),
672 'description' => ts('Contact was merged into another contact'),
673 'is_active' => TRUE,
674 'filter' => 1,
675 ));
676 return TRUE;
677 }
678
679 /**
680 * CRM-12252 Add Help Pre and Help Post Fields for Price Field Value Table.
681 *
682 * @param \CRM_Queue_TaskContext $ctx
683 *
684 * @return bool
685 */
686 public function addHelpPreAndHelpPostFieldsPriceFieldValue(CRM_Queue_TaskContext $ctx) {
687 $domain = new CRM_Core_DAO_Domain();
688 $domain->find(TRUE);
689 if ($domain->locales) {
690 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
691 foreach ($locales as $locale) {
692 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_pre_{$locale}")) {
693 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
694 ADD COLUMN `help_pre_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'", array(), TRUE, NULL, FALSE, FALSE);
695 }
696 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_post_{$locale}")) {
697 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
698 ADD COLUMN `help_post_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'", array(), TRUE, NULL, FALSE, FALSE);
699 }
700 }
701 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL);
702 }
703 else {
704 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_pre')) {
705 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
706 ADD COLUMN `help_pre` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'");
707 }
708 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_post')) {
709 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
710 ADD COLUMN `help_post` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'");
711 }
712 }
713 return TRUE;
714 }
715
716 /**
717 * CRM-18345 Don't delete mailing data on email/phone deletion
718 * Implemented here in CRM-18526
719 *
720 * @param \CRM_Queue_TaskContext $ctx
721 *
722 * @return bool
723 */
724 public function upgradeMailingFKs(CRM_Queue_TaskContext $ctx) {
725
726 // Safely drop the foreign keys
727 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_email_id');
728 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_phone_id');
729 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_email_id');
730 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_phone_id');
731
732 // Set up the new foreign keys
733 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 0;");
734
735 CRM_Core_DAO::executeQuery("
736 ALTER TABLE `civicrm_mailing_event_queue`
737 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_email_id`
738 FOREIGN KEY (`email_id`)
739 REFERENCES `civicrm_email`(`id`)
740 ON DELETE SET NULL
741 ON UPDATE RESTRICT;
742 ");
743
744 CRM_Core_DAO::executeQuery("
745 ALTER TABLE `civicrm_mailing_event_queue`
746 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_phone_id`
747 FOREIGN KEY (`phone_id`)
748 REFERENCES `civicrm_phone`(`id`)
749 ON DELETE SET NULL
750 ON UPDATE RESTRICT;
751 ");
752
753 CRM_Core_DAO::executeQuery("
754 ALTER TABLE `civicrm_mailing_recipients`
755 ADD CONSTRAINT `FK_civicrm_mailing_recipients_email_id`
756 FOREIGN KEY (`email_id`)
757 REFERENCES `civicrm_email`(`id`)
758 ON DELETE SET NULL
759 ON UPDATE RESTRICT;
760 ");
761
762 CRM_Core_DAO::executeQuery("
763 ALTER TABLE `civicrm_mailing_recipients`
764 ADD CONSTRAINT `FK_civicrm_mailing_recipients_phone_id`
765 FOREIGN KEY (`phone_id`)
766 REFERENCES `civicrm_phone`(`id`)
767 ON DELETE SET NULL
768 ON UPDATE RESTRICT;
769 ");
770
771 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;");
772
773 return TRUE;
774 }
775
776 /**
777 * CRM-17663 - Dashboard schema changes
778 *
779 * @param \CRM_Queue_TaskContext $ctx
780 *
781 * @return bool
782 */
783 public function dashboardSchemaUpdate(CRM_Queue_TaskContext $ctx) {
784 if (!CRM_Core_BAO_SchemaHandler::checkIfIndexExists('civicrm_dashboard_contact', 'index_dashboard_id_contact_id')) {
785 // Delete any stray duplicate rows and add unique index to prevent new dupes and enable INSERT/UPDATE combo query
786 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');
787 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dashboard_contact ADD UNIQUE INDEX index_dashboard_id_contact_id (dashboard_id, contact_id);');
788 }
789 $domain = new CRM_Core_DAO_Domain();
790 $domain->find(TRUE);
791 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'content');
792 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_minimized');
793 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_fullscreen');
794 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'created_date');
795 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_fullscreen');
796 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_minimized');
797 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'column_no');
798 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'weight');
799 if ($domain->locales) {
800 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
801 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL);
802 }
803
804 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET url = REPLACE(url, "&snippet=5", ""), fullscreen_url = REPLACE(fullscreen_url, "&snippet=5", "")');
805
806 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dashboard', 'cache_minutes')) {
807 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."');
808 }
809
810 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 1440 WHERE name = "blog"');
811 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 7200 WHERE name IN ("activity","getting-started")');
812 return TRUE;
813 }
814
815 /**
816 * CRM-19100 - Alter Index and Type for Image URL
817 * @return bool
818 */
819 public static function alterIndexAndTypeForImageURL() {
820 $length = array();
821 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_contact', 'index_image_url');
822 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.'");
823
824 $length['civicrm_contact']['image_URL'] = 128;
825 CRM_Core_BAO_SchemaHandler::createIndexes(array('civicrm_contact' => array('image_URL')), 'index', $length);
826
827 return TRUE;
828 }
829
830 }