3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
30 * @copyright CiviCRM LLC (c) 2004-2013
34 class CRM_Upgrade_Incremental_php_FourFour
{
35 const BATCH_SIZE
= 5000;
37 function verifyPreDBstate(&$errors) {
42 * Compute any messages which should be displayed beforeupgrade
44 * Note: This function is called iteratively for each upcoming
45 * revision to the database.
47 * @param $postUpgradeMessage string, alterable
48 * @param $rev string, a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'
51 function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
55 * Compute any messages which should be displayed after upgrade
57 * @param $postUpgradeMessage string, alterable
58 * @param $rev string, an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs
61 function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
62 if ($rev == '4.4.1') {
63 $config = CRM_Core_Config
::singleton();
64 if (!empty($config->useIDS
)) {
65 $postUpgradeMessage .= '<br />' . ts("The setting to skip IDS check has been removed. Your site has this configured in civicrm.settings.php but it will no longer work. Instead, use the new permission 'skip IDS check' to bypass the IDS system.");
68 if ($rev == '4.4.3') {
69 $postUpgradeMessage .= '<br /><br />' . ts('Default versions of the following System Workflow Message Templates have been modified to handle new functionality: <ul><li>Events - Registration Confirmation and Receipt (on-line)</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).');
73 function upgrade_4_4_alpha1($rev) {
74 // task to process sql
75 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.alpha1')), 'task_4_4_x_runSql', $rev);
77 // Consolidate activity contacts CRM-12274.
78 $this->addTask('Consolidate activity contacts', 'activityContacts');
83 function upgrade_4_4_beta1($rev) {
84 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.beta1')), 'task_4_4_x_runSql', $rev);
86 // add new 'data' column in civicrm_batch
87 $query = 'ALTER TABLE civicrm_batch ADD data LONGTEXT NULL COMMENT "cache entered data"';
88 CRM_Core_DAO
::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
90 // check if batch entry data exists in civicrm_cache table
91 $query = 'SELECT path, data FROM civicrm_cache WHERE group_name = "batch entry"';
92 $dao = CRM_Core_DAO
::executeQuery($query);
93 while ($dao->fetch()) {
94 // get batch id $batchId[2]
95 $batchId = explode('-', $dao->path
);
96 $data = unserialize($dao->data
);
98 // move the data to civicrm_batch table
99 CRM_Core_DAO
::setFieldValue('CRM_Batch_DAO_Batch', $batchId[2], 'data', json_encode(array('values' => $data)));
102 // delete entries from civicrm_cache table
103 $query = 'DELETE FROM civicrm_cache WHERE group_name = "batch entry"';
104 CRM_Core_DAO
::executeQuery($query);
106 $this->addTask('Migrate custom word-replacements', 'wordReplacements');
109 function upgrade_4_4_1($rev) {
110 $config = CRM_Core_Config
::singleton();
111 // CRM-13327 upgrade handling for the newly added name badges
112 $ogID = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_OptionGroup', 'name_badge', 'id', 'name');
113 $nameBadges = array_flip(array_values(CRM_Core_BAO_OptionValue
::getOptionValuesAssocArrayFromName('name_badge')));
114 unset($nameBadges['Avery 5395']);
115 if (!empty($nameBadges)) {
116 $dimension = '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":4,"metric":"mm","lMargin":6,"tMargin":19,"SpaceX":0,"SpaceY":0,"width":100,"height":65,"lPadding":0,"tPadding":0}';
117 $query = "UPDATE civicrm_option_value
118 SET value = '{$dimension}'
119 WHERE option_group_id = %1 AND name = 'Fattorini Name Badge 100x65'";
121 CRM_Core_DAO
::executeQuery($query, array(1 => array($ogID, 'Integer')));
125 1 => '{"paper-size":"a4","orientation":"landscape","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":1,"metric":"mm","lMargin":25,"tMargin":27,"SpaceX":0,"SpaceY":35,"width":106,"height":150,"lPadding":5,"tPadding":5}',
126 2 => '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":4,"metric":"mm","lMargin":6,"tMargin":19,"SpaceX":0,"SpaceY":0,"width":100,"height":65,"lPadding":0,"tPadding":0}',
127 3 => '{"paper-size":"a4","orientation":"portrait","font-name":"times","font-size":6,"font-style":"","NX":2,"NY":2,"metric":"mm","lMargin":10,"tMargin":28,"SpaceX":0,"SpaceY":0,"width":96,"height":121,"lPadding":5,"tPadding":5}',
129 $insertStatements = array(
130 1 => "($ogID, %1, '{$dimensions[1]}', %1, NULL, 0, NULL, 2, NULL, 0, 0, 1, NULL, NULL)",
131 2 => "($ogID, %2, '{$dimensions[2]}', %2, NULL, 0, NULL, 3, NULL, 0, 0, 1, NULL, NULL)",
132 3 => "($ogID, %3, '{$dimensions[3]}', %3, NULL, 0, NULL, 4, NULL, 0, 0, 1, NULL, NULL)",
135 $queryParams = array(
136 1 => array('A6 Badge Portrait 150x106', 'String'),
137 2 => array('Fattorini Name Badge 100x65', 'String'),
138 3 => array('Hanging Badge 3-3/4" x 4-3"/4', 'String'),
141 foreach ($insertStatements as $values) {
142 $query = 'INSERT INTO civicrm_option_value (`option_group_id`, `label`, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `description`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`) VALUES' . $values;
143 CRM_Core_DAO
::executeQuery($query, $queryParams);
147 // CRM-12578 - Prior to this version a CSS file under drupal would disable core css
148 if (!empty($config->customCSSURL
) && strpos($config->userFramework
, 'Drupal') === 0) {
149 // The new setting doesn't exist yet - need to create it first
150 CRM_Core_BAO_Setting
::updateSettingsFromMetaData();
151 CRM_Core_BAO_Setting
::setItem('1', CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'disable_core_css');
154 // CRM-13701 - Fix $config->timeInputFormat
157 FROM civicrm_preferences_date
158 WHERE time_format IS NOT NULL
159 AND time_format <> ''
162 $timeInputFormat = CRM_Core_DAO
::singleValueQuery($sql);
163 if ($timeInputFormat && $timeInputFormat != $config->timeInputFormat
) {
164 $params = array('timeInputFormat' => $timeInputFormat);
165 CRM_Core_BAO_ConfigSetting
::add($params);
168 // CRM-13698 - add 'Available' and 'No-show' activity statuses
169 $insertStatus = array();
170 $nsinc = $avinc = $inc = 0;
171 if (!CRM_Core_OptionGroup
::getValue('activity_status', 'Available', 'name')) {
172 $insertStatus[] = "(%1, 'Available', %2, 'Available', NULL, 0, NULL, %3, 0, 0, 1, NULL, NULL)";
175 if (!CRM_Core_OptionGroup
::getValue('activity_status', 'No_show', 'name')) {
176 $insertStatus[] = "(%1, 'No-show', %4, 'No_show', NULL, 0, NULL, %5, 0, 0, 1, NULL, NULL)";
179 if (!empty($insertStatus)) {
180 $acOptionGroupID = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_status', 'id', 'name');
181 $maxVal = CRM_Core_DAO
::singleValueQuery("SELECT MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = $acOptionGroupID");
182 $maxWeight = CRM_Core_DAO
::singleValueQuery("SELECT MAX(weight) FROM civicrm_option_value WHERE option_group_id = $acOptionGroupID");
184 $p[1] = array($acOptionGroupID, 'Integer');
186 $p[2] = array($avinc+
$maxVal, 'Integer');
187 $p[3] = array($avinc+
$maxWeight, 'Integer');
190 $p[4] = array($nsinc+
$maxVal, 'Integer');
191 $p[5] = array($nsinc+
$maxWeight, 'Integer');
193 $insertStatus = implode(',', $insertStatus);
197 civicrm_option_value (`option_group_id`, label, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`)
198 VALUES {$insertStatus}";
199 CRM_Core_DAO
::executeQuery($sql, $p);
202 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.1')), 'task_4_4_x_runSql', $rev);
203 $this->addTask('Patch word-replacement schema', 'wordReplacements_patch', $rev);
207 * Update activity contacts CRM-12274
209 * @return bool TRUE for success
211 static function activityContacts(CRM_Queue_TaskContext
$ctx) {
212 $upgrade = new CRM_Upgrade_Form();
214 $activityContacts = CRM_Core_OptionGroup
::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
215 $ovValue[] = $sourceID = CRM_Utils_Array
::key('Activity Source', $activityContacts);
216 $ovValue[] = $assigneeID = CRM_Utils_Array
::key('Activity Assignees', $activityContacts);
217 $ovValue[] = $targetID = CRM_Utils_Array
::key('Activity Targets', $activityContacts);
219 $optionGroupID = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_contacts', 'id', 'name');
220 if (!empty($ovValue)) {
221 $ovValues = implode(', ', $ovValue);
223 UPDATE civicrm_option_value
225 WHERE option_group_id = {$optionGroupID} AND value IN ($ovValues)";
227 $dao = CRM_Core_DAO
::executeQuery($query);
232 $value[] = "({$optionGroupID}, 'Activity Assignees', 1, 'Activity Assignees', 1, 1, 1)";
236 $value[] = "({$optionGroupID}, 'Activity Source', 2, 'Activity Source', 2, 1, 1)";
240 $value[] = "({$optionGroupID}, 'Activity Targets', 3, 'Activity Targets', 3, 1, 1)";
243 if (!$assigneeID ||
!$sourceID ||
!$targetID ) {
245 INSERT INTO civicrm_option_value
246 (option_group_id, label, value, name, weight, is_reserved, is_active)
250 $values = implode(', ', $value);
251 $query = $insert . $values;
252 $dao = CRM_Core_DAO
::executeQuery($query);
255 // sometimes an user does not make a clean backup and the above table
256 // already exists, so lets delete this table - CRM-13665
257 $query = "DROP TABLE IF EXISTS civicrm_activity_contact";
258 $dao = CRM_Core_DAO
::executeQuery($query);
261 CREATE TABLE IF NOT EXISTS civicrm_activity_contact (
262 id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Activity contact id',
263 activity_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the activity for this record.',
264 contact_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the contact for this record.',
265 record_type_id int(10) unsigned DEFAULT NULL COMMENT 'The record type id for this row',
267 UNIQUE KEY UI_activity_contact (contact_id,activity_id,record_type_id),
268 KEY FK_civicrm_activity_contact_activity_id (activity_id)
269 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
272 $dao = CRM_Core_DAO
::executeQuery($query);
276 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
277 SELECT activity_id, target_contact_id, {$targetID} as record_type_id
278 FROM civicrm_activity_target";
280 $dao = CRM_Core_DAO
::executeQuery($query);
283 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
284 SELECT activity_id, assignee_contact_id, {$assigneeID} as record_type_id
285 FROM civicrm_activity_assignment";
286 $dao = CRM_Core_DAO
::executeQuery($query);
289 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
290 SELECT id, source_contact_id, {$sourceID} as record_type_id
291 FROM civicrm_activity
292 WHERE source_contact_id IS NOT NULL";
294 $dao = CRM_Core_DAO
::executeQuery($query);
296 $query = "DROP TABLE civicrm_activity_target";
297 $dao = CRM_Core_DAO
::executeQuery($query);
299 $query = "DROP TABLE civicrm_activity_assignment";
300 $dao = CRM_Core_DAO
::executeQuery($query);
302 $query = "ALTER TABLE civicrm_activity
303 DROP FOREIGN KEY FK_civicrm_activity_source_contact_id";
305 $dao = CRM_Core_DAO
::executeQuery($query);
307 $query = "ALTER TABLE civicrm_activity DROP COLUMN source_contact_id";
308 $dao = CRM_Core_DAO
::executeQuery($query);
314 * Migrate word-replacements from $config to civicrm_word_replacement
316 * @return bool TRUE for success
317 * @see http://issues.civicrm.org/jira/browse/CRM-13187
319 static function wordReplacements(CRM_Queue_TaskContext
$ctx) {
321 CREATE TABLE IF NOT EXISTS `civicrm_word_replacement` (
322 `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Word replacement ID',
323 `find_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which need to be replaced',
324 `replace_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which will replace the word in find',
325 `is_active` tinyint COMMENT 'Is this entry active?',
326 `match_type` enum('wildcardMatch', 'exactMatch') DEFAULT 'wildcardMatch',
327 `domain_id` int unsigned COMMENT 'FK to Domain ID. This is for Domain specific word replacement',
328 PRIMARY KEY ( `id` ),
329 UNIQUE INDEX `UI_domain_find` (domain_id, find_word),
330 CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain`(`id`)
331 ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
333 $dao = CRM_Core_DAO
::executeQuery($query);
335 self
::rebuildWordReplacementTable();
340 * Fix misconfigured constraints created in 4.4.0. To distinguish the good
341 * and bad configurations, we change the constraint name from "UI_find"
342 * (the original name in 4.4.0) to "UI_domain_find" (the new name in
345 * @return bool TRUE for success
346 * @see http://issues.civicrm.org/jira/browse/CRM-13655
348 static function wordReplacements_patch(CRM_Queue_TaskContext
$ctx, $rev) {
349 if (CRM_Core_DAO
::checkConstraintExists('civicrm_word_replacement', 'UI_find')) {
350 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement DROP FOREIGN KEY FK_civicrm_word_replacement_domain_id;");
351 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY FK_civicrm_word_replacement_domain_id;");
352 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY UI_find;");
353 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement MODIFY COLUMN `find_word` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Word which need to be replaced';");
354 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement MODIFY COLUMN `replace_word` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Word which will replace the word in find';");
355 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT UI_domain_find UNIQUE KEY `UI_domain_find` (`domain_id`,`find_word`);");
356 CRM_Core_DAO
::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain` (`id`);");
362 * (Queue Task Callback)
364 static function task_4_4_x_runSql(CRM_Queue_TaskContext
$ctx, $rev) {
365 $upgrade = new CRM_Upgrade_Form();
366 $upgrade->processSQL($rev);
372 * Syntatic sugar for adding a task which (a) is in this class and (b) has
375 * After passing the $funcName, you can also pass parameters that will go to
376 * the function. Note that all params must be serializable.
378 protected function addTask($title, $funcName) {
379 $queue = CRM_Queue_Service
::singleton()->load(array(
381 'name' => CRM_Upgrade_Form
::QUEUE_NAME
,
384 $args = func_get_args();
385 $title = array_shift($args);
386 $funcName = array_shift($args);
387 $task = new CRM_Queue_Task(
388 array(get_class($this), $funcName),
392 $queue->createItem($task, array('weight' => -1));
396 * Get all the word-replacements stored in config-arrays
397 * and convert them to params for the WordReplacement.create API.
399 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
400 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
401 * step behaves consistently even as the BAO evolves in future versions.
402 * However, if there's a bug in here prior to 4.4.0, we should apply the
403 * bugfix in both places.
405 * @param bool $rebuildEach whether to perform rebuild after each individual API call
406 * @return array Each item is $params for WordReplacement.create
407 * @see CRM_Core_BAO_WordReplacement::convertConfigArraysToAPIParams
409 static function getConfigArraysAsAPIParams($rebuildEach) {
410 $wordReplacementCreateParams = array();
412 $result = civicrm_api3('domain', 'get', array(
413 'return' => array('locale_custom_strings'),
415 if (!empty($result["values"])) {
416 foreach ($result["values"] as $value) {
418 $params["domain_id"] = $value["id"];
419 $params["options"] = array('wp-rebuild' => $rebuildEach);
420 // unserialize word match string
421 $localeCustomArray = unserialize($value["locale_custom_strings"]);
422 if (!empty($localeCustomArray)) {
423 $wordMatchArray = array();
424 // Traverse Language array
425 foreach ($localeCustomArray as $localCustomData) {
426 // Traverse status array "enabled" "disabled"
427 foreach ($localCustomData as $status => $matchTypes) {
428 $params["is_active"] = ($status == "enabled")?
TRUE:FALSE;
429 // Traverse Match Type array "wildcardMatch" "exactMatch"
430 foreach ($matchTypes as $matchType => $words) {
431 $params["match_type"] = $matchType;
432 foreach ($words as $word => $replace) {
433 $params["find_word"] = $word;
434 $params["replace_word"] = $replace;
435 $wordReplacementCreateParams[] = $params;
443 return $wordReplacementCreateParams;
447 * Get all the word-replacements stored in config-arrays
448 * and write them out as records in civicrm_word_replacement.
450 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
451 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
452 * step behaves consistently even as the BAO evolves in future versions.
453 * However, if there's a bug in here prior to 4.4.0, we should apply the
454 * bugfix in both places.
456 public static function rebuildWordReplacementTable() {
457 civicrm_api3('word_replacement', 'replace', array(
458 'options' => array('match' => array('domain_id', 'find_word')),
459 'values' => self
::getConfigArraysAsAPIParams(FALSE),
461 CRM_Core_BAO_WordReplacement
::rebuild();