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