3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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 +--------------------------------------------------------------------+
28 * Upgrade logic for FiveTwenty */
29 class CRM_Upgrade_Incremental_php_FiveTwenty
extends CRM_Upgrade_Incremental_Base
{
32 * @var $relationshipTypes array
33 * api call result keyed on relationship_type.id
35 protected static $relationshipTypes;
38 * Compute any messages which should be displayed beforeupgrade.
40 * Note: This function is called iteratively for each upcoming
41 * revision to the database.
43 * @param string $preUpgradeMessage
45 * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
46 * @param null $currentVer
48 public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
49 // Example: Generate a pre-upgrade message.
50 // if ($rev == '5.12.34') {
51 // $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
56 * Compute any messages which should be displayed after upgrade.
58 * @param string $postUpgradeMessage
61 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
63 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
64 // Example: Generate a post-upgrade message.
65 // if ($rev == '5.12.34') {
66 // $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'.");
71 * Important! All upgrade functions MUST add a 'runSql' task.
72 * Uncomment and use the following template for a new upgrade version
73 * (change the x in the function name):
76 // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
85 public function upgrade_5_20_alpha1($rev) {
86 $this->addTask('Add frontend title column to contribution page table', 'addColumn', 'civicrm_contribution_page',
87 'frontend_title', "varchar(255) DEFAULT NULL COMMENT 'Contribution Page Public title'", TRUE, '5.20.alpha1');
88 $this->addTask('Add is_template field to civicrm_contribution', 'addColumn', 'civicrm_contribution', 'is_template',
89 "tinyint(4) DEFAULT '0' COMMENT 'Shows this is a template for recurring contributions.'", FALSE, '5.20.alpha1');
90 $this->addTask('Add order_reference field to civicrm_financial_trxn', 'addColumn', 'civicrm_financial_trxn', 'order_reference',
91 "varchar(255) COMMENT 'Payment Processor external order reference'", FALSE, '5.20.alpha1');
92 $config = CRM_Core_Config
::singleton();
93 if (in_array('CiviCase', $config->enableComponents
)) {
94 $this->addTask('Change direction of autoassignees in case type xml', 'changeCaseTypeAutoassignee');
96 $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
97 $this->addTask('Add "Template" contribution status', 'templateStatus');
98 $this->addTask('Update smart groups to rename filters on case_from and case_to to case_start_date and case_end_date', 'updateSmartGroups', [
100 ['old' => 'case_from_relative', 'new' => 'case_start_date_relative'],
101 ['old' => 'case_from_start_date_high', 'new' => 'case_start_date_high'],
102 ['old' => 'case_from_start_date_low', 'new' => 'case_start_date_low'],
103 ['old' => 'case_to_relative', 'new' => 'case_end_date_relative'],
104 ['old' => 'case_to_end_date_high', 'new' => 'case_end_date_high'],
105 ['old' => 'case_to_end_date_low', 'new' => 'case_end_date_low'],
108 $this->addTask('Update smart groups where jcalendar fields have been converted to datepicker', 'updateSmartGroups', [
109 'datepickerConversion' => [
116 public static function templateStatus(CRM_Queue_TaskContext
$ctx) {
117 CRM_Core_BAO_OptionValue
::ensureOptionValueExists([
118 'option_group_id' => 'contribution_status',
119 'name' => 'Template',
120 'label' => ts('Template'),
122 'component_id' => 'CiviContribute',
128 * Change direction of activity autoassignees in case type xml for
129 * bidirectional relationship types if they point the other way. This is
130 * mostly a visual issue on the case type edit screen and doesn't affect
131 * normal operation, but could lead to confusion and a future mixup.
133 * ONLY for ones using database storage - don't want to "fork" case types
134 * that aren't currently forked.
136 * Earlier iterations of this used the api and array manipulation
137 * and then another iteration used SimpleXML manipulation, but both
138 * suffered from weirdnesses in how conversion back and forth worked.
140 * Here we use SQL and a regex. The thing we're changing is pretty
141 * well-defined and unique:
142 * <default_assignee_relationship>N_b_a</default_assignee_relationship>
146 public static function changeCaseTypeAutoassignee() {
147 self
::$relationshipTypes = civicrm_api3('RelationshipType', 'get', [
148 'options' => ['limit' => 0],
151 // Get all case types definitions that are using db storage
152 $dao = CRM_Core_DAO
::executeQuery("SELECT id, definition FROM civicrm_case_type WHERE definition IS NOT NULL AND definition <> ''");
153 while ($dao->fetch()) {
154 self
::processCaseTypeAutoassignee($dao->id
, $dao->definition
);
160 * Process a single case type
162 * @param $caseTypeId int
163 * @param $definition string
166 public static function processCaseTypeAutoassignee($caseTypeId, $definition) {
168 // find the autoassignees
169 preg_match_all('/<default_assignee_relationship>(.*?)<\/default_assignee_relationship>/', $definition, $matches);
170 // $matches[1][n] has the text inside the xml tag, e.g. 2_a_b
171 foreach ($matches[1] as $index => $match) {
175 // parse out existing id and direction
176 list($relationshipTypeId, $direction1) = explode('_', $match);
177 // we only care about ones that are b_a
178 if ($direction1 === 'b') {
179 // we only care about bidirectional
180 if (self
::isBidirectionalRelationship($relationshipTypeId)) {
182 // $matches[0][n] has the whole match including the xml tag
183 $definition = str_replace($matches[0][$index], "<default_assignee_relationship>{$relationshipTypeId}_a_b</default_assignee_relationship>", $definition);
191 1 => [$definition, 'String'],
192 2 => [$caseTypeId, 'Integer'],
194 CRM_Core_DAO
::executeQuery("UPDATE civicrm_case_type SET definition = %1 WHERE id = %2", $sqlParams);
195 //echo "UPDATE civicrm_case_type SET definition = '" . CRM_Core_DAO::escapeString($sqlParams[1][0]) . "' WHERE id = {$sqlParams[2][0]}\n";
200 * Check if this is bidirectional, based on label. In the situation where
201 * we're using this we don't care too much about the edge case where name
202 * might not also be bidirectional.
204 * @param $relationshipTypeId int
208 private static function isBidirectionalRelationship($relationshipTypeId) {
209 if (isset(self
::$relationshipTypes[$relationshipTypeId])) {
210 if (self
::$relationshipTypes[$relationshipTypeId]['label_a_b'] === self
::$relationshipTypes[$relationshipTypeId]['label_b_a']) {