CRM-13389, CRM-13555 - Upgrade from 4.0.* to 4.4: DB Error: no such table civicrm_setting
[civicrm-core.git] / CRM / Core / BAO / UFMatch.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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-2013
32 * $Id$
33 *
34 */
35
36/**
37 * The basic class that interfaces with the external user framework
38 */
39class CRM_Core_BAO_UFMatch extends CRM_Core_DAO_UFMatch {
40
41 /*
42 * Create UF Match, Note that thsi function is here in it's simplest form @ the moment
43 *
44 *
45 * @param array $params input parameters
46 */
47 static function create($params) {
48 $hook = empty($params['id']) ? 'create' : 'edit';
49 CRM_Utils_Hook::pre($hook, 'UFMatch', CRM_Utils_Array::value('id', $params), $params);
50 $dao = new CRM_Core_DAO_UFMatch();
51 $dao->copyValues($params);
52 $dao->save();
53 CRM_Utils_Hook::post($hook, 'UFMatch', $dao->id, $dao);
54 return $dao;
55 }
56
57
58 /**
59 * Given a UF user object, make sure there is a contact
60 * object for this user. If the user has new values, we need
61 * to update the CRM DB with the new values
62 *
63 * @param Object $user the drupal user object
64 * @param boolean $update has the user object been edited
65 * @param $uf
66 *
67 * @return void
68 * @access public
69 * @static
70 */
71 static function synchronize(&$user, $update, $uf, $ctype, $isLogin = FALSE) {
72 $config = CRM_Core_Config::singleton();
73 $session = CRM_Core_Session::singleton();
74 if (!is_object($session)) {
75 CRM_Core_Error::fatal('wow, session is not an object?');
76 return;
77 }
78
79 if ($config->userSystem->is_drupal) {
80 $key = 'uid';
81 $login = 'name';
82 $mail = 'mail';
83 }
84 elseif ($uf == 'Joomla') {
85 $key = 'id';
86 $login = 'username';
87 $mail = 'email';
88 if (!isset($user->id) || !isset($user->email)) {
89 $user = JFactory::getUser();
90 }
91 }
92 elseif ($uf == 'WordPress') {
93 $key = 'ID';
94 $login = 'user_login';
95 $mail = 'user_email';
96 }
97 else {
98 CRM_Core_Error::statusBounce(ts('Please set the user framework variable'));
99 }
100
101 // if the id of the object is zero (true for anon users in drupal)
102 // have we already processed this user, if so early
103 // return.
104 $userID = $session->get('userID');
105 $ufID = $session->get('ufID');
106
107 if (!$update && $ufID == $user->$key) {
108 return;
109 }
110
111 //check do we have logged in user.
112 $isUserLoggedIn = CRM_Utils_System::isUserLoggedIn();
113
114 // reset the session if we are a different user
115 if ($ufID && $ufID != $user->$key) {
116 $session->reset();
117
118 //get logged in user ids, and set to session.
119 if ($isUserLoggedIn) {
120 $userIds = self::getUFValues();
121 $session->set('ufID', CRM_Utils_Array::value('uf_id', $userIds, ''));
122 $session->set('userID', CRM_Utils_Array::value('contact_id', $userIds, ''));
123 $session->set('ufUniqID', CRM_Utils_Array::value('uf_name', $userIds, ''));
124 }
125 }
126
127 // return early
128 if ($user->$key == 0) {
129 return;
130 }
131
132 if (!isset($uniqId) || !$uniqId) {
133 $uniqId = $user->$mail;
134 }
135
136 $ufmatch = self::synchronizeUFMatch($user, $user->$key, $uniqId, $uf, NULL, $ctype, $isLogin);
137 if (!$ufmatch) {
138 return;
139 }
140
141 //make sure we have session w/ consistent ids.
142 $ufID = $ufmatch->uf_id;
143 $userID = $ufmatch->contact_id;
144 $ufUniqID = '';
145 if ($isUserLoggedIn) {
146 $loggedInUserUfID = CRM_Utils_System::getLoggedInUfID();
147 //are we processing logged in user.
148 if ($loggedInUserUfID && $loggedInUserUfID != $ufID) {
149 $userIds = self::getUFValues($loggedInUserUfID);
150 $ufID = CRM_Utils_Array::value('uf_id', $userIds, '');
151 $userID = CRM_Utils_Array::value('contact_id', $userIds, '');
152 $ufUniqID = CRM_Utils_Array::value('uf_name', $userIds, '');
153 }
154 }
155
156 //set user ids to session.
157 $session->set('ufID', $ufID);
158 $session->set('userID', $userID);
159 $session->set('ufUniqID', $ufUniqID);
160
161 // add current contact to recently viewed
162 if ($ufmatch->contact_id) {
163 list($displayName, $contactImage, $contactType, $contactSubtype, $contactImageUrl) =
164 CRM_Contact_BAO_Contact::getDisplayAndImage($ufmatch->contact_id, TRUE, TRUE);
165
166 $otherRecent = array(
167 'imageUrl' => $contactImageUrl,
168 'subtype' => $contactSubtype,
169 'editUrl' => CRM_Utils_System::url('civicrm/contact/add', "reset=1&action=update&cid={$ufmatch->contact_id}"),
170 );
171
172 CRM_Utils_Recent::add($displayName,
173 CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$ufmatch->contact_id}"),
174 $ufmatch->contact_id,
175 $contactType,
176 $ufmatch->contact_id,
177 $displayName,
178 $otherRecent
179 );
180 }
181 }
182
183 /**
184 * Synchronize the object with the UF Match entry. Can be called stand-alone from
185 * the drupalUsers script
186 *
187 * @param Object $user the drupal user object
188 * @param string $userKey the id of the user from the uf object
189 * @param string $uniqId the OpenID of the user
190 * @param string $uf the name of the user framework
191 * @param integer $status returns the status if user created or already exits (used for CMS sync)
192 *
193 * @return the ufmatch object that was found or created
194 * @access public
195 * @static
196 */
197 static function &synchronizeUFMatch(&$user, $userKey, $uniqId, $uf, $status = NULL, $ctype = NULL, $isLogin = FALSE) {
198 $config = CRM_Core_Config::singleton();
199
200 if (!CRM_Utils_Rule::email($uniqId)) {
201 $retVal = $status ? NULL : FALSE;
202 return $retVal;
203 }
204
205 $newContact = FALSE;
206
207 // make sure that a contact id exists for this user id
208 $ufmatch = new CRM_Core_DAO_UFMatch();
209 $ufmatch->domain_id = CRM_Core_Config::domainID();
210 $ufmatch->uf_id = $userKey;
211
212 if (!$ufmatch->find(TRUE)) {
213 $transaction = new CRM_Core_Transaction();
214
215 $dao = NULL;
216 if (!empty($_POST) && !$isLogin) {
217 $params = $_POST;
218 $params['email'] = $uniqId;
219
220 $dedupeParams = CRM_Dedupe_Finder::formatParams($params, 'Individual');
221 $dedupeParams['check_permission'] = FALSE;
222 $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual');
223
224 if (!empty($ids) &&
225 CRM_Core_BAO_Setting::getItem(
226 CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME,
227 'uniq_email_per_site'
228 )
229 ) {
230 // restrict dupeIds to ones that belong to current domain/site.
231 $siteContacts = CRM_Core_BAO_Domain::getContactList();
232 foreach ($ids as $index => $dupeId) {
233 if (!in_array($dupeId, $siteContacts)) {
234 unset($ids[$index]);
235 }
236 }
237 // re-index the array
238 $ids = array_values($ids);
239 }
240 if (!empty($ids)) {
241 $dao = new CRM_Core_DAO();
242 $dao->contact_id = $ids[0];
243 }
244 }
245 else {
246 $dao = CRM_Contact_BAO_Contact::matchContactOnEmail($uniqId, $ctype);
247 }
248
249 $found = FALSE;
250 if ($dao) {
251 // ensure there does not exists a contact_id / uf_id pair
252 // in the DB. This might be due to multiple emails per contact
253 // CRM-9091
254 $sql = "
255SELECT id
256FROM civicrm_uf_match
257WHERE contact_id = %1
258AND domain_id = %2
259";
260 $params = array(
261 1 => array($dao->contact_id, 'Integer'),
262 2 => array(CRM_Core_Config::domainID(), 'Integer'),
263 );
264 $conflict = CRM_Core_DAO::singleValueQuery($sql, $params);
265
266 if (!$conflict) {
267 $found = TRUE;
268 $ufmatch->contact_id = $dao->contact_id;
269 $ufmatch->uf_name = $uniqId;
270 }
271 }
272
273 if (!$found) {
274 if ($config->userSystem->is_drupal) {
275 $mail = 'mail';
276 }
277 elseif ($uf == 'WordPress') {
278 $mail = 'user_email';
279 }
280 else {
281 $mail = 'email';
282 }
283
284 if (is_object($user)) {
285 $params = array('email-Primary' => $user->$mail);
286 }
287
288 if ($ctype == 'Organization') {
289 $params['organization_name'] = $uniqId;
290 }
291 elseif ($ctype == 'Household') {
292 $params['household_name'] = $uniqId;
293 }
294
295 if (!$ctype) {
296 $ctype = "Individual";
297 }
298 $params['contact_type'] = $ctype;
299
300 // extract first / middle / last name
301 // for joomla
302 if ($uf == 'Joomla' && $user->name) {
303 CRM_Utils_String::extractName($user->name, $params);
304 }
305
306 if ($uf == 'WordPress') {
307 if ($user->first_name) {
308 $params['first_name'] = $user->first_name;
309 }
310
311 if ($user->last_name) {
312 $params['last_name'] = $user->last_name;
313 }
314 }
315
316 $contactId = CRM_Contact_BAO_Contact::createProfileContact($params, CRM_Core_DAO::$_nullArray);
317 $ufmatch->contact_id = $contactId;
318 $ufmatch->uf_name = $uniqId;
319 }
320
321 // check that there are not two CMS IDs matching the same CiviCRM contact - this happens when a civicrm
322 // user has two e-mails and there is a cms match for each of them
323 // the gets rid of the nasty fata error but still reports the error
324 $sql = "
325SELECT uf_id
326FROM civicrm_uf_match
327WHERE ( contact_id = %1
328OR uf_name = %2
329OR uf_id = %3 )
330AND domain_id = %4
331";
332 $params = array(
333 1 => array($ufmatch->contact_id, 'Integer'),
334 2 => array($ufmatch->uf_name, 'String'),
335 3 => array($ufmatch->uf_id, 'Integer'),
336 4 => array($ufmatch->domain_id, 'Integer'),
337 );
338
339 $conflict = CRM_Core_DAO::singleValueQuery($sql, $params);
340
341 if (!$conflict) {
342 $ufmatch = CRM_Core_BAO_UFMatch::create((array) $ufmatch);
343 $ufmatch->free();
344 $newContact = TRUE;
345 $transaction->commit();
346 }
347 else {
348 $msg = ts("Contact ID %1 is a match for %2 user %3 but has already been matched to %4",
349 array(
350 1 => $ufmatch->contact_id,
351 2 => $uf,
352 3 => $ufmatch->uf_id,
353 4 => $conflict
354 )
355 );
356 unset($conflict);
357 }
358 }
359
360 if ($status) {
361 return $newContact;
362 }
363 else {
364 return $ufmatch;
365 }
366 }
367
368 /**
369 * update the uf_name in the user object
370 *
371 * @param int $contactId id of the contact to update
372 *
373 * @return void
374 * @access public
375 * @static
376 */
377 static function updateUFName($contactId) {
378 if (!$contactId) {
379 return;
380 }
381 $config = CRM_Core_Config::singleton();
382 $ufName = CRM_Contact_BAO_Contact::getPrimaryEmail($contactId);
383
384 if (!$ufName) {
385 return;
386 }
387
388 $update = FALSE;
389
390 // 1.do check for contact Id.
391 $ufmatch = new CRM_Core_DAO_UFMatch();
392 $ufmatch->contact_id = $contactId;
393 $ufmatch->domain_id = CRM_Core_Config::domainID();
394 if (!$ufmatch->find(TRUE)) {
395 return;
396 }
397 if ($ufmatch->uf_name != $ufName) {
398 $update = TRUE;
399 }
400
401 // CRM-6928
402 // 2.do check for duplicate ufName.
403 $ufDupeName = new CRM_Core_DAO_UFMatch();
404 $ufDupeName->uf_name = $ufName;
405 $ufDupeName->domain_id = CRM_Core_Config::domainID();
406 if ($ufDupeName->find(TRUE) &&
407 $ufDupeName->contact_id != $contactId
408 ) {
409 $update = FALSE;
410 }
411
412 if (!$update) {
413 return;
414 }
415
416 // save the updated ufmatch object
417 $ufmatch->uf_name = $ufName;
418 $ufmatch->save();
419 $config->userSystem->updateCMSName($ufmatch->uf_id, $ufName);
420 }
421
422 /**
423 * Update the email value for the contact and user profile
424 *
425 * @param $contactId Int Contact ID of the user
426 * @param $email String email to be modified for the user
427 *
428 * @return void
429 * @access public
430 * @static
431 */
432 static function updateContactEmail($contactId, $emailAddress) {
433 $strtolower = function_exists('mb_strtolower') ? 'mb_strtolower' : 'strtolower';
434 $emailAddress = $strtolower($emailAddress);
435
436 $ufmatch = new CRM_Core_DAO_UFMatch();
437 $ufmatch->contact_id = $contactId;
438 $ufmatch->domain_id = CRM_Core_Config::domainID();
439 if ($ufmatch->find(TRUE)) {
440 // Save the email in UF Match table
441 $ufmatch->uf_name = $emailAddress;
442 CRM_Core_BAO_UFMatch::create((array) $ufmatch);
443
444 //check if the primary email for the contact exists
445 //$contactDetails[1] - email
446 //$contactDetails[3] - email id
447 $contactDetails = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactId);
448
449 if (trim($contactDetails[1])) {
450 $emailID = $contactDetails[3];
451 //update if record is found
452 $query = "UPDATE civicrm_email
453 SET email = %1
454 WHERE id = %2";
455 $p = array(
456 1 => array($emailAddress, 'String'),
457 2 => array($emailID, 'Integer'),
458 );
459 $dao = CRM_Core_DAO::executeQuery($query, $p);
460 }
461 else {
462 //else insert a new email record
463 $email = new CRM_Core_DAO_Email();
464 $email->contact_id = $contactId;
465 $email->is_primary = 1;
466 $email->email = $emailAddress;
467 $email->save();
468 $emailID = $email->id;
469 }
470
471 CRM_Core_BAO_Log::register($contactId,
472 'civicrm_email',
473 $emailID
474 );
475 }
476 }
477
478 /**
479 * Delete the object records that are associated with this cms user
480 *
481 * @param int $ufID id of the user to delete
482 *
483 * @return void
484 * @access public
485 * @static
486 */
487 static function deleteUser($ufID) {
488 $ufmatch = new CRM_Core_DAO_UFMatch();
489
490 $ufmatch->uf_id = $ufID;
491 $ufmatch->domain_id = CRM_Core_Config::domainID();
492 $ufmatch->delete();
493 }
494
495 /**
496 * get the contact_id given a uf_id
497 *
498 * @param int $ufID Id of UF for which related contact_id is required
499 *
500 * @return int contact_id on success, null otherwise
501 * @access public
502 * @static
503 */
504 static function getContactId($ufID) {
505 if (!isset($ufID)) {
506 return NULL;
507 }
508
509 $ufmatch = new CRM_Core_DAO_UFMatch();
510
511 $ufmatch->uf_id = $ufID;
512 $ufmatch->domain_id = CRM_Core_Config::domainID();
513 if ($ufmatch->find(TRUE)) {
514 return (int ) $ufmatch->contact_id;
515 }
516 return NULL;
517 }
518
519 /**
520 * get the uf_id given a contact_id
521 *
522 * @param int $contactID ID of the contact for which related uf_id is required
523 *
524 * @return int uf_id of the given contact_id on success, null otherwise
525 * @access public
526 * @static
527 */
528 static function getUFId($contactID) {
529 if (!isset($contactID)) {
530 return NULL;
531 }
532 $domain = CRM_Core_BAO_Domain::getDomain();
533 $ufmatch = new CRM_Core_DAO_UFMatch();
534
535 $ufmatch->contact_id = $contactID;
536 $ufmatch->domain_id = $domain->id;
537 if ($ufmatch->find(TRUE)) {
538 return $ufmatch->uf_id;
539 }
540 return NULL;
541 }
542
543 static function isEmptyTable() {
544 $sql = "SELECT count(id) FROM civicrm_uf_match";
545 return CRM_Core_DAO::singleValueQuery($sql) > 0 ? FALSE : TRUE;
546 }
547
548 /**
549 * get the list of contact_id
550 *
551 *
552 * @return int contact_id on success, null otherwise
553 * @access public
554 * @static
555 */
556 static function getContactIDs() {
557 $id = array();
558 $dao = new CRM_Core_DAO_UFMatch();
559 $dao->find();
560 while ($dao->fetch()) {
561 $id[] = $dao->contact_id;
562 }
563 return $id;
564 }
565
566 /**
567 * see if this user exists, and if so, if they're allowed to login
568 *
569 *
570 * @return bool true if allowed to login, false otherwise
571 * @access public
572 * @static
573 */
574 static function getAllowedToLogin($openId) {
575 $ufmatch = new CRM_Core_DAO_UFMatch();
576 $ufmatch->uf_name = $openId;
577 $ufmatch->allowed_to_login = 1;
578 if ($ufmatch->find(TRUE)) {
579 return TRUE;
580 }
581 return FALSE;
582 }
583
584 /**
585 * get the next unused uf_id value, since the standalone UF doesn't
586 * have id's (it uses OpenIDs, which go in a different field)
587 *
588 *
589 * @return int next highest unused value for uf_id
590 * @access public
591 * @static
592 */
593 static function getNextUfIdValue() {
594 $query = "SELECT MAX(uf_id)+1 AS next_uf_id FROM civicrm_uf_match";
595 $dao = CRM_Core_DAO::executeQuery($query);
596 if ($dao->fetch()) {
597 $ufId = $dao->next_uf_id;
598 }
599
600 if (!isset($ufId)) {
601 $ufId = 1;
602 }
603 return $ufId;
604 }
605
606 static function isDuplicateUser($email) {
607 $session = CRM_Core_Session::singleton();
608 $contactID = $session->get('userID');
609 if (!empty($email) && isset($contactID)) {
610 $dao = new CRM_Core_DAO_UFMatch();
611 $dao->uf_name = $email;
612 if ($dao->find(TRUE) && $contactID != $dao->contact_id) {
613 return TRUE;
614 }
615 }
616 return FALSE;
617 }
618
619 /**
620 * Get uf match values for given uf id or logged in user.
621 *
622 * @param int $ufID uf id.
623 *
624 * return array $ufValues uf values.
625 **/
626 static function getUFValues($ufID = NULL) {
627 if (!$ufID) {
628 //get logged in user uf id.
629 $ufID = CRM_Utils_System::getLoggedInUfID();
630 }
631 if (!$ufID) {
632 return array();
633 }
634
635 static $ufValues;
636 if ($ufID && !isset($ufValues[$ufID])) {
637 $ufmatch = new CRM_Core_DAO_UFMatch();
638 $ufmatch->uf_id = $ufID;
639 $ufmatch->domain_id = CRM_Core_Config::domainID();
640 if ($ufmatch->find(TRUE)) {
641 $ufValues[$ufID] = array(
642 'uf_id' => $ufmatch->uf_id,
643 'uf_name' => $ufmatch->uf_name,
644 'contact_id' => $ufmatch->contact_id,
645 'domain_id' => $ufmatch->domain_id,
646 );
647 }
648 }
649 return $ufValues[$ufID];
650 }
651}
652