commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-new / civicrm / CRM / Upgrade / Incremental / php / FourFour.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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 and the CiviCRM Licensing Exception. |
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 and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2015
32 * $Id$
33 *
34 */
35 class CRM_Upgrade_Incremental_php_FourFour {
36 const BATCH_SIZE = 5000;
37
38 const MAX_WORD_REPLACEMENT_SIZE = 255;
39
40 /**
41 * @param $errors
42 *
43 * @return bool
44 */
45 public function verifyPreDBstate(&$errors) {
46 return TRUE;
47 }
48
49 /**
50 * Compute any messages which should be displayed beforeupgrade.
51 *
52 * Note: This function is called iteratively for each upcoming
53 * revision to the database.
54 *
55 * @param $preUpgradeMessage
56 * @param string $rev
57 * a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
58 * @param null $currentVer
59 *
60 * @return void
61 */
62 public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
63 if ($rev == '4.4.beta1') {
64 $apiCalls = self::getConfigArraysAsAPIParams(FALSE);
65 $oversizedEntries = 0;
66 foreach ($apiCalls as $params) {
67 if (!self::isValidWordReplacement($params)) {
68 $oversizedEntries++;
69 }
70 }
71 if ($oversizedEntries > 0) {
72 $preUpgradeMessage .= '<br/>' . ts("WARNING: There are %1 word-replacement entries which will not be valid in v4.4+ (eg with over 255 characters). They will be dropped during upgrade. For details, consult the CiviCRM log.", array(
73 1 => $oversizedEntries,
74 ));
75 }
76 }
77 }
78
79 /**
80 * Compute any messages which should be displayed after upgrade.
81 *
82 * @param string $postUpgradeMessage
83 * alterable.
84 * @param string $rev
85 * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
86 * @return void
87 */
88 public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
89 if ($rev == '4.4.1') {
90 $config = CRM_Core_Config::singleton();
91 if (!empty($config->useIDS)) {
92 $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.");
93 }
94 }
95 if ($rev == '4.4.3') {
96 $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).');
97 }
98 if ($rev == '4.4.3') {
99 $query = "SELECT cft.id financial_trxn
100 FROM civicrm_financial_trxn cft
101 LEFT JOIN civicrm_entity_financial_trxn ceft ON ceft.financial_trxn_id = cft.id
102 LEFT JOIN civicrm_contribution cc ON ceft.entity_id = cc.id
103 WHERE ceft.entity_table = 'civicrm_contribution' AND cft.payment_instrument_id IS NULL;";
104 $dao = CRM_Core_DAO::executeQuery($query);
105 if ($dao->N) {
106 $postUpgradeMessage .= '<br /><br /><strong>' . ts('Your database contains %1 financial transaction records with no payment instrument (Paid By is empty). If you use the Accounting Batches feature this may result in unbalanced transactions. If you do not use this feature, you can ignore the condition (although you will be required to select a Paid By value for new transactions). <a href="%2" target="_blank">You can review steps to correct transactions with missing payment instruments on the wiki.</a>', array(
107 1 => $dao->N,
108 2 => 'http://wiki.civicrm.org/confluence/display/CRMDOC/Fixing+Transactions+Missing+a+Payment+Instrument+-+4.4.3+Upgrades',
109 )) . '</strong>';
110 }
111 }
112 if ($rev == '4.4.6') {
113 $postUpgradeMessage .= '<br /><br /><strong>' . ts('Your contact image urls have been upgraded. If your contact image urls did not follow the standard format for image Urls they have not been upgraded. Please check the log to see image urls that were not upgraded.');
114 }
115 }
116
117 /**
118 * @param $rev
119 *
120 * @return bool
121 */
122 public function upgrade_4_4_alpha1($rev) {
123 // task to process sql
124 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.alpha1')), 'task_4_4_x_runSql', $rev);
125
126 // Consolidate activity contacts CRM-12274.
127 $this->addTask('Consolidate activity contacts', 'activityContacts');
128
129 return TRUE;
130 }
131
132 /**
133 * @param $rev
134 */
135 public function upgrade_4_4_beta1($rev) {
136 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.beta1')), 'task_4_4_x_runSql', $rev);
137
138 // add new 'data' column in civicrm_batch
139 $query = 'ALTER TABLE civicrm_batch ADD data LONGTEXT NULL COMMENT "cache entered data"';
140 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
141
142 // check if batch entry data exists in civicrm_cache table
143 $query = 'SELECT path, data FROM civicrm_cache WHERE group_name = "batch entry"';
144 $dao = CRM_Core_DAO::executeQuery($query);
145 while ($dao->fetch()) {
146 // get batch id $batchId[2]
147 $batchId = explode('-', $dao->path);
148 $data = unserialize($dao->data);
149
150 // move the data to civicrm_batch table
151 CRM_Core_DAO::setFieldValue('CRM_Batch_DAO_Batch', $batchId[2], 'data', json_encode(array('values' => $data)));
152 }
153
154 // delete entries from civicrm_cache table
155 $query = 'DELETE FROM civicrm_cache WHERE group_name = "batch entry"';
156 CRM_Core_DAO::executeQuery($query);
157
158 $this->addTask('Migrate custom word-replacements', 'wordReplacements');
159 }
160
161 /**
162 * @param $rev
163 */
164 public function upgrade_4_4_1($rev) {
165 $config = CRM_Core_Config::singleton();
166 // CRM-13327 upgrade handling for the newly added name badges
167 $ogID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'name_badge', 'id', 'name');
168 $nameBadges = array_flip(array_values(CRM_Core_BAO_OptionValue::getOptionValuesAssocArrayFromName('name_badge')));
169 unset($nameBadges['Avery 5395']);
170 if (!empty($nameBadges)) {
171 $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}';
172 $query = "UPDATE civicrm_option_value
173 SET value = '{$dimension}'
174 WHERE option_group_id = %1 AND name = 'Fattorini Name Badge 100x65'";
175
176 CRM_Core_DAO::executeQuery($query, array(1 => array($ogID, 'Integer')));
177 }
178 else {
179 $dimensions = array(
180 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}',
181 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}',
182 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}',
183 );
184 $insertStatements = array(
185 1 => "($ogID, %1, '{$dimensions[1]}', %1, NULL, 0, NULL, 2, NULL, 0, 0, 1, NULL, NULL)",
186 2 => "($ogID, %2, '{$dimensions[2]}', %2, NULL, 0, NULL, 3, NULL, 0, 0, 1, NULL, NULL)",
187 3 => "($ogID, %3, '{$dimensions[3]}', %3, NULL, 0, NULL, 4, NULL, 0, 0, 1, NULL, NULL)",
188 );
189
190 $queryParams = array(
191 1 => array('A6 Badge Portrait 150x106', 'String'),
192 2 => array('Fattorini Name Badge 100x65', 'String'),
193 3 => array('Hanging Badge 3-3/4" x 4-3"/4', 'String'),
194 );
195
196 foreach ($insertStatements as $values) {
197 $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;
198 CRM_Core_DAO::executeQuery($query, $queryParams);
199 }
200 }
201
202 // CRM-12578 - Prior to this version a CSS file under drupal would disable core css
203 if (!empty($config->customCSSURL) && strpos($config->userFramework, 'Drupal') === 0) {
204 // The new setting doesn't exist yet - need to create it first
205 CRM_Core_BAO_Setting::updateSettingsFromMetaData();
206 CRM_Core_BAO_Setting::setItem('1', CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'disable_core_css');
207 }
208
209 // CRM-13701 - Fix $config->timeInputFormat
210 $sql = "
211 SELECT time_format
212 FROM civicrm_preferences_date
213 WHERE time_format IS NOT NULL
214 AND time_format <> ''
215 LIMIT 1
216 ";
217 $timeInputFormat = CRM_Core_DAO::singleValueQuery($sql);
218 if ($timeInputFormat && $timeInputFormat != $config->timeInputFormat) {
219 $params = array('timeInputFormat' => $timeInputFormat);
220 CRM_Core_BAO_ConfigSetting::add($params);
221 }
222
223 // CRM-13698 - add 'Available' and 'No-show' activity statuses
224 $insertStatus = array();
225 $nsinc = $avinc = $inc = 0;
226 if (!CRM_Core_OptionGroup::getValue('activity_status', 'Available', 'name')) {
227 $insertStatus[] = "(%1, 'Available', %2, 'Available', NULL, 0, NULL, %3, 0, 0, 1, NULL, NULL)";
228 $avinc = $inc = 1;
229 }
230 if (!CRM_Core_OptionGroup::getValue('activity_status', 'No_show', 'name')) {
231 $insertStatus[] = "(%1, 'No-show', %4, 'No_show', NULL, 0, NULL, %5, 0, 0, 1, NULL, NULL)";
232 $nsinc = $inc + 1;
233 }
234 if (!empty($insertStatus)) {
235 $acOptionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_status', 'id', 'name');
236 $maxVal = CRM_Core_DAO::singleValueQuery("SELECT MAX(ROUND(op.value)) FROM civicrm_option_value op WHERE op.option_group_id = $acOptionGroupID");
237 $maxWeight = CRM_Core_DAO::singleValueQuery("SELECT MAX(weight) FROM civicrm_option_value WHERE option_group_id = $acOptionGroupID");
238
239 $p[1] = array($acOptionGroupID, 'Integer');
240 if ($avinc) {
241 $p[2] = array($avinc + $maxVal, 'Integer');
242 $p[3] = array($avinc + $maxWeight, 'Integer');
243 }
244 if ($nsinc) {
245 $p[4] = array($nsinc + $maxVal, 'Integer');
246 $p[5] = array($nsinc + $maxWeight, 'Integer');
247 }
248 $insertStatus = implode(',', $insertStatus);
249
250 $sql = "
251 INSERT INTO
252 civicrm_option_value (`option_group_id`, label, `value`, `name`, `grouping`, `filter`, `is_default`, `weight`, `is_optgroup`, `is_reserved`, `is_active`, `component_id`, `visibility_id`)
253 VALUES {$insertStatus}";
254 CRM_Core_DAO::executeQuery($sql, $p);
255 }
256
257 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.1')), 'task_4_4_x_runSql', $rev);
258 $this->addTask('Patch word-replacement schema', 'wordReplacements_patch', $rev);
259 }
260
261 /**
262 * @param $rev
263 *
264 * @return bool
265 */
266 public function upgrade_4_4_4($rev) {
267 $fkConstraint = array();
268 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'activity_id')) {
269 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_activity_id` FOREIGN KEY (`activity_id`) REFERENCES `civicrm_activity` (`id`) ON DELETE CASCADE";
270 }
271 if (!CRM_Core_DAO::checkFKConstraintInFormat('civicrm_activity_contact', 'contact_id')) {
272 $fkConstraint[] = "ADD CONSTRAINT `FK_civicrm_activity_contact_contact_id` FOREIGN KEY (`contact_id`) REFERENCES `civicrm_contact` (`id`) ON DELETE CASCADE;
273 ";
274 }
275
276 if (!empty($fkConstraint)) {
277 $fkConstraint = implode(',', $fkConstraint);
278 $sql = "ALTER TABLE `civicrm_activity_contact`
279 {$fkConstraint}
280 ";
281 // CRM-14036 : delete entries of un-mapped contacts
282 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
283 LEFT JOIN civicrm_contact c
284 ON c.id = ac.contact_id
285 WHERE c.id IS NULL;
286 ");
287 // delete entries of un-mapped activities
288 CRM_Core_DAO::executeQuery("DELETE ac FROM civicrm_activity_contact ac
289 LEFT JOIN civicrm_activity a
290 ON a.id = ac.activity_id
291 WHERE a.id IS NULL;
292 ");
293
294 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=0;");
295 CRM_Core_DAO::executeQuery($sql);
296 CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS=1;");
297 }
298
299 // task to process sql
300 $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => '4.4.4')), 'task_4_4_x_runSql', $rev);
301
302 // CRM-13892 : add `name` column to dashboard schema
303 $query = "
304 ALTER TABLE civicrm_dashboard
305 ADD name varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'Internal name of dashlet.' AFTER domain_id ";
306 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
307
308 $dashboard = new CRM_Core_DAO_Dashboard();
309 $dashboard->find();
310 $values = '';
311 while ($dashboard->fetch()) {
312 $urlElements = explode('/', $dashboard->url);
313 if ($urlElements[1] == 'dashlet') {
314 $url = explode('&', $urlElements[2]);
315 $name = $url[0];
316 }
317 elseif ($urlElements[1] == 'report') {
318 $url = explode('&', $urlElements[3]);
319 $name = 'report/' . $url[0];
320 }
321 $values .= "
322 WHEN {$dashboard->id} THEN '{$name}'
323 ";
324 }
325
326 $query = "
327 UPDATE civicrm_dashboard
328 SET name = CASE id
329 {$values}
330 END;
331 ";
332 CRM_Core_DAO::executeQuery($query, array(), TRUE, NULL, FALSE, FALSE);
333
334 // CRM-13998 : missing alter statements for civicrm_report_instance
335 $this->addTask(ts('Confirm civicrm_report_instance sql table for upgrades'), 'updateReportInstanceTable');
336
337 return TRUE;
338 }
339
340 /**
341 * @param $rev
342 */
343 public function upgrade_4_4_6($rev) {
344 $sql = "SELECT count(*) AS count FROM INFORMATION_SCHEMA.STATISTICS where " .
345 "TABLE_SCHEMA = database() AND INDEX_NAME = 'index_image_url' AND TABLE_NAME = 'civicrm_contact';";
346 $dao = CRM_Core_DAO::executeQuery($sql);
347 $dao->fetch();
348 if ($dao->count < 1) {
349 $sql = "CREATE INDEX index_image_url ON civicrm_contact (image_url);";
350 $dao = CRM_Core_DAO::executeQuery($sql);
351 }
352 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
353 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
354 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
355 $endId = $startId + self::BATCH_SIZE - 1;
356 $title = ts('Upgrade image_urls (%1 => %2)', array(1 => $startId, 2 => $endId));
357 $this->addTask($title, 'upgradeImageUrls', $startId, $endId);
358 }
359 }
360
361 /**
362 * @param $rev
363 * @param $originalVer
364 * @param $latestVer
365 *
366 * @return void
367 */
368 public function upgrade_4_4_7($rev, $originalVer, $latestVer) {
369 // For WordPress/Joomla(?), cleanup broken image_URL from 4.4.6 upgrades - https://issues.civicrm.org/jira/browse/CRM-14971
370 $exBackendUrl = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=XXX', TRUE); // URL formula from 4.4.6 upgrade
371 $exFrontendUrl = CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=XXX', TRUE, NULL, TRUE, TRUE);
372 if ($originalVer == '4.4.6' && $exBackendUrl != $exFrontendUrl) {
373 $minId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(min(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
374 $maxId = CRM_Core_DAO::singleValueQuery('SELECT coalesce(max(id),0) FROM civicrm_contact WHERE image_URL IS NOT NULL');
375 for ($startId = $minId; $startId <= $maxId; $startId += self::BATCH_SIZE) {
376 $endId = $startId + self::BATCH_SIZE - 1;
377 $title = ts('Upgrade image_urls (%1 => %2)', array(1 => $startId, 2 => $endId));
378 $this->addTask($title, 'cleanupBackendImageUrls', $startId, $endId);
379 }
380 }
381 $this->addTask(ts('Update saved search information'), 'changeSavedSearch');
382 }
383
384 /**
385 * Upgrade image URLs.
386 *
387 * @param \CRM_Queue_TaskContext $ctx
388 * @param $startId
389 * @param $endId
390 *
391 * @return bool
392 */
393 public static function upgradeImageUrls(CRM_Queue_TaskContext $ctx, $startId, $endId) {
394 $dao = self::findContactImageUrls($startId, $endId);
395 $failures = array();
396 $config = CRM_Core_Config::singleton();
397 while ($dao->fetch()) {
398 $imageURL = $dao->image_url;
399 $baseurl = CIVICRM_UF_BASEURL;
400 //CRM-15897 - gross hack for joomla to remove the administrator/
401 if ($config->userFramework == 'Joomla') {
402 $baseurl = str_replace("/administrator/", "/", $baseurl);
403 }
404 $baselen = strlen($baseurl);
405 if (substr($imageURL, 0, $baselen) == $baseurl) {
406 $photo = basename($dao->image_url);
407 $fullpath = $config->customFileUploadDir . $photo;
408 if (file_exists($fullpath)) {
409 // For anyone who upgraded 4.4.6 release (eg 4.4.0=>4.4.6), the $newImageUrl incorrectly used backend URLs.
410 // For anyone who skipped 4.4.6 (eg 4.4.0=>4.4.7), the $newImageUrl correctly uses frontend URLs
411 self::setContactImageUrl($dao->id,
412 CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=' . $photo, TRUE, NULL, TRUE, TRUE));
413 }
414 else {
415 $failures[$dao->id] = $dao->image_url;
416 }
417 }
418 else {
419 $failures[$dao->id] = $dao->image_url;
420 }
421 }
422 CRM_Core_Error::debug_var('imageUrlsNotUpgraded', $failures);
423 return TRUE;
424 }
425
426 /**
427 * Change saved search.
428 *
429 * @param \CRM_Queue_TaskContext $ctx
430 *
431 * @return bool
432 */
433 public static function changeSavedSearch(CRM_Queue_TaskContext $ctx) {
434 $membershipStatuses = array_flip(CRM_Member_PseudoConstant::membershipStatus());
435
436 $dao = new CRM_Contact_DAO_SavedSearch();
437 $dao->find();
438 while ($dao->fetch()) {
439 $formValues = NULL;
440 if (!empty($dao->form_values)) {
441 $formValues = unserialize($dao->form_values);
442 }
443 if (!empty($formValues['mapper'])) {
444 foreach ($formValues['mapper'] as $key => $value) {
445 foreach ($value as $k => $v) {
446 if ($v[0] == 'Membership' && in_array($v[1], array('membership_status', 'membership_status_id'))) {
447 $value = $formValues['value'][$key][$k];
448 $op = $formValues['operator'][$key][$k];
449 if ($op == 'IN') {
450 $value = trim($value);
451 $value = str_replace('(', '', $value);
452 $value = str_replace(')', '', $value);
453
454 $v = explode(',', $value);
455 $value = array();
456 foreach ($v as $k1 => $v2) {
457 if (is_numeric($v2)) {
458 break 2;
459 }
460 $value[$k1] = $membershipStatuses[$v2];
461 }
462 $formValues['value'][$key][$k] = "(" . implode(',', $value) . ")";
463 }
464 elseif (in_array($op, array('=', '!='))) {
465 if (is_numeric($value)) {
466 break;
467 }
468 $formValues['value'][$key][$k] = $membershipStatuses[$value];
469 }
470 }
471 }
472 }
473 $dao->form_values = serialize($formValues);
474 $dao->save();
475 }
476 }
477
478 return TRUE;
479 }
480
481 /**
482 * For WordPress/Joomla(?) sites which upgraded to 4.4.6, find back-end image_URLs
483 * (e.g. "http://example.com/wp-admin/admin.php?page=CiviCRM&amp;q=civicrm/contact/imagefile&amp;photo=123.jpg")
484 * and convert them to front-end URLs
485 * (e.g. "http://example.com/?page=CiviCRM&amp;q=civicrm/contact/imagefile&amp;photo=123.jpg").
486 *
487 * @param CRM_Queue_TaskContext $ctx
488 * @param int $startId
489 * @param int $endId
490 * @return bool
491 */
492 public static function cleanupBackendImageUrls(CRM_Queue_TaskContext $ctx, $startId, $endId) {
493 $dao = self::findContactImageUrls($startId, $endId);
494 while ($dao->fetch()) {
495 $imageUrl = str_replace('&amp;', '&', $dao->image_url);
496 if (preg_match(":civicrm/contact/imagefile.*photo=:", $imageUrl)) {
497 // looks like one of ours
498 $imageUrlParts = parse_url($imageUrl);
499 parse_str($imageUrlParts['query'], $imageUrlQuery);
500 self::setContactImageUrl($dao->id,
501 CRM_Utils_System::url('civicrm/contact/imagefile', 'photo=' . $imageUrlQuery['photo'], TRUE, NULL, TRUE, TRUE));
502 }
503 }
504 return TRUE;
505 }
506
507 /**
508 * @param int $startId
509 * @param int $endId
510 * @return CRM_Core_DAO
511 * columns include "id" and "image_URL"
512 */
513 public static function findContactImageUrls($startId, $endId) {
514 $sql = "
515 SELECT id, image_url
516 FROM civicrm_contact
517 WHERE 1
518 AND id BETWEEN %1 AND %2
519 AND image_URL IS NOT NULL
520 ";
521
522 $params = array(
523 1 => array($startId, 'Integer'),
524 2 => array($endId, 'Integer'),
525 );
526 $dao = CRM_Core_DAO::executeQuery($sql, $params, TRUE, NULL, FALSE, FALSE);
527 return $dao;
528 }
529
530 /**
531 * @param int $cid
532 * @param string $newImageUrl
533 */
534 public static function setContactImageUrl($cid, $newImageUrl) {
535 $sql = 'UPDATE civicrm_contact SET image_url=%1 WHERE id=%2';
536 $params = array(
537 1 => array($newImageUrl, 'String'),
538 2 => array($cid, 'Integer'),
539 );
540 $updatedao = CRM_Core_DAO::executeQuery($sql, $params);
541 }
542
543 /**
544 * Update activity contacts CRM-12274
545 *
546 * @param CRM_Queue_TaskContext $ctx
547 *
548 * @return bool
549 * TRUE for success
550 */
551 public static function activityContacts(CRM_Queue_TaskContext $ctx) {
552 $upgrade = new CRM_Upgrade_Form();
553
554 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
555 $ovValue[] = $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
556 $ovValue[] = $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
557 $ovValue[] = $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
558
559 $optionGroupID = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'activity_contacts', 'id', 'name');
560 if (!empty($ovValue)) {
561 $ovValues = implode(', ', $ovValue);
562 $query = "
563 UPDATE civicrm_option_value
564 SET is_reserved = 1
565 WHERE option_group_id = {$optionGroupID} AND value IN ($ovValues)";
566
567 $dao = CRM_Core_DAO::executeQuery($query);
568 }
569
570 if (!$assigneeID) {
571 $assigneeID = 1;
572 $value[] = "({$optionGroupID}, 'Activity Assignees', 1, 'Activity Assignees', 1, 1, 1)";
573 }
574 if (!$sourceID) {
575 $sourceID = 2;
576 $value[] = "({$optionGroupID}, 'Activity Source', 2, 'Activity Source', 2, 1, 1)";
577 }
578 if (!$targetID) {
579 $targetID = 3;
580 $value[] = "({$optionGroupID}, 'Activity Targets', 3, 'Activity Targets', 3, 1, 1)";
581 }
582
583 if (!$assigneeID || !$sourceID || !$targetID) {
584 $insert = "
585 INSERT INTO civicrm_option_value
586 (option_group_id, label, value, name, weight, is_reserved, is_active)
587 VALUES
588
589 ";
590 $values = implode(', ', $value);
591 $query = $insert . $values;
592 $dao = CRM_Core_DAO::executeQuery($query);
593 }
594
595 // sometimes an user does not make a clean backup and the above table
596 // already exists, so lets delete this table - CRM-13665
597 $query = "DROP TABLE IF EXISTS civicrm_activity_contact";
598 $dao = CRM_Core_DAO::executeQuery($query);
599
600 $query = "
601 CREATE TABLE IF NOT EXISTS civicrm_activity_contact (
602 id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Activity contact id',
603 activity_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the activity for this record.',
604 contact_id int(10) unsigned NOT NULL COMMENT 'Foreign key to the contact for this record.',
605 record_type_id int(10) unsigned DEFAULT NULL COMMENT 'The record type id for this row',
606 PRIMARY KEY (id),
607 UNIQUE KEY UI_activity_contact (contact_id,activity_id,record_type_id),
608 KEY FK_civicrm_activity_contact_activity_id (activity_id)
609 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
610 ";
611
612 $dao = CRM_Core_DAO::executeQuery($query);
613
614 $query = "
615 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
616 SELECT activity_id, target_contact_id, {$targetID} as record_type_id
617 FROM civicrm_activity_target";
618
619 $dao = CRM_Core_DAO::executeQuery($query);
620
621 $query = "
622 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
623 SELECT activity_id, assignee_contact_id, {$assigneeID} as record_type_id
624 FROM civicrm_activity_assignment";
625 $dao = CRM_Core_DAO::executeQuery($query);
626
627 $query = "
628 INSERT INTO civicrm_activity_contact (activity_id, contact_id, record_type_id)
629 SELECT id, source_contact_id, {$sourceID} as record_type_id
630 FROM civicrm_activity
631 WHERE source_contact_id IS NOT NULL";
632
633 $dao = CRM_Core_DAO::executeQuery($query);
634
635 $query = "DROP TABLE civicrm_activity_target";
636 $dao = CRM_Core_DAO::executeQuery($query);
637
638 $query = "DROP TABLE civicrm_activity_assignment";
639 $dao = CRM_Core_DAO::executeQuery($query);
640
641 $query = "ALTER TABLE civicrm_activity
642 DROP FOREIGN KEY FK_civicrm_activity_source_contact_id";
643
644 $dao = CRM_Core_DAO::executeQuery($query);
645
646 $query = "ALTER TABLE civicrm_activity DROP COLUMN source_contact_id";
647 $dao = CRM_Core_DAO::executeQuery($query);
648
649 return TRUE;
650 }
651
652 /**
653 * Migrate word-replacements from $config to civicrm_word_replacement
654 *
655 * @param CRM_Queue_TaskContext $ctx
656 *
657 * @return bool
658 * TRUE for success
659 * @see http://issues.civicrm.org/jira/browse/CRM-13187
660 */
661 public static function wordReplacements(CRM_Queue_TaskContext $ctx) {
662 $query = "
663 CREATE TABLE IF NOT EXISTS `civicrm_word_replacement` (
664 `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Word replacement ID',
665 `find_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which need to be replaced',
666 `replace_word` varchar(255) COLLATE utf8_bin COMMENT 'Word which will replace the word in find',
667 `is_active` tinyint COMMENT 'Is this entry active?',
668 `match_type` enum('wildcardMatch', 'exactMatch') DEFAULT 'wildcardMatch',
669 `domain_id` int unsigned COMMENT 'FK to Domain ID. This is for Domain specific word replacement',
670 PRIMARY KEY ( `id` ),
671 UNIQUE INDEX `UI_domain_find` (domain_id, find_word),
672 CONSTRAINT FK_civicrm_word_replacement_domain_id FOREIGN KEY (`domain_id`) REFERENCES `civicrm_domain`(`id`)
673 ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
674 ";
675 $dao = CRM_Core_DAO::executeQuery($query);
676
677 self::rebuildWordReplacementTable();
678 return TRUE;
679 }
680
681 /**
682 * Fix misconfigured constraints created in 4.4.0. To distinguish the good
683 * and bad configurations, we change the constraint name from "UI_find"
684 * (the original name in 4.4.0) to "UI_domain_find" (the new name in
685 * 4.4.1).
686 *
687 * @param CRM_Queue_TaskContext $ctx
688 * @param $rev
689 *
690 * @return bool
691 * TRUE for success
692 * @see http://issues.civicrm.org/jira/browse/CRM-13655
693 */
694 public static function wordReplacements_patch(CRM_Queue_TaskContext $ctx, $rev) {
695 if (CRM_Core_DAO::checkConstraintExists('civicrm_word_replacement', 'UI_find')) {
696 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP FOREIGN KEY FK_civicrm_word_replacement_domain_id;");
697 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY FK_civicrm_word_replacement_domain_id;");
698 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement DROP KEY UI_find;");
699 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';");
700 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';");
701 CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_word_replacement ADD CONSTRAINT UI_domain_find UNIQUE KEY `UI_domain_find` (`domain_id`,`find_word`);");
702 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`);");
703 }
704 return TRUE;
705 }
706
707 /**
708 * (Queue Task Callback)
709 */
710 public static function task_4_4_x_runSql(CRM_Queue_TaskContext $ctx, $rev) {
711 $upgrade = new CRM_Upgrade_Form();
712 $upgrade->processSQL($rev);
713
714 return TRUE;
715 }
716
717 /**
718 * Syntatic sugar for adding a task which (a) is in this class and (b) has
719 * a high priority.
720 *
721 * After passing the $funcName, you can also pass parameters that will go to
722 * the function. Note that all params must be serializable.
723 */
724 protected function addTask($title, $funcName) {
725 $queue = CRM_Queue_Service::singleton()->load(array(
726 'type' => 'Sql',
727 'name' => CRM_Upgrade_Form::QUEUE_NAME,
728 ));
729
730 $args = func_get_args();
731 $title = array_shift($args);
732 $funcName = array_shift($args);
733 $task = new CRM_Queue_Task(
734 array(get_class($this), $funcName),
735 $args,
736 $title
737 );
738 $queue->createItem($task, array('weight' => -1));
739 }
740
741 /**
742 * Get all the word-replacements stored in config-arrays
743 * and convert them to params for the WordReplacement.create API.
744 *
745 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
746 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
747 * step behaves consistently even as the BAO evolves in future versions.
748 * However, if there's a bug in here prior to 4.4.0, we should apply the
749 * bugfix in both places.
750 *
751 * @param bool $rebuildEach
752 * Whether to perform rebuild after each individual API call.
753 * @return array
754 * Each item is $params for WordReplacement.create
755 * @see CRM_Core_BAO_WordReplacement::convertConfigArraysToAPIParams
756 */
757 public static function getConfigArraysAsAPIParams($rebuildEach) {
758 $wordReplacementCreateParams = array();
759 // get all domains
760 $result = civicrm_api3('domain', 'get', array(
761 'return' => array('locale_custom_strings'),
762 ));
763 if (!empty($result["values"])) {
764 foreach ($result["values"] as $value) {
765 $params = array();
766 $params["domain_id"] = $value["id"];
767 $params["options"] = array('wp-rebuild' => $rebuildEach);
768 // unserialize word match string
769 $localeCustomArray = array();
770 if (!empty($value["locale_custom_strings"])) {
771 $localeCustomArray = unserialize($value["locale_custom_strings"]);
772 }
773 if (!empty($localeCustomArray)) {
774 $wordMatchArray = array();
775 // Traverse Language array
776 foreach ($localeCustomArray as $localCustomData) {
777 // Traverse status array "enabled" "disabled"
778 foreach ($localCustomData as $status => $matchTypes) {
779 $params["is_active"] = ($status == "enabled") ? TRUE : FALSE;
780 // Traverse Match Type array "wildcardMatch" "exactMatch"
781 foreach ($matchTypes as $matchType => $words) {
782 $params["match_type"] = $matchType;
783 foreach ($words as $word => $replace) {
784 $params["find_word"] = $word;
785 $params["replace_word"] = $replace;
786 $wordReplacementCreateParams[] = $params;
787 }
788 }
789 }
790 }
791 }
792 }
793 }
794 return $wordReplacementCreateParams;
795 }
796
797 /**
798 * Get all the word-replacements stored in config-arrays
799 * and write them out as records in civicrm_word_replacement.
800 *
801 * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
802 * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
803 * step behaves consistently even as the BAO evolves in future versions.
804 * However, if there's a bug in here prior to 4.4.0, we should apply the
805 * bugfix in both places.
806 */
807 public static function rebuildWordReplacementTable() {
808 civicrm_api3('word_replacement', 'replace', array(
809 'options' => array('match' => array('domain_id', 'find_word')),
810 'values' => array_filter(self::getConfigArraysAsAPIParams(FALSE), array(__CLASS__, 'isValidWordReplacement')),
811 ));
812 CRM_Core_BAO_WordReplacement::rebuild();
813 }
814
815
816 /**
817 * CRM-13998 missing alter statements for civicrm_report_instance
818 */
819 public function updateReportInstanceTable() {
820
821 // add civicrm_report_instance.name
822
823 $sql = "SELECT count(*) FROM information_schema.columns "
824 . "WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'name' ";
825
826 $res = CRM_Core_DAO::singleValueQuery($sql);
827
828 if ($res <= 0) {
829 $sql = "ALTER TABLE civicrm_report_instance ADD `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'when combined with report_id/template uniquely identifies the instance'";
830 $res = CRM_Core_DAO::executeQuery($sql);
831 }
832
833 // add civicrm_report_instance args
834
835 $sql = "SELECT count(*) FROM information_schema.columns WHERE table_schema = database() AND table_name = 'civicrm_report_instance' AND COLUMN_NAME = 'args' ";
836
837 $res = CRM_Core_DAO::singleValueQuery($sql);
838
839 if ($res <= 0) {
840 $sql = "ALTER TABLE civicrm_report_instance ADD `args` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'arguments that are passed in the url when invoking the instance'";
841
842 $res = CRM_Core_DAO::executeQuery($sql);
843 }
844
845 return TRUE;
846 }
847
848 /**
849 * @param array $params
850 * @return bool
851 * TRUE if $params is valid
852 */
853 public static function isValidWordReplacement($params) {
854 $result = strlen($params['find_word']) <= self::MAX_WORD_REPLACEMENT_SIZE && strlen($params['replace_word']) <= self::MAX_WORD_REPLACEMENT_SIZE;
855 if (!$result) {
856 CRM_Core_Error::debug_var('invalidWordReplacement', $params);
857 }
858 return $result;
859 }
860
861 }