Merge pull request #9900 from fuzionnz/CRM-20181-deprecate_crm_core_error_fatal
[civicrm-core.git] / CRM / Contact / Form / Merge.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
0f03f337 6 | Copyright CiviCRM LLC (c) 2004-2017 |
6a488035
TO
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
0f03f337 31 * @copyright CiviCRM LLC (c) 2004-2017
6a488035
TO
32 */
33
86538308 34/**
5a409b50 35 * Class CRM_Contact_Form_Merge.
86538308 36 */
6a488035 37class CRM_Contact_Form_Merge extends CRM_Core_Form {
5af77f03 38 // The id of the contact that there's a duplicate for; this one will
39 // possibly inherit some of $_oid's properties and remain in the system.
6a488035
TO
40 var $_cid = NULL;
41
5af77f03 42 // The id of the other contact - the duplicate one that will get deleted.
6a488035
TO
43 var $_oid = NULL;
44
45 var $_contactType = NULL;
46
dc6285d5 47 /**
48 * Query limit to be retained in the urls.
49 *
50 * @var int
51 */
52 var $limit;
53
5af77f03 54 /**
55 * String for quickform bug handling.
56 *
57 * FIXME: QuickForm can't create advcheckboxes with value set to 0 or '0' :(
58 * see HTML_QuickForm_advcheckbox::setValues() - but patching that doesn't
59 * help, as QF doesn't put the 0-value elements in exportValues() anyway...
60 * to side-step this, we use the below UUID as a (re)placeholder
61 *
62 * @var string
63 */
8ef12e64 64 var $_qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9';
65
00be9182 66 public function preProcess() {
6a488035
TO
67 if (!CRM_Core_Permission::check('merge duplicate contacts')) {
68 CRM_Core_Error::fatal(ts('You do not have access to this page'));
69 }
70
353ffa53
TO
71 $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);
72 $oid = CRM_Utils_Request::retrieve('oid', 'Positive', $this, TRUE);
6a488035
TO
73 $flip = CRM_Utils_Request::retrieve('flip', 'Positive', $this, FALSE);
74
e9299e88 75 $this->_rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE);
353ffa53 76 $this->_gid = $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE);
6a488035 77 $this->_mergeId = CRM_Utils_Request::retrieve('mergeId', 'Positive', $this, FALSE);
dc6285d5 78 $this->limit = CRM_Utils_Request::retrieve('limit', 'Positive', $this, FALSE);
79 $urlParams = "reset=1&rgid={$this->_rgid}&gid={$this->_gid}&limit=" . $this->limit;
6a488035 80
6d5a3f21
CW
81 // Sanity check
82 if ($cid == $oid) {
83 CRM_Core_Error::statusBounce(ts('Cannot merge a contact with itself.'));
84 }
85
6a488035 86 if (!CRM_Dedupe_BAO_Rule::validateContacts($cid, $oid)) {
cce70162 87 CRM_Core_Error::statusBounce(ts('The selected pair of contacts are marked as non duplicates. If these records should be merged, you can remove this exception on the <a href="%1">Dedupe Exceptions</a> page.', array(1 => CRM_Utils_System::url('civicrm/dedupe/exception', 'reset=1'))));
6a488035 88 }
e9299e88 89 $this->_contactType = civicrm_api3('Contact', 'getvalue', array('id' => $cid, 'return' => 'contact_type'));
4e052b22 90 $isFromDedupeScreen = TRUE;
e9299e88 91 if (!$this->_rgid) {
4e052b22 92 $isFromDedupeScreen = FALSE;
e9299e88 93 $this->_rgid = civicrm_api3('RuleGroup', 'getvalue', array(
94 'contact_type' => $this->_contactType,
95 'used' => 'Supervised',
96 'return' => 'id',
97 ));
98 }
6a488035 99
e9299e88 100 $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid);
2ae26001 101
102 $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
6a488035
TO
103 $where = "de.id IS NULL";
104
105 $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $cid, $oid, $this->_mergeId, $join, $where, $flip);
106
107 // Block access if user does not have EDIT permissions for both contacts.
108 if (!(CRM_Contact_BAO_Contact_Permission::allow($cid, CRM_Core_Permission::EDIT) &&
353ffa53
TO
109 CRM_Contact_BAO_Contact_Permission::allow($oid, CRM_Core_Permission::EDIT)
110 )
111 ) {
6a488035
TO
112 CRM_Utils_System::permissionDenied();
113 }
114
115 // get user info of main contact.
116 $config = CRM_Core_Config::singleton();
117 $config->doNotResetCache = 1;
118
119 $viewUser = CRM_Core_Permission::check('access user profiles');
120 $mainUfId = CRM_Core_BAO_UFMatch::getUFId($cid);
121 $mainUser = NULL;
122 if ($mainUfId) {
123 // d6 compatible
124 if ($config->userSystem->is_drupal == '1') {
125 $mainUser = user_load($mainUfId);
126 }
127 elseif ($config->userFramework == 'Joomla') {
128 $mainUser = JFactory::getUser($mainUfId);
129 }
130
131 $this->assign('mainUfId', $mainUfId);
132 $this->assign('mainUfName', $mainUser ? $mainUser->name : NULL);
133 }
134
395d8dc6 135 $flipUrl = CRM_Utils_System::url('civicrm/contact/merge',
e9299e88 136 "reset=1&action=update&cid={$oid}&oid={$cid}&rgid={$this->_rgid}&gid={$gid}"
6a488035
TO
137 );
138 if (!$flip) {
139 $flipUrl .= '&flip=1';
140 }
141 $this->assign('flip', $flipUrl);
142
143 $this->prev = $this->next = NULL;
144 foreach (array(
353ffa53 145 'prev',
389bcebf 146 'next',
353ffa53 147 ) as $position) {
6a488035
TO
148 if (!empty($pos[$position])) {
149 if ($pos[$position]['id1'] && $pos[$position]['id2']) {
dc6285d5 150 $urlParams .= "&cid={$pos[$position]['id1']}&oid={$pos[$position]['id2']}&mergeId={$pos[$position]['mergeId']}&action=update";
151 $this->$position = CRM_Utils_System::url('civicrm/contact/merge', $urlParams);
6a488035
TO
152 $this->assign($position, $this->$position);
153 }
154 }
155 }
156
157 // get user info of other contact.
158 $otherUfId = CRM_Core_BAO_UFMatch::getUFId($oid);
159 $otherUser = NULL;
160
161 if ($otherUfId) {
162 // d6 compatible
163 if ($config->userSystem->is_drupal == '1') {
164 $otherUser = user_load($otherUfId);
165 }
166 elseif ($config->userFramework == 'Joomla') {
167 $otherUser = JFactory::getUser($otherUfId);
168 }
169
170 $this->assign('otherUfId', $otherUfId);
171 $this->assign('otherUfName', $otherUser ? $otherUser->name : NULL);
172 }
173
174 $cmsUser = ($mainUfId && $otherUfId) ? TRUE : FALSE;
175 $this->assign('user', $cmsUser);
176
177 $session = CRM_Core_Session::singleton();
178
179 // context fixed.
4e052b22 180 if ($isFromDedupeScreen) {
dc6285d5 181 $browseUrl = CRM_Utils_System::url('civicrm/contact/dedupefind', $urlParams . '&action=browse');
4e052b22 182 $session->pushUserContext($browseUrl);
6a488035 183 }
4e052b22 184 $this->assign('browseUrl', empty($browseUrl) ? '' : $browseUrl);
6a488035
TO
185
186 // ensure that oid is not the current user, if so refuse to do the merge
187 if ($session->get('userID') == $oid) {
188 $display_name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $oid, 'display_name');
189 $message = ts('The contact record which is linked to the currently logged in user account - \'%1\' - cannot be deleted.',
190 array(1 => $display_name)
191 );
192 CRM_Core_Error::statusBounce($message);
193 }
194
195 $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($cid, $oid);
471ec338
BS
196 $main = $this->_mainDetails = &$rowsElementsAndInfo['main_details'];
197 $other = $this->_otherDetails = &$rowsElementsAndInfo['other_details'];
6a488035
TO
198
199 if ($main['contact_id'] != $cid) {
200 CRM_Core_Error::fatal(ts('The main contact record does not exist'));
201 }
202
203 if ($other['contact_id'] != $oid) {
204 CRM_Core_Error::fatal(ts('The other contact record does not exist'));
205 }
206
6a488035 207 $this->assign('contact_type', $main['contact_type']);
6a488035
TO
208 $this->assign('main_name', $main['display_name']);
209 $this->assign('other_name', $other['display_name']);
210 $this->assign('main_cid', $main['contact_id']);
211 $this->assign('other_cid', $other['contact_id']);
e9299e88 212 $this->assign('rgid', $this->_rgid);
6a488035 213
353ffa53
TO
214 $this->_cid = $cid;
215 $this->_oid = $oid;
e9299e88 216
d664f648 217 $this->addElement('checkbox', 'toggleSelect', NULL, NULL, array('class' => 'select-rows'));
6a488035 218
bf43eaac
J
219 $this->assign('mainLocBlock', json_encode($rowsElementsAndInfo['main_details']['location_blocks']));
220 $this->assign('locationBlockInfo', json_encode(CRM_Dedupe_Merger::getLocationBlockInfo()));
6a488035
TO
221 $this->assign('rows', $rowsElementsAndInfo['rows']);
222
6a488035
TO
223 // add elements
224 foreach ($rowsElementsAndInfo['elements'] as $element) {
225 $this->addElement($element[0],
226 $element[1],
227 array_key_exists('2', $element) ? $element[2] : NULL,
228 array_key_exists('3', $element) ? $element[3] : NULL,
229 array_key_exists('4', $element) ? $element[4] : NULL,
230 array_key_exists('5', $element) ? $element[5] : NULL
231 );
232 }
233
234 // add related table elements
235 foreach ($rowsElementsAndInfo['rel_table_elements'] as $relTableElement) {
236 $element = $this->addElement($relTableElement[0], $relTableElement[1]);
237 $element->setChecked(TRUE);
238 }
239
240 $this->assign('rel_tables', $rowsElementsAndInfo['rel_tables']);
241 $this->assign('userContextURL', $session->readUserContext());
242 }
243
86538308
EM
244 /**
245 * This virtual function is used to set the default values of
246 * various form elements
247 *
248 * access public
249 *
a6c01b45
CW
250 * @return array
251 * reference to the array of default values
86538308
EM
252 */
253 /**
254 * @return array
255 */
00be9182 256 public function setDefaultValues() {
6a488035
TO
257 return array('deleteOther' => 1);
258 }
259
6ea503d4
TO
260 public function addRules() {
261 }
6a488035
TO
262
263 public function buildQuickForm() {
d5be719d 264 CRM_Utils_System::setTitle(ts('Merge %1 contacts', array(1 => $this->_contactType)));
fd66df85
CW
265 $buttons = array();
266
267 $buttons[] = array(
268 'type' => 'next',
3709190a 269 'name' => $this->next ? ts('Merge and go to Next Pair') : ts('Merge'),
fd66df85
CW
270 'isDefault' => TRUE,
271 'icon' => $this->next ? 'circle-triangle-e' : 'check',
272 );
6a488035
TO
273
274 if ($this->next || $this->prev) {
fd66df85
CW
275 $buttons[] = array(
276 'type' => 'submit',
3709190a 277 'name' => ts('Merge and go to Listing'),
6a488035 278 );
fd66df85
CW
279 $buttons[] = array(
280 'type' => 'done',
281 'name' => ts('Merge and View Result'),
0291a521 282 'icon' => 'fa-check-circle',
6a488035
TO
283 );
284 }
285
fd66df85
CW
286 $buttons[] = array(
287 'type' => 'cancel',
288 'name' => ts('Cancel'),
289 );
290
291 $this->addButtons($buttons);
4b87bd02 292 $this->addFormRule(array('CRM_Contact_Form_Merge', 'formRule'), $this);
293 }
294
86538308
EM
295 /**
296 * @param $fields
297 * @param $files
298 * @param $self
299 *
300 * @return array
301 */
00be9182 302 public static function formRule($fields, $files, $self) {
4b87bd02 303 $errors = array();
0653585f 304 $link = CRM_Utils_System::href(ts('Flip between the original and duplicate contacts.'),
b74201e4 305 'civicrm/contact/merge',
306 'reset=1&action=update&cid=' . $self->_oid . '&oid=' . $self->_cid . '&rgid=' . $self->_rgid . '&flip=1'
307 );
4b87bd02 308 if (CRM_Contact_BAO_Contact::checkDomainContact($self->_oid)) {
0653585f 309 $errors['_qf_default'] = ts("The Default Organization contact cannot be merged into another contact record. It is associated with the CiviCRM installation for this domain and contains information used for system functions. If you want to merge these records, you can: %1", array(1 => $link));
4b87bd02 310 }
311 return $errors;
6a488035
TO
312 }
313
314 public function postProcess() {
315 $formValues = $this->exportValues();
8ef12e64 316
6a488035
TO
317 // reset all selected contact ids from session
318 // when we came from search context, CRM-3526
319 $session = CRM_Core_Session::singleton();
320 if ($session->get('selectedSearchContactIds')) {
321 $session->resetScope('selectedSearchContactIds');
322 }
323
471ec338
BS
324 $formValues['main_details'] = $this->_mainDetails;
325 $formValues['other_details'] = $this->_otherDetails;
b54f692d 326 $migrationData = array('migration_info' => $formValues);
327 CRM_Utils_Hook::merge('form', $migrationData, $this->_cid, $this->_oid);
328 CRM_Dedupe_Merger::moveAllBelongings($this->_cid, $this->_oid, $migrationData['migration_info']);
6a488035 329
7b99ead3
CW
330 $name = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_cid, 'display_name');
331 $message = '<ul><li>' . ts('%1 has been updated.', array(1 => $name)) . '</li><li>' . ts('Contact ID %1 has been deleted.', array(1 => $this->_oid)) . '</li></ul>';
332 CRM_Core_Session::setStatus($message, ts('Contacts Merged'), 'success');
333
6a488035 334 $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_cid}");
dc6285d5 335 $urlParams = "reset=1&gid={$this->_gid}&rgid={$this->_rgid}&limit={$this->limit}";
336
a7488080 337 if (!empty($formValues['_qf_Merge_submit'])) {
dc6285d5 338 $urlParams .= "&action=update";
6a488035 339 $lisitingURL = CRM_Utils_System::url('civicrm/contact/dedupefind',
dc6285d5 340 $urlParams
6a488035
TO
341 );
342 CRM_Utils_System::redirect($lisitingURL);
343 }
353ffa53 344 if (!empty($formValues['_qf_Merge_done'])) {
6a488035
TO
345 CRM_Utils_System::redirect($url);
346 }
347
348 if ($this->next && $this->_mergeId) {
2ae26001 349 $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid);
6a488035 350
2ae26001 351 $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
6a488035
TO
352 $where = "de.id IS NULL";
353
354 $pos = CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, NULL, NULL, $this->_mergeId, $join, $where);
355
356 if (!empty($pos) &&
357 $pos['next']['id1'] &&
358 $pos['next']['id2']
359 ) {
360
dc6285d5 361 $urlParams .= "&cid={$pos['next']['id1']}&oid={$pos['next']['id2']}&mergeId={$pos['next']['mergeId']}&action=update";
362 $url = CRM_Utils_System::url('civicrm/contact/merge', $urlParams);
6a488035
TO
363 }
364 }
365
366 CRM_Utils_System::redirect($url);
367 }
96025800 368
6a488035 369}