Merge remote-tracking branch 'upstream/4.5' into 4.5-master-2015-03-04-18-48-05
[civicrm-core.git] / CRM / Upgrade / Incremental / php / FourFive.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 *
29 * @package CRM
30 * @copyright CiviCRM LLC (c) 2004-2014
31 * $Id$
32 *
33 */
34 class CRM_Upgrade_Incremental_php_FourFive {
35 const BATCH_SIZE = 5000;
36
37 /**
38 * @param $errors
39 *
40 * @return bool
41 */
42 public function verifyPreDBstate(&$errors) {
43 return TRUE;
44 }
45
46 /**
47 * Compute any messages which should be displayed beforeupgrade.
48 *
49 * Note: This function is called iteratively for each upcoming
50 * revision to the database.
51 *
52 * @param $preUpgradeMessage
53 * @param string $rev
54 * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
55 * @param null $currentVer
56 *
57 * @return void
58 */
59 public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
60 }
61
62 /**
63 * Compute any messages which should be displayed after upgrade.
64 *
65 * @param string $postUpgradeMessage
66 * alterable.
67 * @param string $rev
68 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
69 * @return void
70 */
71 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
72 if ($rev == '4.5.alpha1') {
73 $postUpgradeMessage .= '<br /><br />' . ts('Default versions of the following System Workflow Message Templates have been modified to handle new functionality: <ul><li>Contributions - Receipt (off-line)</li><li>Contributions - Receipt (on-line)</li><li>Contributions - Recurring Start and End Notification</li><li>Contributions - Recurring Updates</li><li>Memberships - Receipt (on-line)</li><li>Memberships - Signup and Renewal Receipts (off-line)</li><li>Pledges - Acknowledgement</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). (<a href="%1">learn more...</a>)', array(1 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Updating+System+Workflow+Message+Templates+after+Upgrades+-+method+1+-+kdiff'));
74 $postUpgradeMessage .= '<br /><br />' . ts('This release allows you to view and edit multiple-record custom field sets in a table format which will be more usable in some cases. You can try out the format by navigating to Administer > Custom Data & Screens > Custom Fields. Click Settings for a custom field set and change Display Style to "Tab with Tables".');
75 $postUpgradeMessage .= '<br /><br />' . ts('This release changes the way that anonymous event registrations match participants with existing contacts. By default, all event participants will be matched with existing individuals using the Unsupervised rule, even if multiple registrations with the same email address are allowed. However, you can now select a different matching rule to use for each event. Please review your events to make sure you choose the appropriate matching rule and collect sufficient information for it to match contacts.');
76 }
77 if ($rev == '4.5.beta2') {
78 $postUpgradeMessage .= '<br /><br />' . ts('If you use CiviMail for newsletters or other communications, check out the new sample CiviMail templates which use responsive design to optimize display on mobile devices (Administer > Communications > Message Templates ).');
79 }
80 if ($rev == '4.5.1') {
81 $postUpgradeMessage .= '<br /><br />' . ts('WARNING: If you use CiviCase with v4.5.alpha*, v4.5.beta*, or v4.5.0, it is possible that previous upgrades corrupted some CiviCase metadata. If you have not already done so, please identify any custom field sets, smart groups, or reports which refer to CiviCase and ensure that they are properly configured.');
82 }
83 }
84
85 /**
86 * @param $rev
87 *
88 * @return bool
89 */
90 public function upgrade_4_5_alpha1($rev) {
91 // task to process sql
92 $this->addTask(ts('Migrate honoree information to module_data'), 'migrateHonoreeInfo');
93 $this->addTask(ts('Upgrade DB to 4.5.alpha1: SQL'), 'task_4_5_x_runSql', $rev);
94 $this->addTask(ts('Set default for Individual name fields configuration'), 'addNameFieldOptions');
95
96 // CRM-14522 - The below schema checking is done as foreign key name
97 // for pdf_format_id column varies for different databases
98 // if DB is been into upgrade for 3.4.2 version, it would have pdf_format_id name for FK
99 // else FK_civicrm_msg_template_pdf_format_id
100 $config = CRM_Core_Config::singleton();
101 $dbUf = DB::parseDSN($config->dsn);
102 $query = "
103 SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
104 WHERE TABLE_NAME = 'civicrm_msg_template'
105 AND CONSTRAINT_TYPE = 'FOREIGN KEY'
106 AND TABLE_SCHEMA = %1
107 ";
108 $params = array(1 => array($dbUf['database'], 'String'));
109 $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
110 if ($dao->fetch()) {
111 if ($dao->CONSTRAINT_NAME == 'FK_civicrm_msg_template_pdf_format_id' ||
112 $dao->CONSTRAINT_NAME == 'pdf_format_id'
113 ) {
114 $sqlDropFK = "ALTER TABLE `civicrm_msg_template`
115 DROP FOREIGN KEY `{$dao->CONSTRAINT_NAME}`,
116 DROP KEY `{$dao->CONSTRAINT_NAME}`";
117 CRM_Core_DAO::executeQuery($sqlDropFK, CRM_Core_DAO::$_nullArray, TRUE, NULL, FALSE, FALSE);
118 }
119 }
120
121 return TRUE;
122 }
123
124 /**
125 * @param $rev
126 *
127 * @return bool
128 */
129 public function upgrade_4_5_beta9($rev) {
130 $this->addTask(ts('Upgrade DB to 4.5.beta9: SQL'), 'task_4_5_x_runSql', $rev);
131
132 $entityTable = array(
133 'Participant' => 'civicrm_participant_payment',
134 'Contribution' => 'civicrm_contribution',
135 'Membership' => 'civicrm_membership',
136 );
137
138 foreach ($entityTable as $label => $tableName) {
139 list($minId, $maxId) = CRM_Core_DAO::executeQuery("SELECT coalesce(min(id),0), coalesce(max(id),0)
140 FROM {$tableName}")->getDatabaseResult()->fetchRow();
141 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
142 $endId = $startId + self::BATCH_SIZE - 1;
143 $title = ts("Upgrade DB to 4.5.beta9: Fix line items for {$label} (%1 => %2)", array(
144 1 => $startId,
145 2 => $endId,
146 ));
147 $this->addTask($title, 'task_4_5_0_fixLineItem', $startId, $endId, $label);
148 }
149 }
150 return TRUE;
151 }
152
153 /**
154 * (Queue Task Callback)
155 *
156 * update the line items
157 *
158 *
159 * @param CRM_Queue_TaskContext $ctx
160 * @param int $startId
161 * the first/lowest entity ID to convert.
162 * @param int $endId
163 * the last/highest entity ID to convert.
164 * @param
165 *
166 * @return bool
167 */
168 public static function task_4_5_0_fixLineItem(CRM_Queue_TaskContext $ctx, $startId, $endId, $entityTable) {
169
170 $sqlParams = array(
171 1 => array($startId, 'Integer'),
172 2 => array($endId, 'Integer'),
173 );
174 switch ($entityTable) {
175 case 'Contribution':
176 // update all the line item entity_table and entity_id with contribution due to bug CRM-15055
177 CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item li
178 INNER JOIN civicrm_contribution cc ON cc.id = li.contribution_id
179 SET entity_id = li.contribution_id, entity_table = 'civicrm_contribution'
180 WHERE li.contribution_id IS NOT NULL AND li.entity_table <> 'civicrm_participant' AND (cc.id BETWEEN %1 AND %2)", $sqlParams);
181
182 // update the civicrm_line_item.contribution_id
183 CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item li
184 INNER JOIN civicrm_contribution cc ON cc.id = li.entity_id
185 SET contribution_id = entity_id
186 WHERE li.contribution_id IS NULL AND li.entity_table = 'civicrm_contribution' AND (cc.id BETWEEN %1 AND %2)", $sqlParams);
187 break;
188
189 case 'Participant':
190 // update the civicrm_line_item.contribution_id
191 CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item li
192 INNER JOIN civicrm_participant_payment pp ON pp.participant_id = li.entity_id
193 SET li.contribution_id = pp.contribution_id
194 WHERE li.entity_table = 'civicrm_participant' AND li.contribution_id IS NULL AND (pp.id BETWEEN %1 AND %2)", $sqlParams);
195 break;
196
197 case 'Membership':
198 $upgrade = new CRM_Upgrade_Form();
199 // update the line item of membership
200 CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item li
201 INNER JOIN civicrm_membership_payment mp ON mp.contribution_id = li.contribution_id
202 INNER JOIN civicrm_membership cm ON mp.membership_id = cm.id
203 INNER JOIN civicrm_price_field_value pv ON pv.id = li.price_field_value_id
204 SET li.entity_table = 'civicrm_membership', li.entity_id = mp.membership_id
205 WHERE li.entity_table = 'civicrm_contribution'
206 AND pv.membership_type_id IS NOT NULL AND cm.membership_type_id = pv.membership_type_id AND (cm.id BETWEEN %1 AND %2)", $sqlParams);
207
208 CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item li
209 INNER JOIN civicrm_membership_payment mp ON mp.contribution_id = li.contribution_id
210 INNER JOIN civicrm_price_field_value pv ON pv.id = li.price_field_value_id
211 SET li.entity_table = 'civicrm_membership', li.entity_id = mp.membership_id
212 WHERE li.entity_table = 'civicrm_contribution'
213 AND pv.membership_type_id IS NOT NULL AND (mp.membership_id BETWEEN %1 AND %2)", $sqlParams);
214
215 CRM_Core_DAO::executeQuery("INSERT INTO civicrm_line_item (entity_table, entity_id, price_field_id, label,
216 qty, unit_price, line_total, price_field_value_id, financial_type_id)
217 SELECT 'civicrm_membership', cm.id, cpf.id price_field_id, cpfv.label, 1 as qty, cpfv.amount, cpfv.amount line_total,
218 cpfv.id price_field_value_id, cpfv.financial_type_id FROM civicrm_membership cm
219 LEFT JOIN civicrm_membership_payment cmp ON cmp.membership_id = cm.id
220 INNER JOIN civicrm_price_field_value cpfv ON cpfv.membership_type_id = cm.membership_type_id
221 INNER JOIN civicrm_price_field cpf ON cpf.id = cpfv.price_field_id
222 INNER JOIN civicrm_price_set cps ON cps.id = cpf.price_set_id
223 WHERE cmp.contribution_id IS NULL AND cps.name = 'default_membership_type_amount' AND (cm.id BETWEEN %1 AND %2)", $sqlParams);
224 break;
225 }
226 return TRUE;
227 }
228
229 /**
230 * Add defaults for the newly introduced name fields configuration in 'contact_edit_options' setting
231 *
232 * @param CRM_Queue_TaskContext $ctx
233 *
234 * @return bool
235 * TRUE for success
236 */
237 public static function addNameFieldOptions(CRM_Queue_TaskContext $ctx) {
238 $query = "SELECT `value` FROM `civicrm_setting` WHERE `group_name` = 'CiviCRM Preferences' AND `name` = 'contact_edit_options'";
239 $dao = CRM_Core_DAO::executeQuery($query);
240 $dao->fetch();
241 $oldValue = unserialize($dao->value);
242
243 $newValue = $oldValue . '12\ 114\ 115\ 116\ 117\ 1';
244
245 $query = "UPDATE `civicrm_setting` SET `value` = %1 WHERE `group_name` = 'CiviCRM Preferences' AND `name` = 'contact_edit_options'";
246 $params = array(1 => array(serialize($newValue), 'String'));
247 CRM_Core_DAO::executeQuery($query, $params);
248
249 return TRUE;
250 }
251
252 /**
253 * Migrate honoree information to uf_join.module_data as honoree columns (text and title) will be dropped
254 * on DB upgrade
255 *
256 * @param CRM_Queue_TaskContext $ctx
257 *
258 * @return bool
259 * TRUE for success
260 */
261 public static function migrateHonoreeInfo(CRM_Queue_TaskContext $ctx) {
262 $query = "ALTER TABLE `civicrm_uf_join`
263 ADD COLUMN `module_data` longtext COMMENT 'Json serialized array of data used by the ufjoin.module'";
264 CRM_Core_DAO::executeQuery($query);
265
266 $honorTypes = array_keys(CRM_Core_OptionGroup::values('honor_type'));
267 $ufGroupDAO = new CRM_Core_DAO_UFGroup();
268 $ufGroupDAO->name = 'new_individual';
269 $ufGroupDAO->find(TRUE);
270
271 $query = "SELECT * FROM civicrm_contribution_page";
272 $dao = CRM_Core_DAO::executeQuery($query);
273
274 if ($dao->N) {
275 $domain = new CRM_Core_DAO_Domain();
276 $domain->find(TRUE);
277 while ($dao->fetch()) {
278 $honorParams = array('soft_credit' => array('soft_credit_types' => $honorTypes));
279 if ($domain->locales) {
280 $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
281 foreach ($locales as $locale) {
282 $honor_block_title = "honor_block_title_{$locale}";
283 $honor_block_text = "honor_block_text_{$locale}";
284 $honorParams['soft_credit'] += array(
285 $locale => array(
286 'honor_block_title' => $dao->$honor_block_title,
287 'honor_block_text' => $dao->$honor_block_text,
288 ),
289 );
290 }
291 }
292 else {
293 $honorParams['soft_credit'] += array(
294 'default' => array(
295 'honor_block_title' => $dao->honor_block_title,
296 'honor_block_text' => $dao->honor_block_text,
297 ),
298 );
299 }
300 $ufJoinParam = array(
301 'module' => 'soft_credit',
302 'entity_table' => 'civicrm_contribution_page',
303 'is_active' => $dao->honor_block_is_active,
304 'entity_id' => $dao->id,
305 'uf_group_id' => $ufGroupDAO->id,
306 'module_data' => json_encode($honorParams),
307 );
308 CRM_Core_BAO_UFJoin::create($ufJoinParam);
309 }
310 }
311
312 return TRUE;
313 }
314
315 /**
316 * (Queue Task Callback)
317 */
318 public static function task_4_5_x_runSql(CRM_Queue_TaskContext $ctx, $rev) {
319 $upgrade = new CRM_Upgrade_Form();
320 $upgrade->processSQL($rev);
321
322 return TRUE;
323 }
324
325 /**
326 * Syntactic sugar for adding a task which (a) is in this class and (b) has
327 * a high priority.
328 *
329 * After passing the $funcName, you can also pass parameters that will go to
330 * the function. Note that all params must be serializable.
331 */
332 protected function addTask($title, $funcName) {
333 $queue = CRM_Queue_Service::singleton()->load(array(
334 'type' => 'Sql',
335 'name' => CRM_Upgrade_Form::QUEUE_NAME,
336 ));
337
338 $args = func_get_args();
339 $title = array_shift($args);
340 $funcName = array_shift($args);
341 $task = new CRM_Queue_Task(
342 array(get_class($this), $funcName),
343 $args,
344 $title
345 );
346 $queue->createItem($task, array('weight' => -1));
347 }
348
349 }