Merge pull request #13987 from seamuslee001/new_coder_pcp_pledge_profile_queue_report
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourSeven.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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.', [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.', [1 => 'Moneris']) . '</p>';
60 }
61 }
62 if ($rev == '4.7.13') {
63 $preUpgradeMessage .= '<p>' . ts('A new permission has been added called %1 This Permission is now used to control access to the Manage Tags screen', [1 => 'manage tags']) . '</p>';
64 }
65 if ($rev == '4.7.22') {
66 // Based on support inquiries for 4.7.21, show message during 4.7.22.
67 // For affected users, this issue prevents loading the regular status screen.
68 if (!$this->checkImageUploadDir()) {
69 $preUpgradeMessage .= '<p>' . ts('There appears to be an inconsistency in the configuration of "Image Upload URL" and "Image Upload Directory".') . '</p>'
70 . '<p>'
71 . ts('Further advice will be displayed at the end of the upgrade.')
72 . '</p>';
73 }
74 }
75 if ($rev == '4.7.27') {
76 $params = [
77 1 => 'Close accounting batches created by user',
78 2 => 'Close all accounting batches',
79 3 => 'Reopen accounting batches created by user',
80 4 => 'Reopen all accounting batches',
81 5 => 'https://wiki.civicrm.org/confluence/display/CRMDOC/Default+Permissions+and+Roles',
82 ];
83 $preUpgradeMessage .= '<p>' . ts('A new set of batch permissions has been added called "%1", "%2", "%3" and "%4". These permissions are now used to control access to the Accounting Batches tasks. If your users need to be able to Reopen or Close batches you may need to give them additional permissions. <a href=%5>Read more</a>', $params) . '</p>';
84 }
85 if ($rev == '4.7.32') {
86 $preUpgradeMessage .= '<p>' . ts('A new %1 permission has been added. It is not granted by default. If you use SMS, you may wish to review your permissions.', [1 => 'send SMS']) . '</p>';
87 }
88 }
89
90 /**
91 * Compute any messages which should be displayed after upgrade.
92 *
93 * @param string $postUpgradeMessage
94 * alterable.
95 * @param string $rev
96 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
97 */
98 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
99 if ($rev == '4.7.alpha1') {
100 $config = CRM_Core_Config::singleton();
101 // FIXME: Performing an upgrade step during postUpgrade message phase is probably bad
102 $editor_id = self::updateWysiwyg();
103 $msg = NULL;
104 $ext_href = 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"';
105 $dsp_href = 'href="' . CRM_Utils_System::url('civicrm/admin/setting/preferences/display', 'reset=1') . '"';
106 $blog_href = 'href="https://civicrm.org/blogs/colemanw/big-changes-wysiwyg-editing-47"';
107 switch ($editor_id) {
108 // TinyMCE
109 case 1:
110 $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.', [1 => $ext_href]);
111 break;
112
113 // Drupal/Joomla editor
114 case 3:
115 case 4:
116 $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>', [1 => $config->userFramework, 2 => $blog_href]);
117 break;
118 }
119 if ($msg) {
120 $postUpgradeMessage .= '<p>' . $msg . '</p>';
121 }
122 $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>', [1 => $dsp_href, 2 => $blog_href]) . '</p>';
123
124 $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).');
125
126 $postUpgradeMessage .= '<p>' . ts('The custom fatal error template setting has been removed.') . '</p>';
127 }
128 //if ($rev == '4.7.11') {
129 // $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'");
130 //}
131 if ($rev == '4.7.11') {
132 $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'.");
133 }
134 if ($rev == '4.7.14') {
135 $ck_href = 'href="' . CRM_Utils_System::url('civicrm/admin/ckeditor') . '"';
136 $postUpgradeMessage .= '<p>' . ts('CiviMail no longer forces CKEditor to add html/head/body tags to email content because some sites place these in the message header/footer. This was added in 4.7.5 and is now disabled by default.')
137 . '<br />' . ts('You can re-enable it by visiting the <a %1>CKEditor Config</a> screen and setting "fullPage = true" under the Advanced Options of the CiviMail preset.', [1 => $ck_href])
138 . '</p>';
139 }
140 if ($rev == '4.7.19') {
141 $postUpgradeMessage .= '<br /><br />' . ts('Default version of the following System Workflow Message Templates have been modified: <ul><li>Additional Payment Receipt or Refund Notification</li><li>Contribution Invoice</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).');
142 $check = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_domain");
143 $smsCheck = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_sms_provider");
144 if ($check > 1 && (bool) $smsCheck) {
145 $postUpgradeMessage .= '<p>civicrm_sms_provider ' . ts('has now had a domain id column added. As there is more than 1 domains in this install you need to manually set the domain id for the providers in this install') . '</p>';
146 }
147 }
148 if ($rev == '4.7.22') {
149 // Based on support inquiries for 4.7.21, show message during 4.7.22.
150 // For affected users, this issue prevents loading the regular status screen.
151 if (!$this->checkImageUploadDir()) {
152 $config = CRM_Core_Config::singleton();
153 $postUpgradeMessage .=
154 '<h3>' . ts('Warning') . '</h3>'
155 . '<p>' . ts('There appears to be an inconsistency in the configuration of "Image Upload URL" and "Image Upload Directory".') . '</p>'
156 . sprintf("<ul><li><b>imageUploadDir</b>: <code>%s</code></li><li><b>imageUploadURL</b>: <code>%s</code></li></ul>", htmlentities($config->imageUploadDir), htmlentities($config->imageUploadURL))
157 . '<p>'
158 . ts('You may need to check that: <ul><li>(a) the path and URL match,</li><li> (b) the httpd/htaccess policy allows requests for files inside this folder,</li><li>and (c) the web domain matches the normal web domain.</ul>')
159 . '</p>'
160 . '<p><em>'
161 . ts('(Note: Although files should be readable, it is best if they are not listable or browseable.)')
162 . '</em></p>'
163 . '<p>'
164 . ts('If this remains unresolved, then some important screens may fail to load.')
165 . '</p>';
166 }
167 }
168 if ($rev == '4.7.23') {
169 $postUpgradeMessage .= '<br /><br />' . ts('Default version of the following System Workflow Message Templates have been modified: <ul><li>Contribution Invoice</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).');
170 }
171 }
172
173 /**
174 * Upgrade function.
175 *
176 * @param string $rev
177 */
178 public function upgrade_4_7_alpha1($rev) {
179 $this->addTask('Drop action scheudle mapping foreign key', 'dropActionScheudleMappingForeignKey');
180 $this->addTask('Migrate \'on behalf of\' information to module_data', 'migrateOnBehalfOfInfo');
181 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
182 $this->addTask(ts('Migrate Settings to %1', [1 => $rev]), 'migrateSettings', $rev);
183 $this->addTask('Add Getting Started dashlet', 'addGettingStartedDashlet', $rev);
184 }
185
186 /**
187 * Upgrade function.
188 *
189 * @param string $rev
190 */
191 public function upgrade_4_7_alpha4($rev) {
192 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
193 $this->addTask(ts('Remove %1', [1 => 'Moneris']), 'removePaymentProcessorType', 'Moneris');
194 $this->addTask('Update Smart Groups', 'fixContactTypeInSmartGroups');
195 }
196
197 /**
198 * Upgrade function.
199 *
200 * @param string $rev
201 */
202 public function upgrade_4_7_beta2($rev) {
203 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
204 $this->addTask('Delete unused file', 'deleteVersionCheckCacheFile');
205 }
206
207 /**
208 * Upgrade function.
209 *
210 * @param string $rev
211 */
212 public function upgrade_4_7_beta6($rev) {
213 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
214 $this->addTask('Disable flexible jobs extension', 'disableFlexibleJobsExtension');
215 $this->addTask('Add Index to financial_trxn trxn_id field', 'addIndexFinancialTrxnTrxnID');
216 }
217
218 /**
219 * Upgrade function.
220 *
221 * @param string $rev
222 */
223 public function upgrade_4_7_1($rev) {
224 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
225 $this->addTask('Add Index to civicrm_contribution creditnote_id field', 'addIndexContributionCreditNoteID');
226 }
227
228 /**
229 * Upgrade function.
230 *
231 * @param string $rev
232 */
233 public function upgrade_4_7_2($rev) {
234 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
235 $this->addTask('Fix Index on civicrm_financial_item combined entity_id + entity_table', 'addCombinedIndexFinancialItemEntityIDEntityType');
236 $this->addTask('enable financial account relationships for chargeback & refund', 'addRefundAndChargeBackAccountsIfNotExist');
237 $this->addTask('Add Index to civicrm_contribution.source', 'addIndexContributionSource');
238 }
239
240 /**
241 * Upgrade function.
242 *
243 * @param string $rev
244 */
245 public function upgrade_4_7_3($rev) {
246 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
247 $this->addTask('Add Index to civicrm_contribution.total_amount', 'addIndexContributionAmount');
248 }
249
250 /**
251 * Upgrade function.
252 *
253 * @param string $rev
254 */
255 public function upgrade_4_7_4($rev) {
256 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
257 $this->addTask('Add Contact Deleted by Merge Activity Type', 'addDeletedByMergeActivityType');
258 }
259
260 /**
261 * Upgrade function.
262 *
263 * @param string $rev
264 */
265 public function upgrade_4_7_7($rev) {
266 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
267 // https://issues.civicrm.org/jira/browse/CRM-18006
268 if (CRM_Core_DAO::checkTableExists('civicrm_install_canary')) {
269 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_install_canary ENGINE=InnoDB');
270 }
271 }
272
273 /**
274 * Upgrade function.
275 *
276 * @param string $rev
277 */
278 public function upgrade_4_7_8($rev) {
279 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
280 $this->addTask('Upgrade mailing foreign key constraints', 'upgradeMailingFKs');
281 }
282
283 /**
284 * Upgrade function.
285 *
286 * @param string $rev
287 */
288 public function upgrade_4_7_10($rev) {
289 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
290 $this->addTask('Upgrade Add Help Pre and Post Fields to price value table', 'addHelpPreAndHelpPostFieldsPriceFieldValue');
291 $this->addTask('Alter index and type for image URL', 'alterIndexAndTypeForImageURL');
292 }
293
294 /**
295 * Upgrade function.
296 *
297 * @param string $rev
298 */
299 public function upgrade_4_7_11($rev) {
300 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
301 $this->addTask('Dashboard schema updates', 'dashboardSchemaUpdate');
302 $this->addTask('Fill in setting "remote_profile_submissions"', 'migrateRemoteSubmissionsSetting');
303 }
304
305 /**
306 * Upgrade function.
307 *
308 * @param string $rev
309 */
310 public function upgrade_4_7_12($rev) {
311 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
312 $this->addTask('Add Data Type column to civicrm_option_group', 'addDataTypeColumnToOptionGroupTable');
313 }
314
315 /**
316 * Upgrade function.
317 *
318 * @param string $rev
319 */
320 public function upgrade_4_7_13($rev) {
321 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
322 $this->addTask('CRM-19372 - Add column to allow for payment processors to set what card types are accepted', 'addColumn',
323 'civicrm_payment_processor', 'accepted_credit_cards', "text DEFAULT NULL COMMENT 'array of accepted credit card types'");
324 }
325
326 /**
327 * Upgrade function.
328 *
329 * @param string $rev
330 */
331 public function upgrade_4_7_14($rev) {
332 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
333 $this->addTask('Add WYSIWYG Editor Presets', 'addWysiwygPresets');
334 }
335
336 /**
337 * Upgrade function.
338 *
339 * @param string $rev
340 */
341 public function upgrade_4_7_15($rev) {
342 $this->addTask('CRM-19626 - Add min_amount column to civicrm_price_set', 'addColumn',
343 'civicrm_price_set', 'min_amount', "INT(10) UNSIGNED DEFAULT '0' COMMENT 'Minimum Amount required for this set.'");
344 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
345 }
346
347 /**
348 * Upgrade function.
349 *
350 * @param string $rev
351 */
352 public function upgrade_4_7_16($rev) {
353 $this->addTask('CRM-19723 - Add icon column to civicrm_option_value', 'addColumn',
354 'civicrm_option_value', 'icon', "varchar(255) COMMENT 'crm-i icon class' DEFAULT NULL");
355 $this->addTask('CRM-19769 - Add color column to civicrm_tag', 'addColumn',
356 'civicrm_tag', 'color', "varchar(255) COMMENT 'Hex color value e.g. #ffffff' DEFAULT NULL");
357 $this->addTask('CRM-19779 - Add color column to civicrm_option_value', 'addColumn',
358 'civicrm_option_value', 'color', "varchar(255) COMMENT 'Hex color value e.g. #ffffff' DEFAULT NULL");
359 $this->addTask('Add new CiviMail fields', 'addMailingTemplateType');
360 $this->addTask('CRM-19770 - Add is_star column to civicrm_activity', 'addColumn',
361 'civicrm_activity', 'is_star', "tinyint DEFAULT '0' COMMENT 'Activity marked as favorite.'");
362 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
363 }
364
365 /**
366 * Upgrade function.
367 *
368 * @param string $rev
369 */
370 public function upgrade_4_7_18($rev) {
371 $this->addTask('Update Kenyan Provinces', 'updateKenyanProvinces');
372 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
373 }
374
375 /**
376 * Upgrade function.
377 *
378 * @param string $rev
379 */
380 public function upgrade_4_7_19($rev) {
381 if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_financial_account', 'opening_balance')) {
382 $query = "SELECT id FROM civicrm_financial_account WHERE opening_balance <> 0 OR current_period_opening_balance <> 0";
383 $result = CRM_Core_DAO::executeQuery($query);
384 if (!$result->N) {
385 $this->addTask('Drop Column current_period_opening_balance From civicrm_financial_account table.', 'dropColumn', 'civicrm_financial_account', 'current_period_opening_balance');
386 $this->addTask('Drop Column opening_balance From civicrm_financial_account table.', 'dropColumn', 'civicrm_financial_account', 'opening_balance');
387 }
388 }
389 $this->addTask('CRM-19961 - Add domain_id column to civicrm_sms_provider', 'addColumn',
390 'civicrm_sms_provider', 'domain_id', "int(10) unsigned COMMENT 'Which Domain is this sms provier for'");
391 $this->addTask('CRM-19961 - Populate domain id table and perhaps add foreign key', 'populateSMSProviderDomainId');
392 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
393 $this->addTask('CRM-16633 - Add "Change Case Subject" activity', 'addChangeCaseSubjectActivityType');
394 $this->addTask('Add is_public column to civicrm_custom_group', 'addColumn',
395 'civicrm_custom_group', 'is_public', "boolean DEFAULT '1' COMMENT 'Is this property public?'");
396 }
397
398 /**
399 * Upgrade function.
400 *
401 * @param string $rev
402 */
403 public function upgrade_4_7_20($rev) {
404 $this->addtask('Fix Schema on civicrm_action_schedule', 'fixSchemaOnCiviCRMActionSchedule');
405 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
406 $this->addTask('Add activity_status column to civicrm_mail_settings', 'addColumn',
407 'civicrm_mail_settings', 'activity_status', "varchar (255) DEFAULT NULL COMMENT 'Name of status to use when creating email to activity.'");
408 }
409
410 /**
411 * Upgrade function.
412 *
413 * @param string $rev
414 */
415 public function upgrade_4_7_23($rev) {
416 $this->addTask('CRM-20387 - Add invoice_number column to civicrm_contribution', 'addColumn',
417 'civicrm_contribution', 'invoice_number', "varchar(255) COMMENT 'Human readable invoice number' DEFAULT NULL");
418 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
419 }
420
421 /**
422 * Upgrade function.
423 *
424 * @param string $rev
425 */
426 public function upgrade_4_7_25($rev) {
427 $this->addTask("CRM-20927 - Add column to 'civicrm_menu' for additional metadata", 'addColumn',
428 'civicrm_menu', 'module_data', "text COMMENT 'All other menu metadata not stored in other fields'");
429 $this->addTask('CRM-21052 - Determine activity revision policy', 'pickActivityRevisionPolicy');
430 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
431 $this->addTask('Add cancel button text column to civicrm_uf_group', 'addColumn',
432 'civicrm_uf_group', 'cancel_button_text', "varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Custom Text to display on the cancel button when used in create or edit mode'", TRUE);
433 $this->addTask('Add Submit button text column to civicrm_uf_group', 'addColumn',
434 'civicrm_uf_group', 'submit_button_text', "varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Custom Text to display on the submit button on profile edit/create screens'", TRUE);
435
436 $this->addTask('CRM-20958 - Add created_date to civicrm_activity', 'addColumn',
437 'civicrm_activity', 'created_date', "timestamp NULL DEFAULT NULL COMMENT 'When was the activity was created.'");
438 $this->addTask('CRM-20958 - Add modified_date to civicrm_activity', 'addColumn',
439 'civicrm_activity', 'modified_date', "timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'When was the activity (or closely related entity) was created or modified or deleted.'");
440 $this->addTask('CRM-20958 - Add created_date to civicrm_case', 'addColumn',
441 'civicrm_case', 'created_date', "timestamp NULL DEFAULT NULL COMMENT 'When was the case was created.'");
442 $this->addTask('CRM-20958 - Add modified_date to civicrm_case', 'addColumn',
443 'civicrm_case', 'modified_date', "timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'When was the case (or closely related entity) was created or modified or deleted.'");
444 }
445
446 /**
447 * Upgrade function.
448 *
449 * @param string $rev
450 */
451 public function upgrade_4_7_27($rev) {
452 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
453 $this->addTask('CRM-20892 Change created_date to default to NULL', 'civiMailingCreatedDateNull');
454 $this->addTask('CRM-21234 Missing subdivisions of Tajikistan', 'tajikistanMissingSubdivisions');
455 $this->addTask('CRM-20892 - Add modified_date to civicrm_mailing', 'addColumn',
456 'civicrm_mailing', 'modified_date', "timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'When the mailing (or closely related entity) was created or modified or deleted.'");
457 $this->addTask('CRM-21195 - Add icon field to civicrm_navigation', 'addColumn',
458 'civicrm_navigation', 'icon', "varchar(255) NULL DEFAULT NULL COMMENT 'CSS class name for an icon'");
459 $this->addTask('CRM-12167 - Add visibility column to civicrm_price_field_value', 'addColumn',
460 'civicrm_price_field_value', 'visibility_id', 'int(10) unsigned DEFAULT 1 COMMENT "Implicit FK to civicrm_option_group with name = \'visibility\'"');
461 $this->addTask('Remove broken Contribution_logging reports', 'removeContributionLoggingReports');
462 }
463
464 /**
465 * Upgrade function.
466 *
467 * @param string $rev
468 */
469 public function upgrade_4_7_28($rev) {
470 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
471 $this->addTask('CRM-20572: Fix date fields in save search criteria of Contrib Sybunt custom search ', 'fixDateFieldsInSmartGroups');
472 // CRM-20868 : Update invoice_numbers (in batch) with value in [invoice prefix][contribution id] format
473 if ($invoicePrefix = CRM_Contribute_BAO_Contribution::checkContributeSettings('invoice_prefix', TRUE)) {
474 list($minId, $maxId) = CRM_Core_DAO::executeQuery("SELECT coalesce(min(id),0), coalesce(max(id),0)
475 FROM civicrm_contribution ")->getDatabaseResult()->fetchRow();
476 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
477 $endId = $startId + self::BATCH_SIZE - 1;
478 $title = ts("Upgrade DB to %1: Update Contribution Invoice number (%2 => %3)", [
479 1 => $rev,
480 2 => $startId,
481 3 => $endId,
482 ]);
483 $this->addTask($title, 'updateContributionInvoiceNumber', $startId, $endId, $invoicePrefix);
484 }
485 }
486
487 }
488
489 /**
490 * Upgrade function.
491 *
492 * @param string $rev
493 */
494 public function upgrade_4_7_31($rev) {
495 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
496 $this->addTask('CRM-21225: Add display title field to civicrm_uf_group', 'addColumn', 'civicrm_uf_group', 'frontend_title',
497 "VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT 'Profile Form Public title'", TRUE);
498 $this->addTask('Rebuild Multilingual Schema', 'rebuildMultilingalSchema');
499 }
500
501 /**
502 * Upgrade function.
503 *
504 * @param string $rev
505 */
506 public function upgrade_4_7_32($rev) {
507 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
508
509 $this->addTask('CRM-21733: Add status_override_end_date field to civicrm_membership table', 'addColumn', 'civicrm_membership', 'status_override_end_date',
510 "date DEFAULT NULL COMMENT 'The end date of membership status override if (Override until selected date) override type is selected.'");
511 }
512
513 /*
514 * Important! All upgrade functions MUST add a 'runSql' task.
515 * Uncomment and use the following template for a new upgrade version
516 * (change the x in the function name):
517 */
518
519 // /**
520 // * Upgrade function.
521 // *
522 // * @param string $rev
523 // */
524 // public function upgrade_4_7_x($rev) {
525 // $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
526 // // Additional tasks here...
527 // // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
528 // // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
529 // }
530
531 /**
532 * CRM-16354
533 *
534 * @return int
535 */
536 public static function updateWysiwyg() {
537 $editorID = Civi::settings()->get('editor_id');
538 // Previously a numeric value indicated one of 4 wysiwyg editors shipped in core, and no value indicated 'Textarea'
539 // Now the options are "Textarea", "CKEditor", and the rest have been dropped from core.
540 $newEditor = $editorID ? "CKEditor" : "Textarea";
541 Civi::settings()->set('editor_id', $newEditor);
542
543 return $editorID;
544 }
545
546 /**
547 * Migrate any last remaining options from `civicrm_domain.config_backend` to `civicrm_setting`.
548 * Cleanup setting schema.
549 *
550 * @param CRM_Queue_TaskContext $ctx
551 * @return bool
552 */
553 public static function migrateSettings(CRM_Queue_TaskContext $ctx) {
554 // Tip: If there are problems with adding the new uniqueness index, try inspecting:
555 // SELECT name, domain_id, contact_id, count(*) AS dupes FROM civicrm_setting cs GROUP BY name, domain_id, contact_id HAVING dupes > 1;
556
557 // Nav records are expendable. https://forum.civicrm.org/index.php?topic=36933.0
558 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE contact_id IS NOT NULL AND name = "navigation"');
559
560 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP INDEX index_group_name');
561 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting DROP COLUMN group_name');
562
563 // Handle Strange activity_tab_filter settings.
564 CRM_Core_DAO::executeQuery('CREATE TABLE civicrm_activity_setting LIKE civicrm_setting');
565 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_activity_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
566 CRM_Core_DAO::executeQuery('INSERT INTO civicrm_activity_setting (name, contact_id, domain_id, value)
567 SELECT DISTINCT name, contact_id, domain_id, value
568 FROM civicrm_setting
569 WHERE name = "activity_tab_filter"
570 AND value is not NULL');
571 CRM_Core_DAO::executeQuery('DELETE FROM civicrm_setting WHERE name = "activity_tab_filter"');
572
573 $date = CRM_Utils_Time::getTime('Y-m-d H:i:s');
574 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_setting ADD UNIQUE INDEX index_domain_contact_name (domain_id, contact_id, name)');
575 CRM_Core_DAO::executeQuery("INSERT INTO civicrm_setting (name, contact_id, domain_id, value, is_domain, created_id, created_date)
576 SELECT name, contact_id, domain_id, value, 0, contact_id,'$date'
577 FROM civicrm_activity_setting
578 WHERE name = 'activity_tab_filter'
579 AND value is not NULL"
580 );
581 CRM_Core_DAO::executeQuery('DROP TABLE civicrm_activity_setting');
582
583 $domainDao = CRM_Core_DAO::executeQuery('SELECT id, config_backend FROM civicrm_domain');
584 while ($domainDao->fetch()) {
585 $settings = CRM_Upgrade_Incremental_php_FourSeven::convertBackendToSettings($domainDao->id, $domainDao->config_backend);
586 CRM_Core_Error::debug_var('convertBackendToSettings', [
587 'domainId' => $domainDao->id,
588 'backend' => $domainDao->config_backend,
589 'settings' => $settings,
590 ]);
591
592 foreach ($settings as $name => $value) {
593 $rowParams = [
594 1 => [$domainDao->id, 'Positive'],
595 2 => [$name, 'String'],
596 3 => [serialize($value), 'String'],
597 ];
598 $settingId = CRM_Core_DAO::singleValueQuery(
599 'SELECT id FROM civicrm_setting WHERE domain_id = %1 AND name = %2',
600 $rowParams);
601 if (!$settingId) {
602 CRM_Core_DAO::executeQuery(
603 'INSERT INTO civicrm_setting (domain_id, name, value, is_domain) VALUES (%1,%2,%3,1)',
604 $rowParams);
605 }
606 }
607 }
608
609 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_domain DROP COLUMN config_backend');
610
611 return TRUE;
612 }
613
614 /**
615 * Take a config_backend blob and produce an equivalent list of settings.
616 *
617 * @param int $domainId
618 * Domain ID.
619 * @param string $config_backend
620 * Serialized blob.
621 * @return array
622 */
623 public static function convertBackendToSettings($domainId, $config_backend) {
624 if (!$config_backend) {
625 return [];
626 }
627
628 $backend = unserialize($config_backend);
629 if (!$backend) {
630 return [];
631 }
632
633 $mappings = \CRM_Core_Config_MagicMerge::getPropertyMap();
634 $settings = [];
635 foreach ($backend as $propertyName => $propertyValue) {
636 if (isset($mappings[$propertyName][0]) && preg_match('/^setting/', $mappings[$propertyName][0])) {
637 // $mapping format: $propertyName => Array(0 => $type, 1 => $setting|NULL).
638 $settingName = isset($mappings[$propertyName][1]) ? $mappings[$propertyName][1] : $propertyName;
639 $settings[$settingName] = $propertyValue;
640 }
641 }
642
643 return $settings;
644 }
645
646 /**
647 * Update Invoice number for all completed contribution.
648 *
649 * @param \CRM_Queue_TaskContext $ctx
650 * @param int $startID
651 * @param int $endID
652 * @param string $invoicePrefix
653 *
654 * @return bool
655 */
656 public static function updateContributionInvoiceNumber(CRM_Queue_TaskContext $ctx, $startID, $endID, $invoicePrefix) {
657 CRM_Core_DAO::executeQuery("
658 UPDATE `civicrm_contribution` SET `invoice_number` = CONCAT(%1, `id`)
659 WHERE `id` >= %2 AND `id` <= %3 AND `invoice_number` IS NOT NULL",
660 [
661 1 => [$invoicePrefix, 'String'],
662 2 => [$startID, 'Integer'],
663 3 => [$endID, 'Integer'],
664 ]
665 );
666
667 return TRUE;
668 }
669
670 /**
671 * Add Getting Started dashlet to dashboard
672 *
673 * @param \CRM_Queue_TaskContext $ctx
674 *
675 * @return bool
676 */
677 public static function addGettingStartedDashlet(CRM_Queue_TaskContext $ctx) {
678 $sql = "SELECT count(*) FROM civicrm_dashboard WHERE name='getting-started'";
679 $res = CRM_Core_DAO::singleValueQuery($sql);
680 $domainId = CRM_Core_Config::domainID();
681 if ($res <= 0) {
682 $sql = "INSERT INTO `civicrm_dashboard`
683 ( `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)";
684 CRM_Core_DAO::executeQuery($sql);
685 // Add default position for Getting Started Dashlet ( left column)
686 $sql = "INSERT INTO `civicrm_dashboard_contact` (dashboard_id, contact_id, column_no, is_active)
687 SELECT (SELECT MAX(id) FROM `civicrm_dashboard`), contact_id, 0, IF (SUM(is_active) > 0, 1, 0)
688 FROM `civicrm_dashboard_contact` JOIN `civicrm_contact` WHERE civicrm_dashboard_contact.contact_id = civicrm_contact.id GROUP BY contact_id";
689 CRM_Core_DAO::executeQuery($sql);
690 }
691 return TRUE;
692 }
693
694 /**
695 * Migrate on-behalf information to uf_join.module_data as on-behalf columns will be dropped
696 * on DB upgrade
697 *
698 * @param CRM_Queue_TaskContext $ctx
699 *
700 * @return bool
701 * TRUE for success
702 */
703 public static function migrateOnBehalfOfInfo(CRM_Queue_TaskContext $ctx) {
704 $domain = new CRM_Core_DAO_Domain();
705 $domain->find(TRUE);
706
707 // fetch onBehalf entry in UFJoin table
708 $ufGroupDAO = new CRM_Core_DAO_UFJoin();
709 $ufGroupDAO->module = 'OnBehalf';
710 $ufGroupDAO->find(TRUE);
711
712 $forOrgColums = ['is_for_organization'];
713 if ($domain->locales) {
714 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
715 foreach ($locales as $locale) {
716 $forOrgColums[] = "for_organization_{$locale}";
717 }
718 }
719 else {
720 $forOrgColums[] = "for_organization";
721 }
722
723 $query = "
724 SELECT " . implode(", ", $forOrgColums) . ", uj.id as join_id, uj.uf_group_id as uf_group_id
725 FROM civicrm_contribution_page cp
726 INNER JOIN civicrm_uf_join uj ON uj.entity_id = cp.id AND uj.module = 'OnBehalf'";
727 $dao = CRM_Core_DAO::executeQuery($query, [], TRUE, NULL, FALSE, FALSE);
728
729 if ($dao->N) {
730 while ($dao->fetch()) {
731 $onBehalfParams['on_behalf'] = ['is_for_organization' => $dao->is_for_organization];
732 if ($domain->locales) {
733 foreach ($locales as $locale) {
734 $for_organization = "for_organization_{$locale}";
735 $onBehalfParams['on_behalf'] += [
736 $locale => [
737 'for_organization' => $dao->$for_organization,
738 ],
739 ];
740 }
741 }
742 else {
743 $onBehalfParams['on_behalf'] += [
744 'default' => [
745 'for_organization' => $dao->for_organization,
746 ],
747 ];
748 }
749 $ufJoinParam = [
750 'id' => $dao->join_id,
751 'module' => 'on_behalf',
752 'uf_group_id' => $dao->uf_group_id,
753 'module_data' => json_encode($onBehalfParams),
754 ];
755 CRM_Core_BAO_UFJoin::create($ufJoinParam);
756 }
757 }
758
759 return TRUE;
760 }
761
762 /**
763 * v4.7.11 adds a new setting "remote_profile_submissions". This is
764 * long-standing feature that existing sites may be using; however, it's
765 * a bit prone to abuse. For new sites, the default is to disable it
766 * (since that is more secure). For existing sites, the default is to
767 * enable it (since that is more compatible).
768 *
769 * @param \CRM_Queue_TaskContext $ctx
770 *
771 * @return bool
772 */
773 public static function migrateRemoteSubmissionsSetting(CRM_Queue_TaskContext $ctx) {
774 $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");
775 while ($domains->fetch()) {
776 CRM_Core_DAO::executeQuery(
777 "INSERT INTO civicrm_setting (`name`, `value`, `domain_id`, `is_domain`, `contact_id`, `component_id`, `created_date`, `created_id`)
778 VALUES (%2, %3, %4, %5, NULL, NULL, %6, NULL)",
779 [
780 2 => ['remote_profile_submissions', 'String'],
781 3 => ['s:1:"1";', 'String'],
782 4 => [$domains->id, 'Integer'],
783 5 => [1, 'Integer'],
784 6 => [date('Y-m-d H:i:s'), 'String'],
785 ]
786 );
787 }
788 return TRUE;
789 }
790
791 /**
792 * CRM-11782 - Get rid of VALUE_SEPARATOR character in saved search form values
793 *
794 * @param \CRM_Queue_TaskContext $ctx
795 *
796 * @return bool
797 */
798 public static function fixContactTypeInSmartGroups(CRM_Queue_TaskContext $ctx) {
799 $sep = CRM_Core_DAO::VALUE_SEPARATOR;
800 $dao = CRM_Core_DAO::executeQuery("SELECT id, form_values FROM civicrm_saved_search WHERE form_values LIKE '%$sep%'");
801 while ($dao->fetch()) {
802 $formValues = unserialize($dao->form_values);
803 if (isset($formValues['contact_type']) && is_array($formValues['contact_type'])) {
804 $newVals = [];
805 foreach ($formValues['contact_type'] as $key => $val) {
806 $newVals[str_replace($sep, '__', $key)] = is_string($val) ? str_replace($sep, '__', $val) : $val;
807 }
808 $formValues['contact_type'] = $newVals;
809 }
810 CRM_Core_DAO::executeQuery("UPDATE civicrm_saved_search SET form_values = %1 WHERE id = {$dao->id}", [1 => [serialize($formValues), 'String']]);
811 }
812
813 return TRUE;
814 }
815
816 /**
817 * CRM-17637 - Ths file location has been moved; delete the old one
818 *
819 * @param \CRM_Queue_TaskContext $ctx
820 *
821 * @return bool
822 */
823 public static function deleteVersionCheckCacheFile(CRM_Queue_TaskContext $ctx) {
824 $config = CRM_Core_Config::singleton();
825 $cacheFile = $config->uploadDir . 'version-info-cache.json';
826 if (file_exists($cacheFile)) {
827 unlink($cacheFile);
828 }
829 return TRUE;
830 }
831
832 /**
833 * CRM-17669 and CRM-17686, make scheduled jobs more flexible, disable the 4.6 extension if installed
834 *
835 * @param \CRM_Queue_TaskContext $ctx
836 *
837 * @return bool
838 */
839 public static function disableFlexibleJobsExtension(CRM_Queue_TaskContext $ctx) {
840 try {
841 civicrm_api3('Extension', 'disable', ['key' => 'com.klangsoft.flexiblejobs']);
842 }
843 catch (CiviCRM_API3_Exception $e) {
844 // just ignore if the extension isn't installed
845 }
846
847 return TRUE;
848 }
849
850 /**
851 * CRM-17752 add index to civicrm_financial_trxn.trxn_id (deliberately non-unique).
852 *
853 * @param \CRM_Queue_TaskContext $ctx
854 *
855 * @return bool
856 */
857 public static function addIndexFinancialTrxnTrxnID(CRM_Queue_TaskContext $ctx) {
858 $tables = ['civicrm_financial_trxn' => ['trxn_id']];
859 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
860 return TRUE;
861 }
862
863 /**
864 * CRM-17882 Add index to civicrm_contribution.credit_note_id.
865 *
866 * @param \CRM_Queue_TaskContext $ctx
867 *
868 * @return bool
869 */
870 public static function addIndexContributionCreditNoteID(CRM_Queue_TaskContext $ctx) {
871 $tables = ['civicrm_contribution' => ['creditnote_id']];
872 CRM_Core_BAO_SchemaHandler::createIndexes($tables);
873 return TRUE;
874 }
875
876 /**
877 * CRM-17775 Add correct index for table civicrm_financial_item.
878 *
879 * Note that the entity ID should always precede the entity_table as
880 * it is more unique. This is better for performance and does not cause fallback
881 * to no index if table it omitted.
882 *
883 * @return bool
884 */
885 public static function addCombinedIndexFinancialItemEntityIDEntityType() {
886 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'UI_id');
887 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_financial_item', 'IX_Entity');
888 CRM_Core_BAO_SchemaHandler::createIndexes([
889 'civicrm_financial_item' => [['entity_id', 'entity_table']],
890 ]);
891 return TRUE;
892 }
893
894 /**
895 * CRM-17951 Add accounts option values for refund and chargeback.
896 *
897 * Add Chargeback contribution status and Chargeback and Contra account relationships,
898 * checking first if one exists.
899 */
900 public static function addRefundAndChargeBackAccountsIfNotExist() {
901 // First we enable and edit the record for Credit contra - this exists but is disabled for most sites.
902 // Using the ensure function (below) will not enabled a disabled option (by design).
903 CRM_Core_DAO::executeQuery("UPDATE civicrm_option_value v
904 INNER JOIN civicrm_option_group g on v.option_group_id=g.id and g.name='account_relationship'
905 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'
906 WHERE v.name = 'Credit/Contra Account is';");
907
908 CRM_Core_BAO_OptionValue::ensureOptionValueExists([
909 'option_group_id' => 'account_relationship',
910 'name' => 'Chargeback Account is',
911 'label' => ts('Chargeback Account is'),
912 'is_active' => TRUE,
913 'component_id' => 'CiviContribute',
914 ]);
915
916 CRM_Core_BAO_OptionValue::ensureOptionValueExists([
917 'option_group_id' => 'contribution_status',
918 'name' => 'Chargeback',
919 'label' => ts('Chargeback'),
920 'is_active' => TRUE,
921 'component_id' => 'CiviContribute',
922 ]);
923 return TRUE;
924 }
925
926 /**
927 * CRM-17999 Add index to civicrm_contribution.source.
928 *
929 * @param \CRM_Queue_TaskContext $ctx
930 *
931 * @return bool
932 */
933 public static function addIndexContributionSource(CRM_Queue_TaskContext $ctx) {
934 CRM_Core_BAO_SchemaHandler::createIndexes(['civicrm_contribution' => ['source']]);
935 return TRUE;
936 }
937
938 /**
939 * CRM-18124 Add index to civicrm_contribution.total_amount.
940 *
941 * Note that I made this a combined index with receive_date because the issue included
942 * both criteria and they seemed likely to be used in conjunction to me in other cases.
943 *
944 * @param \CRM_Queue_TaskContext $ctx
945 *
946 * @return bool
947 */
948 public static function addIndexContributionAmount(CRM_Queue_TaskContext $ctx) {
949 CRM_Core_BAO_SchemaHandler::createIndexes([
950 'civicrm_contribution' => [['total_amount', 'receive_date']],
951 ]);
952 return TRUE;
953 }
954
955 /**
956 * CRM-18124 Add index to civicrm_contribution.total_amount.
957 *
958 * Note that I made this a combined index with receive_date because the issue included
959 * both criteria and they seemed likely to be used in conjunction to me in other cases.
960 *
961 * @param \CRM_Queue_TaskContext $ctx
962 *
963 * @return bool
964 */
965 public static function addDeletedByMergeActivityType(CRM_Queue_TaskContext $ctx) {
966 CRM_Core_BAO_OptionValue::ensureOptionValueExists([
967 'option_group_id' => 'activity_type',
968 'name' => 'Contact Deleted by Merge',
969 'label' => ts('Contact Deleted by Merge'),
970 'description' => ts('Contact was merged into another contact'),
971 'is_active' => TRUE,
972 'filter' => 1,
973 ]);
974 return TRUE;
975 }
976
977 /**
978 * CRM-12252 Add Help Pre and Help Post Fields for Price Field Value Table.
979 *
980 * @param \CRM_Queue_TaskContext $ctx
981 *
982 * @return bool
983 */
984 public static function addHelpPreAndHelpPostFieldsPriceFieldValue(CRM_Queue_TaskContext $ctx) {
985 $domain = new CRM_Core_DAO_Domain();
986 $domain->find(TRUE);
987 if ($domain->locales) {
988 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
989 foreach ($locales as $locale) {
990 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_pre_{$locale}")) {
991 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
992 ADD COLUMN `help_pre_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'", [], TRUE, NULL, FALSE, FALSE);
993 }
994 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists("civicrm_price_field_value", "help_post_{$locale}")) {
995 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
996 ADD COLUMN `help_post_{$locale}` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'", [], TRUE, NULL, FALSE, FALSE);
997 }
998 }
999 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL, TRUE);
1000 }
1001 else {
1002 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_pre')) {
1003 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
1004 ADD COLUMN `help_pre` text COLLATE utf8_unicode_ci COMMENT 'Price field option pre help text.'");
1005 }
1006 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_price_field_value', 'help_post')) {
1007 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_price_field_value`
1008 ADD COLUMN `help_post` text COLLATE utf8_unicode_ci COMMENT 'Price field option post help text.'");
1009 }
1010 }
1011 return TRUE;
1012 }
1013
1014 /**
1015 * CRM-18464 Check if Foreign key exists and also drop any index of same name accidentially created.
1016 *
1017 * @param \CRM_Queue_TaskContext $ctx
1018 *
1019 * @return bool
1020 */
1021 public static function dropActionScheudleMappingForeignKey(CRM_Queue_TaskContext $ctx) {
1022 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_action_schedule', 'FK_civicrm_action_schedule_mapping_id');
1023 return TRUE;
1024 }
1025
1026 /**
1027 * CRM-18345 Don't delete mailing data on email/phone deletion
1028 * Implemented here in CRM-18526
1029 *
1030 * @param \CRM_Queue_TaskContext $ctx
1031 *
1032 * @return bool
1033 */
1034 public static function upgradeMailingFKs(CRM_Queue_TaskContext $ctx) {
1035
1036 // Safely drop the foreign keys
1037 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_email_id');
1038 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_event_queue', 'FK_civicrm_mailing_event_queue_phone_id');
1039 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_email_id');
1040 CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_mailing_recipients', 'FK_civicrm_mailing_recipients_phone_id');
1041
1042 // Set up the new foreign keys
1043 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 0;");
1044
1045 CRM_Core_DAO::executeQuery("
1046 ALTER TABLE `civicrm_mailing_event_queue`
1047 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_email_id`
1048 FOREIGN KEY (`email_id`)
1049 REFERENCES `civicrm_email`(`id`)
1050 ON DELETE SET NULL
1051 ON UPDATE RESTRICT;
1052 ");
1053
1054 CRM_Core_DAO::executeQuery("
1055 ALTER TABLE `civicrm_mailing_event_queue`
1056 ADD CONSTRAINT `FK_civicrm_mailing_event_queue_phone_id`
1057 FOREIGN KEY (`phone_id`)
1058 REFERENCES `civicrm_phone`(`id`)
1059 ON DELETE SET NULL
1060 ON UPDATE RESTRICT;
1061 ");
1062
1063 CRM_Core_DAO::executeQuery("
1064 ALTER TABLE `civicrm_mailing_recipients`
1065 ADD CONSTRAINT `FK_civicrm_mailing_recipients_email_id`
1066 FOREIGN KEY (`email_id`)
1067 REFERENCES `civicrm_email`(`id`)
1068 ON DELETE SET NULL
1069 ON UPDATE RESTRICT;
1070 ");
1071
1072 CRM_Core_DAO::executeQuery("
1073 ALTER TABLE `civicrm_mailing_recipients`
1074 ADD CONSTRAINT `FK_civicrm_mailing_recipients_phone_id`
1075 FOREIGN KEY (`phone_id`)
1076 REFERENCES `civicrm_phone`(`id`)
1077 ON DELETE SET NULL
1078 ON UPDATE RESTRICT;
1079 ");
1080
1081 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;");
1082
1083 return TRUE;
1084 }
1085
1086 /**
1087 * CRM-17663 - Dashboard schema changes
1088 *
1089 * @param \CRM_Queue_TaskContext $ctx
1090 *
1091 * @return bool
1092 */
1093 public static function dashboardSchemaUpdate(CRM_Queue_TaskContext $ctx) {
1094 if (!CRM_Core_BAO_SchemaHandler::checkIfIndexExists('civicrm_dashboard_contact', 'index_dashboard_id_contact_id')) {
1095 // Delete any stray duplicate rows and add unique index to prevent new dupes and enable INSERT/UPDATE combo query
1096 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');
1097 CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dashboard_contact ADD UNIQUE INDEX index_dashboard_id_contact_id (dashboard_id, contact_id);');
1098 }
1099 $domain = new CRM_Core_DAO_Domain();
1100 $domain->find(TRUE);
1101 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'content', FALSE, TRUE);
1102 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_minimized', FALSE, TRUE);
1103 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'is_fullscreen', FALSE, TRUE);
1104 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard_contact', 'created_date', FALSE, TRUE);
1105 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_fullscreen', FALSE, TRUE);
1106 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'is_minimized', FALSE, TRUE);
1107 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'column_no', FALSE, TRUE);
1108 CRM_Core_BAO_SchemaHandler::dropColumn('civicrm_dashboard', 'weight', FALSE, TRUE);
1109
1110 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET url = REPLACE(url, "&snippet=5", ""), fullscreen_url = REPLACE(fullscreen_url, "&snippet=5", "")');
1111
1112 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dashboard', 'cache_minutes')) {
1113 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."',
1114 [], TRUE, NULL, FALSE, FALSE);
1115 }
1116 if ($domain->locales) {
1117 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
1118 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL, TRUE);
1119 }
1120
1121 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 1440 WHERE name = "blog"');
1122 CRM_Core_DAO::executeQuery('UPDATE civicrm_dashboard SET cache_minutes = 7200 WHERE name IN ("activity","getting-started")');
1123 return TRUE;
1124 }
1125
1126 /**
1127 * CRM-19100 - Alter Index and Type for Image URL
1128 * @return bool
1129 */
1130 public static function alterIndexAndTypeForImageURL() {
1131 $length = [];
1132 CRM_Core_BAO_SchemaHandler::dropIndexIfExists('civicrm_contact', 'index_image_url');
1133 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.'");
1134
1135 $length['civicrm_contact']['image_URL'] = 128;
1136 CRM_Core_BAO_SchemaHandler::createIndexes(['civicrm_contact' => ['image_URL']], 'index', $length);
1137
1138 return TRUE;
1139 }
1140
1141 /**
1142 * Add mailing template type.
1143 *
1144 * @return bool
1145 */
1146 public static function addMailingTemplateType() {
1147 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_mailing', 'template_type', FALSE)) {
1148 CRM_Core_DAO::executeQuery('
1149 ALTER TABLE civicrm_mailing
1150 ADD COLUMN `template_type` varchar(64) NOT NULL DEFAULT \'traditional\' COMMENT \'The language/processing system used for email templates.\',
1151 ADD COLUMN `template_options` longtext COMMENT \'Advanced options used by the email templating system. (JSON encoded)\'
1152 ');
1153 }
1154 return TRUE;
1155 }
1156
1157 /**
1158 * CRM-18651 Add DataType column to Option Group Table
1159 * @return bool
1160 */
1161 public static function addDataTypeColumnToOptionGroupTable() {
1162 if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_option_group', 'data_type')) {
1163 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.'",
1164 [], TRUE, NULL, FALSE, FALSE);
1165 }
1166 $domain = new CRM_Core_DAO_Domain();
1167 $domain->find(TRUE);
1168 if ($domain->locales) {
1169 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
1170 CRM_Core_I18n_Schema::rebuildMultilingualSchema($locales, NULL, TRUE);
1171 }
1172
1173 CRM_Core_DAO::executeQuery("UPDATE `civicrm_option_group` SET `data_type` = 'Integer'
1174 WHERE name IN ('activity_type', 'gender', 'payment_instrument', 'participant_role', 'event_type')");
1175 return TRUE;
1176 }
1177
1178 /**
1179 * CRM-19372 Add field to store accepted credit credit cards for a payment processor.
1180 * @return bool
1181 */
1182 public static function addWysiwygPresets() {
1183 CRM_Core_BAO_OptionGroup::ensureOptionGroupExists([
1184 'name' => 'wysiwyg_presets',
1185 'title' => ts('WYSIWYG Editor Presets'),
1186 'is_reserved' => 1,
1187 ]);
1188 $values = [
1189 'default' => ['label' => ts('Default'), 'is_default' => 1],
1190 'civimail' => ['label' => ts('CiviMail'), 'component_id' => 'CiviMail'],
1191 'civievent' => ['label' => ts('CiviEvent'), 'component_id' => 'CiviEvent'],
1192 ];
1193 foreach ($values as $name => $value) {
1194 CRM_Core_BAO_OptionValue::ensureOptionValueExists($value + [
1195 'name' => $name,
1196 'option_group_id' => 'wysiwyg_presets',
1197 ]);
1198 }
1199 $fileName = Civi::paths()->getPath('[civicrm.files]/persist/crm-ckeditor-config.js');
1200 // Ensure the config file contains the allowedContent setting
1201 if (file_exists($fileName)) {
1202 $config = file_get_contents($fileName);
1203 $pos = strrpos($config, '};');
1204 $setting = "\n\tconfig.allowedContent = true;\n";
1205 $config = substr_replace($config, $setting, $pos, 0);
1206 unlink($fileName);
1207 $newFileName = Civi::paths()->getPath('[civicrm.files]/persist/crm-ckeditor-default.js');
1208 file_put_contents($newFileName, $config);
1209 }
1210 return TRUE;
1211 }
1212
1213 /**
1214 * Update Kenyan Provinces to reflect changes per CRM-20062
1215 *
1216 * @param \CRM_Queue_TaskContext $ctx
1217 */
1218 public static function updateKenyanProvinces(CRM_Queue_TaskContext $ctx) {
1219 $kenyaCountryID = CRM_Core_DAO::singleValueQuery('SELECT max(id) from civicrm_country where iso_code = "KE"');
1220 $oldProvinces = [
1221 'Nairobi Municipality',
1222 'Coast',
1223 'North-Eastern Kaskazini Mashariki',
1224 'Rift Valley',
1225 'Western Magharibi',
1226 ];
1227 self::deprecateStateProvinces($kenyaCountryID, $oldProvinces);
1228 return TRUE;
1229 }
1230
1231 /**
1232 * Deprecate provinces that no longer exist.
1233 *
1234 * @param int $countryID
1235 * @param array $provinces
1236 */
1237 public static function deprecateStateProvinces($countryID, $provinces) {
1238 foreach ($provinces as $province) {
1239 $existingStateID = CRM_Core_DAO::singleValueQuery("
1240 SELECT id FROM civicrm_state_province
1241 WHERE country_id = %1
1242 AND name = %2
1243 ",
1244 [1 => [$countryID, 'Int'], 2 => [$province, 'String']]);
1245
1246 if (!$existingStateID) {
1247 continue;
1248 }
1249 if (!CRM_Core_DAO::singleValueQuery("
1250 SELECT count(*) FROM civicrm_address
1251 WHERE state_province_id = %1
1252 ", [1 => [$existingStateID, 'Int']])
1253 ) {
1254 CRM_Core_DAO::executeQuery("DELETE FROM civicrm_state_province WHERE id = %1", [1 => [$existingStateID, 'Int']]);
1255 }
1256 else {
1257 $params = ['1' => [ts("Former - $province"), 'String']];
1258 CRM_Core_DAO::executeQuery("
1259 UPDATE civicrm_state_province SET name = %1 WHERE id = $existingStateID
1260 ", $params);
1261 }
1262 }
1263 }
1264
1265 /**
1266 * CRM-19961
1267 * Poputate newly added domain id column and add foriegn key onto table.
1268 */
1269 public static function populateSMSProviderDomainId() {
1270 $count = CRM_Core_DAO::singleValueQuery("SELECT count(id) FROM civicrm_domain");
1271 if ($count == 1) {
1272 CRM_Core_DAO::executeQuery("UPDATE civicrm_sms_provider SET domain_id = (SELECT id FROM civicrm_domain)");
1273 }
1274 if (!parent::checkFKExists('civicrm_sms_provider', 'FK_civicrm_sms_provider_domain_id')) {
1275 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 0;");
1276 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_sms_provider`
1277 ADD CONSTRAINT FK_civicrm_sms_provider_domain_id
1278 FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain`(`id`)
1279 ON DELETE SET NULL");
1280
1281 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;");
1282 }
1283 return TRUE;
1284 }
1285
1286 /**
1287 * CRM-16633 - Add activity type for Change Case Status
1288 *
1289 * @param \CRM_Queue_TaskContext $ctx
1290 *
1291 * @return bool
1292 */
1293 public static function addChangeCaseSubjectActivityType(CRM_Queue_TaskContext $ctx) {
1294 CRM_Core_BAO_OptionValue::ensureOptionValueExists([
1295 'option_group_id' => 'activity_type',
1296 'name' => 'Change Case Subject',
1297 'label' => ts('Change Case Subject'),
1298 'is_active' => TRUE,
1299 'component_id' => 'CiviCase',
1300 'icon' => 'fa-pencil-square-o',
1301 ]);
1302 return TRUE;
1303 }
1304
1305 /**
1306 * CRM-19986 fix schema differnces in civicrm_action_schedule
1307 */
1308 public static function fixSchemaOnCiviCRMActionSchedule() {
1309 if (!parent::checkFKExists('civicrm_action_schedule', 'FK_civicrm_action_schedule_sms_template_id')) {
1310 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_action_schedule`
1311 ADD CONSTRAINT FK_civicrm_action_schedule_sms_template_id
1312 FOREIGN KEY (`sms_template_id`) REFERENCES `civicrm_msg_template`(`id`)
1313 ON DELETE SET NULL");
1314 }
1315 CRM_Core_DAO::executeQuery("ALTER TABLE `civicrm_action_schedule`
1316 CHANGE `mapping_id` `mapping_id` varchar(64) COLLATE
1317 utf8_unicode_ci DEFAULT NULL COMMENT 'Name/ID of the mapping to use on this table'");
1318 return TRUE;
1319 }
1320
1321 public static function pickActivityRevisionPolicy(CRM_Queue_TaskContext $ctx) {
1322 // CRM-21052 - If site is using activity revisions, continue doing so. Otherwise, switch out.
1323 $count = CRM_Core_DAO::singleValueQuery('SELECT count(*) FROM civicrm_activity WHERE is_current_revision = 0 OR original_id IS NOT NULL');
1324 Civi::settings()->set('civicaseActivityRevisions', $count > 0);
1325 return TRUE;
1326 }
1327
1328 /**
1329 * Add in missing Tajikistan Subdivisions
1330 *
1331 * @param \CRM_Queue_TaskContext $ctx
1332 *
1333 * @return bool
1334 */
1335 public static function tajikistanMissingSubdivisions(CRM_Queue_TaskContext $ctx) {
1336 $sql = 'INSERT INTO civicrm_state_province (id, country_id, abbreviation, name) VALUES';
1337 $updates = [];
1338 if (!CRM_Core_DAO::singleValueQuery("Select id FROM civicrm_state_province WHERE country_id = 1209 AND name = 'Dushanbe'")) {
1339 $updates[] = '(NULL, 1209, "DU", "Dushanbe")';
1340 }
1341 if (!CRM_Core_DAO::singleValueQuery("Select id FROM civicrm_state_province WHERE country_id = 1209 AND name = 'Nohiyahoi Tobei JumhurĂ­'")) {
1342 $updates[] = '(NULL, 1209, "RA", "Nohiyahoi Tobei JumhurĂ­")';
1343 }
1344 if (!empty($updates)) {
1345 CRM_Core_DAO::executeQuery($sql . implode(', ', $updates));
1346 }
1347 return TRUE;
1348 }
1349
1350 /**
1351 * Remove the contribution logging reports which have been broken for a very long time.
1352 *
1353 * @param \CRM_Queue_TaskContext $ctx
1354 *
1355 * @return bool
1356 */
1357 public static function removeContributionLoggingReports(CRM_Queue_TaskContext $ctx) {
1358 if (class_exists('CRM_Report_Form_Contribute_LoggingDetail') || class_exists('CRM_Report_Form_Contribute_LoggingSummary')) {
1359 // Perhaps the site has overridden these classes. The core ones are broken but they
1360 // may have functional ones.
1361 return TRUE;
1362 }
1363 $options = civicrm_api3('OptionValue', 'get', ['option_group_id' => 'report_template', 'options' => ['limit' => 0]]);
1364 foreach ($options['values'] as $option) {
1365 if ($option['name'] === 'CRM_Report_Form_Contribute_LoggingDetail' || $option['name'] === 'CRM_Report_Form_Contribute_LoggingSummary') {
1366 $instances = civicrm_api3('ReportInstance', 'get', ['report_id' => $option['value']]);
1367 if ($instances['count']) {
1368 foreach ($instances['values'] as $instance) {
1369 if ($instance['navigation_id']) {
1370 civicrm_api3('Navigation', 'delete', ['id' => $instance['navigation_id']]);
1371 }
1372 civicrm_api3('ReportInstance', 'delete', ['id' => $instance['id']]);
1373 }
1374 }
1375 civicrm_api3('OptionValue', 'delete', ['id' => $option['id']]);
1376 }
1377 }
1378 return TRUE;
1379 }
1380
1381 /**
1382 * @return bool
1383 */
1384 protected function checkImageUploadDir() {
1385 $config = CRM_Core_Config::singleton();
1386 $check = new CRM_Utils_Check_Component_Security();
1387 return $config->imageUploadDir && $config->imageUploadURL && $check->isDirAccessible($config->imageUploadDir, $config->imageUploadURL);
1388 }
1389
1390 /**
1391 * CRM-20572 - Format date fields in Contrib Sybunt custom search's saved criteria.
1392 *
1393 * @param \CRM_Queue_TaskContext $ctx
1394 *
1395 * @return bool
1396 */
1397 public static function fixDateFieldsInSmartGroups(CRM_Queue_TaskContext $ctx) {
1398 $dao = CRM_Core_DAO::executeQuery("SELECT id, form_values FROM civicrm_saved_search WHERE form_values LIKE '%CRM_Contact_Form_Search_Custom_ContribSYBNT%'");
1399 while ($dao->fetch()) {
1400 $formValues = unserialize($dao->form_values);
1401 CRM_Contact_Form_Search_Custom_ContribSYBNT::formatSavedSearchFields($formValues);
1402 CRM_Core_DAO::executeQuery("UPDATE civicrm_saved_search SET form_values = %1 WHERE id = {$dao->id}", [1 => [serialize($formValues), 'String']]);
1403 }
1404 return TRUE;
1405 }
1406
1407 /**
1408 * CRM-20892 Convert default of created_date in civicrm_mailing table to NULL
1409 * @return bool
1410 */
1411 public static function civiMailingCreatedDateNull(CRM_Queue_TaskContext $ctx) {
1412 $dataType = 'timestamp';
1413 if (CRM_Utils_Check_Component_Timestamps::isFieldType('civicrm_mailing', 'created_date', 'datetime')) {
1414 $dataType = 'datetime';
1415 }
1416 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_mailing CHANGE created_date created_date {$dataType} NULL DEFAULT NULL COMMENT 'Date and time this mailing was created.'");
1417 return TRUE;
1418 }
1419
1420 }