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