Merge pull request #14768 from eileenmcnaughton/export_test
[civicrm-core.git] / CRM / Utils / System / Drupal8.php
CommitLineData
d3e88312
EM
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
d3e88312 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
d3e88312
EM
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 */
d3e88312
EM
27
28/**
29 *
30 * @package CRM
6b83d5bd 31 * @copyright CiviCRM LLC (c) 2004-2019
d3e88312
EM
32 */
33
34/**
5a7f3b8b 35 * Drupal specific stuff goes here.
d3e88312
EM
36 */
37class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
38
7e9cadcf 39 /**
17f443df 40 * @inheritDoc
7e9cadcf 41 */
00be9182 42 public function createUser(&$params, $mail) {
7e9cadcf
EM
43 $user = \Drupal::currentUser();
44 $user_register_conf = \Drupal::config('user.settings')->get('register');
45 $verify_mail_conf = \Drupal::config('user.settings')->get('verify_mail');
46
47 // Don't create user if we don't have permission to.
48 if (!$user->hasPermission('administer users') && $user_register_conf == 'admin_only') {
49 return FALSE;
50 }
51
ab8510e2 52 /** @var \Drupal\user\Entity\User $account */
7e9cadcf
EM
53 $account = entity_create('user');
54 $account->setUsername($params['cms_name'])->setEmail($params[$mail]);
55
56 // Allow user to set password only if they are an admin or if
57 // the site settings don't require email verification.
58 if (!$verify_mail_conf || $user->hasPermission('administer users')) {
59 // @Todo: do we need to check that passwords match or assume this has already been done for us?
60 $account->setPassword($params['cms_pass']);
61 }
62
63 // Only activate account if we're admin or if anonymous users don't require
64 // approval to create accounts.
65 if ($user_register_conf != 'visitors' && !$user->hasPermission('administer users')) {
66 $account->block();
67 }
ab8510e2
DS
68 elseif (!$verify_mail_conf) {
69 $account->activate();
70 }
7e9cadcf
EM
71
72 // Validate the user object
73 $violations = $account->validate();
74 if (count($violations)) {
75 return FALSE;
76 }
77
ab8510e2
DS
78 // Let the Drupal module know we're already in CiviCRM.
79 $config = CRM_Core_Config::singleton();
80 $config->inCiviCRM = TRUE;
81
7e9cadcf
EM
82 try {
83 $account->save();
6102c55c 84 $config->inCiviCRM = FALSE;
7e9cadcf
EM
85 }
86 catch (\Drupal\Core\Entity\EntityStorageException $e) {
6102c55c 87 $config->inCiviCRM = FALSE;
7e9cadcf
EM
88 return FALSE;
89 }
90
91 // Send off any emails as required.
92 // Possible values for $op:
93 // - 'register_admin_created': Welcome message for user created by the admin.
94 // - 'register_no_approval_required': Welcome message when user
95 // self-registers.
96 // - 'register_pending_approval': Welcome message, user pending admin
97 // approval.
98 // @Todo: Should we only send off emails if $params['notify'] is set?
99 switch (TRUE) {
100 case $user_register_conf == 'admin_only' || $user->isAuthenticated():
101 _user_mail_notify('register_admin_created', $account);
102 break;
e7292422 103
7e9cadcf
EM
104 case $user_register_conf == 'visitors':
105 _user_mail_notify('register_no_approval_required', $account);
106 break;
e7292422 107
7e9cadcf
EM
108 case 'visitors_admin_approval':
109 _user_mail_notify('register_pending_approval', $account);
110 break;
111 }
112
ab8510e2
DS
113 // If this is a user creating their own account, login them in!
114 if ($account->isActive() && $user->isAnonymous()) {
115 \user_login_finalize($account);
116 }
117
7e9cadcf
EM
118 return $account->id();
119 }
120
121 /**
17f443df 122 * @inheritDoc
7e9cadcf 123 */
00be9182 124 public function updateCMSName($ufID, $email) {
ce391511 125 $user = entity_load('user', $ufID);
7e9cadcf
EM
126 if ($user && $user->getEmail() != $email) {
127 $user->setEmail($email);
128
129 if (!count($user->validate())) {
130 $user->save();
131 }
132 }
133 }
134
135 /**
fe482240 136 * Check if username and email exists in the drupal db.
7e9cadcf 137 *
77855840
TO
138 * @param array $params
139 * Array of name and mail values.
140 * @param array $errors
141 * Errors.
142 * @param string $emailName
143 * Field label for the 'email'.
7e9cadcf 144 */
00be9182 145 public static function checkUserNameEmailExists(&$params, &$errors, $emailName = 'email') {
7e9cadcf
EM
146 // If we are given a name, let's check to see if it already exists.
147 if (!empty($params['name'])) {
148 $name = $params['name'];
149
150 $user = entity_create('user');
151 $user->setUsername($name);
152
153 // This checks for both username uniqueness and validity.
154 $violations = iterator_to_array($user->validate());
155 // We only care about violations on the username field; discard the rest.
353ffa53 156 $violations = array_filter($violations, function ($v) {
ab8510e2 157 return $v->getPropertyPath() == 'name';
e7292422 158 });
7e9cadcf 159 if (count($violations) > 0) {
ab8510e2 160 $errors['cms_name'] = (string) $violations[0]->getMessage();
7e9cadcf
EM
161 }
162 }
163
164 // And if we are given an email address, let's check to see if it already exists.
165 if (!empty($params[$emailName])) {
166 $mail = $params[$emailName];
167
168 $user = entity_create('user');
169 $user->setEmail($mail);
170
171 // This checks for both email uniqueness.
172 $violations = iterator_to_array($user->validate());
173 // We only care about violations on the email field; discard the rest.
353ffa53 174 $violations = array_filter($violations, function ($v) {
ab8510e2 175 return $v->getPropertyPath() == 'mail';
e7292422 176 });
7e9cadcf 177 if (count($violations) > 0) {
ab8510e2 178 $errors[$emailName] = (string) $violations[0]->getMessage();
7e9cadcf
EM
179 }
180 }
181 }
182
183 /**
17f443df 184 * @inheritDoc
d3e88312
EM
185 */
186 public function getLoginURL($destination = '') {
be2fb01f 187 $query = $destination ? ['destination' => $destination] : [];
17c152b6 188 return \Drupal::url('user.login', [], ['query' => $query]);
7e9cadcf
EM
189 }
190
7e9cadcf 191 /**
17f443df 192 * @inheritDoc
7e9cadcf 193 */
00be9182 194 public function setTitle($title, $pageTitle = NULL) {
7e9cadcf
EM
195 if (!$pageTitle) {
196 $pageTitle = $title;
197 }
7e9cadcf
EM
198 \Drupal::service('civicrm.page_state')->setTitle($pageTitle);
199 }
200
201 /**
17f443df 202 * @inheritDoc
7e9cadcf 203 */
00be9182 204 public function appendBreadCrumb($breadcrumbs) {
7e9cadcf
EM
205 $civicrmPageState = \Drupal::service('civicrm.page_state');
206 foreach ($breadcrumbs as $breadcrumb) {
207 $civicrmPageState->addBreadcrumb($breadcrumb['title'], $breadcrumb['url']);
208 }
209 }
210
211 /**
17f443df 212 * @inheritDoc
7e9cadcf 213 */
00be9182 214 public function resetBreadCrumb() {
7e9cadcf
EM
215 \Drupal::service('civicrm.page_state')->resetBreadcrumbs();
216 }
217
218 /**
17f443df 219 * @inheritDoc
7e9cadcf 220 */
00be9182 221 public function addHTMLHead($header) {
7e9cadcf
EM
222 \Drupal::service('civicrm.page_state')->addHtmlHeader($header);
223 }
224
7e9cadcf 225 /**
17f443df 226 * @inheritDoc
7e9cadcf
EM
227 */
228 public function addStyleUrl($url, $region) {
229 if ($region != 'html-header') {
230 return FALSE;
d3e88312 231 }
be2fb01f 232 $css = [
ce391511 233 '#tag' => 'link',
be2fb01f 234 '#attributes' => [
ce391511
T
235 'href' => $url,
236 'rel' => 'stylesheet',
be2fb01f
CW
237 ],
238 ];
ce391511 239 \Drupal::service('civicrm.page_state')->addCSS($css);
7e9cadcf 240 return TRUE;
d3e88312
EM
241 }
242
7e9cadcf 243 /**
17f443df 244 * @inheritDoc
7e9cadcf
EM
245 */
246 public function addStyle($code, $region) {
247 if ($region != 'html-header') {
248 return FALSE;
249 }
be2fb01f 250 $css = [
ce391511
T
251 '#tag' => 'style',
252 '#value' => $code,
be2fb01f 253 ];
ce391511 254 \Drupal::service('civicrm.page_state')->addCSS($css);
7e9cadcf
EM
255 return TRUE;
256 }
257
258 /**
fe482240 259 * Check if a resource url is within the drupal directory and format appropriately.
7e9cadcf
EM
260 *
261 * This seems to be a legacy function. We assume all resources are within the drupal
262 * directory and always return TRUE. As well, we clean up the $url.
263 *
17f443df
CW
264 * FIXME: This is not a legacy function and the above is not a safe assumption.
265 * External urls are allowed by CRM_Core_Resources and this needs to return the correct value.
266 *
7e9cadcf
EM
267 * @param $url
268 *
269 * @return bool
270 */
00be9182 271 public function formatResourceUrl(&$url) {
7e9cadcf
EM
272 // Remove leading slash if present.
273 $url = ltrim($url, '/');
274
275 // Remove query string — presumably added to stop intermediary caching.
276 if (($pos = strpos($url, '?')) !== FALSE) {
277 $url = substr($url, 0, $pos);
278 }
17f443df 279 // FIXME: Should not unconditionally return true
7e9cadcf
EM
280 return TRUE;
281 }
282
283 /**
7e9cadcf
EM
284 * This function does nothing in Drupal 8. Changes to the base_url should be made
285 * in settings.php directly.
7e9cadcf 286 */
00be9182 287 public function mapConfigToSSL() {
7e9cadcf
EM
288 }
289
290 /**
17f443df 291 * @inheritDoc
7e9cadcf 292 */
17f443df
CW
293 public function url(
294 $path = '',
295 $query = '',
296 $absolute = FALSE,
297 $fragment = NULL,
17f443df
CW
298 $frontend = FALSE,
299 $forceBackend = FALSE
300 ) {
7e9cadcf 301 $query = html_entity_decode($query);
756ad860 302
8da6670d 303 $config = CRM_Core_Config::singleton();
32040f62
JG
304 $base = $absolute ? $config->userFrameworkBaseURL : 'internal:/';
305
306 $url = \Drupal\civicrm\CivicrmHelper::parseURL("{$path}?{$query}");
8da6670d 307
756ad860 308 // Not all links that CiviCRM generates are Drupal routes, so we use the weaker ::fromUri method.
7e9cadcf 309 try {
32040f62
JG
310 $url = \Drupal\Core\Url::fromUri("{$base}{$url['path']}", array(
311 'query' => $url['query'],
312 'fragment' => $fragment,
313 'absolute' => $absolute,
314 ))->toString();
7e9cadcf
EM
315 }
316 catch (Exception $e) {
8da6670d 317 \Drupal::logger('civicrm')->error($e->getMessage());
7e9cadcf
EM
318 }
319
7e9cadcf
EM
320 return $url;
321 }
322
7e9cadcf 323 /**
17f443df 324 * @inheritDoc
7e9cadcf 325 */
00be9182 326 public function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realPath = NULL) {
d90814f1 327 $system = new CRM_Utils_System_Drupal8();
be2fb01f 328 $system->loadBootStrap([], FALSE);
7e9cadcf
EM
329
330 $uid = \Drupal::service('user.auth')->authenticate($name, $password);
c0c5132a
DS
331 if ($uid) {
332 if ($this->loadUser($name)) {
333 $contact_id = CRM_Core_BAO_UFMatch::getContactId($uid);
be2fb01f 334 return [$contact_id, $uid, mt_rand()];
c0c5132a
DS
335 }
336 }
7e9cadcf 337
c0c5132a 338 return FALSE;
7e9cadcf
EM
339 }
340
341 /**
17f443df 342 * @inheritDoc
7e9cadcf 343 */
00be9182 344 public function loadUser($username) {
7e9cadcf
EM
345 $user = user_load_by_name($username);
346 if (!$user) {
347 return FALSE;
348 }
349
350 // Set Drupal's current user to the loaded user.
351 \Drupal::currentUser()->setAccount($user);
352
353 $uid = $user->id();
354 $contact_id = CRM_Core_BAO_UFMatch::getContactId($uid);
355
356 // Store the contact id and user id in the session
357 $session = CRM_Core_Session::singleton();
358 $session->set('ufID', $uid);
359 $session->set('userID', $contact_id);
360 return TRUE;
361 }
362
363 /**
fe482240 364 * Determine the native ID of the CMS user.
7e9cadcf 365 *
100fef9d 366 * @param string $username
e97c66ff 367 * @return int|null
7e9cadcf 368 */
00be9182 369 public function getUfId($username) {
7e9cadcf
EM
370 if ($id = user_load_by_name($username)->id()) {
371 return $id;
372 }
373 }
374
375 /**
17f443df 376 * @inheritDoc
7e9cadcf 377 */
00be9182 378 public function permissionDenied() {
7e9cadcf
EM
379 \Drupal::service('civicrm.page_state')->setAccessDenied();
380 }
381
382 /**
383 * In previous versions, this function was the controller for logging out. In Drupal 8, we rewrite the route
384 * to hand off logout to the standard Drupal logout controller. This function should therefore never be called.
385 */
00be9182 386 public function logout() {
7e9cadcf
EM
387 // Pass
388 }
389
390 /**
fe482240 391 * Load drupal bootstrap.
7e9cadcf 392 *
77855840
TO
393 * @param array $params
394 * Either uid, or name & pass.
395 * @param bool $loadUser
396 * Boolean Require CMS user load.
397 * @param bool $throwError
398 * If true, print error on failure and exit.
399 * @param bool|string $realPath path to script
7e9cadcf
EM
400 *
401 * @return bool
402 * @Todo Handle setting cleanurls configuration for CiviCRM?
403 */
be2fb01f 404 public function loadBootStrap($params = [], $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) {
7e9cadcf 405 static $run_once = FALSE;
a3e55d9c
TO
406 if ($run_once) {
407 return TRUE;
0db6c3e1
TO
408 }
409 else {
a3e55d9c 410 $run_once = TRUE;
e7292422 411 }
7e9cadcf
EM
412
413 if (!($root = $this->cmsRootPath())) {
414 return FALSE;
415 }
416 chdir($root);
417
418 // Create a mock $request object
3eca4d68 419 $autoloader = require_once $root . '/autoload.php';
45b293a2
DS
420 if ($autoloader === TRUE) {
421 $autoloader = ComposerAutoloaderInitDrupal8::getLoader();
422 }
7e9cadcf 423 // @Todo: do we need to handle case where $_SERVER has no HTTP_HOST key, ie. when run via cli?
be2fb01f 424 $request = new \Symfony\Component\HttpFoundation\Request([], [], [], [], [], $_SERVER);
7e9cadcf
EM
425
426 // Create a kernel and boot it.
427 \Drupal\Core\DrupalKernel::createFromRequest($request, $autoloader, 'prod')->prepareLegacyRequest($request);
428
429 // Initialize Civicrm
393f6d1d 430 \Drupal::service('civicrm')->initialize();
7e9cadcf
EM
431
432 // We need to call the config hook again, since we now know
433 // all the modules that are listening on it (CRM-8655).
434 CRM_Utils_Hook::config($config);
435
436 if ($loadUser) {
3637b50a 437 if (!empty($params['uid']) && $username = \Drupal\user\Entity\User::load($params['uid'])->getUsername()) {
7e9cadcf
EM
438 $this->loadUser($username);
439 }
c0c5132a 440 elseif (!empty($params['name']) && !empty($params['pass']) && \Drupal::service('user.auth')->authenticate($params['name'], $params['pass'])) {
7e9cadcf
EM
441 $this->loadUser($params['name']);
442 }
443 }
444 return TRUE;
445 }
446
447 /**
448 * Determine the location of the CMS root.
5a7f3b8b 449 *
450 * @param string $path
7e9cadcf
EM
451 *
452 * @return NULL|string
453 */
00be9182 454 public function cmsRootPath($path = NULL) {
a93a0366
TO
455 global $civicrm_paths;
456 if (!empty($civicrm_paths['cms.root']['path'])) {
457 return $civicrm_paths['cms.root']['path'];
458 }
459
7e9cadcf
EM
460 if (defined('DRUPAL_ROOT')) {
461 return DRUPAL_ROOT;
462 }
463
464 // It looks like Drupal hasn't been bootstrapped.
465 // We're going to attempt to discover the root Drupal path
466 // by climbing out of the folder hierarchy and looking around to see
467 // if we've found the Drupal root directory.
468 if (!$path) {
469 $path = $_SERVER['SCRIPT_FILENAME'];
470 }
471
472 // Normalize and explode path into its component paths.
473 $paths = explode(DIRECTORY_SEPARATOR, realpath($path));
474
475 // Remove script filename from array of directories.
476 array_pop($paths);
477
478 while (count($paths)) {
479 $candidate = implode('/', $paths);
480 if (file_exists($candidate . "/core/includes/bootstrap.inc")) {
481 return $candidate;
482 }
483
484 array_pop($paths);
485 }
486 }
487
488 /**
17f443df 489 * @inheritDoc
7e9cadcf
EM
490 */
491 public function isUserLoggedIn() {
492 return \Drupal::currentUser()->isAuthenticated();
493 }
494
8caad0ce 495 /**
496 * @inheritDoc
497 */
498 public function isUserRegistrationPermitted() {
499 if (\Drupal::config('user.settings')->get('register') == 'admin_only') {
500 return FALSE;
501 }
502 return TRUE;
503 }
504
63df6889
HD
505 /**
506 * @inheritDoc
507 */
1a6630be 508 public function isPasswordUserGenerated() {
63df6889
HD
509 if (\Drupal::config('user.settings')->get('verify_mail') == TRUE) {
510 return FALSE;
511 }
512 return TRUE;
513 }
514
4d16a7e1
DS
515 /**
516 * @inheritDoc
517 */
518 public function updateCategories() {
519 // @todo Is anything necessary?
520 }
521
7e9cadcf 522 /**
17f443df 523 * @inheritDoc
7e9cadcf
EM
524 */
525 public function getLoggedInUfID() {
526 if ($id = \Drupal::currentUser()->id()) {
527 return $id;
528 }
529 }
624142d4
EM
530
531 /**
17f443df 532 * @inheritDoc
624142d4 533 */
00be9182 534 public function getDefaultBlockLocation() {
624142d4
EM
535 return 'sidebar_first';
536 }
96025800 537
f38178e6
T
538 /**
539 * @inheritDoc
540 */
541 public function flush() {
542 // CiviCRM and Drupal both provide (different versions of) Symfony (and possibly share other classes too).
543 // If we call drupal_flush_all_caches(), Drupal will attempt to rediscover all of its classes, use Civicrm's
544 // alternatives instead and then die. Instead, we only clear cache bins and no more.
545 foreach (Drupal\Core\Cache\Cache::getBins() as $service_id => $cache_backend) {
546 $cache_backend->deleteAll();
547 }
548 }
5a7f3b8b 549
c4b3a8ba
AS
550 /**
551 * @inheritDoc
552 */
553 public function getModules() {
be2fb01f 554 $modules = [];
c4b3a8ba
AS
555
556 $module_data = system_rebuild_module_data();
557 foreach ($module_data as $module_name => $extension) {
558 if (!isset($extension->info['hidden']) && $extension->origin != 'core') {
559 $extension->schema_version = drupal_get_installed_schema_version($module_name);
560 $modules[] = new CRM_Core_Module('drupal.' . $module_name, ($extension->status == 1 ? TRUE : FALSE));
561 }
562 }
563 return $modules;
564 }
565
cff0c9aa
DS
566 /**
567 * @inheritDoc
568 */
569 public function getUser($contactID) {
570 $user_details = parent::getUser($contactID);
571 $user_details['name'] = $user_details['name']->value;
572 $user_details['email'] = $user_details['email']->value;
573 return $user_details;
574 }
575
3eb59ab5
AS
576 /**
577 * @inheritDoc
578 */
579 public function getUniqueIdentifierFromUserObject($user) {
580 return $user->get('mail')->value;
581 }
582
583 /**
584 * @inheritDoc
585 */
586 public function getUserIDFromUserObject($user) {
587 return $user->get('uid')->value;
588 }
589
590 /**
591 * @inheritDoc
592 */
593 public function synchronizeUsers() {
594 $config = CRM_Core_Config::singleton();
595 if (PHP_SAPI != 'cli') {
596 set_time_limit(300);
597 }
598
be2fb01f 599 $users = [];
3eb59ab5
AS
600 $users = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties();
601
602 $uf = $config->userFramework;
603 $contactCount = 0;
604 $contactCreated = 0;
605 $contactMatching = 0;
606 foreach ($users as $user) {
607 $mail = $user->get('mail')->value;
608 if (empty($mail)) {
609 continue;
610 }
611 $uid = $user->get('uid')->value;
612 $contactCount++;
613 if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user, $uid, $mail, $uf, 1, 'Individual', TRUE)) {
614 $contactCreated++;
615 }
616 else {
617 $contactMatching++;
618 }
619 if (is_object($match)) {
620 $match->free();
621 }
622 }
623
be2fb01f 624 return [
3eb59ab5
AS
625 'contactCount' => $contactCount,
626 'contactMatching' => $contactMatching,
627 'contactCreated' => $contactCreated,
be2fb01f 628 ];
3eb59ab5
AS
629 }
630
61c48624
ML
631 /**
632 * @inheritDoc
633 */
634 public function setMessage($message) {
635 // CiviCRM sometimes includes markup in messages (ex: Event Cart)
636 // it needs to be rendered before being displayed.
637 $message = \Drupal\Core\Render\Markup::create($message);
638 \Drupal::messenger()->addMessage($message);
639 }
3eb59ab5 640
76753b3d
V
641 /**
642 * Drupal 8 has a different function to get current path, hence
643 * overriding the postURL function
644 *
645 * @param string $action
646 *
647 * @return string
648 */
649 public function postURL($action) {
650 if (!empty($action)) {
651 return $action;
652 }
653 $current_path = \Drupal::service('path.current')->getPath();
654 return $this->url($current_path);
655 }
656
ea9245cc 657 /**
658 * Function to return current language of Drupal8
659 *
660 * @return string
661 */
662 public function getCurrentLanguage() {
663 // Drupal might not be bootstrapped if being called by the REST API.
c5a1e8d2 664 if (!class_exists('Drupal') || !\Drupal::hasContainer()) {
ea9245cc 665 return NULL;
666 }
667
668 return \Drupal::languageManager()->getCurrentLanguage()->getId();
669 }
670
7eed4524 671 /**
672 * Append Drupal8 js to coreResourcesList.
673 *
303017a1 674 * @param \Civi\Core\Event\GenericHookEvent $e
7eed4524 675 */
303017a1
CW
676 public function appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) {
677 $e->list[] = 'js/crm.drupal8.js';
7eed4524 678 }
679
f637dfc7 680 /**
681 * @inheritDoc
682 */
683 public function setUFLocale($civicrm_language) {
684 $langcode = substr(str_replace('_', '', $civicrm_language), 0, 2);
685 $languageManager = \Drupal::languageManager();
686 $languages = $languageManager->getLanguages();
687
688 if (isset($languages[$langcode])) {
689 $languageManager->setConfigOverrideLanguage($languages[$langcode]);
690
691 // Config must be re-initialized to reset the base URL
692 // otherwise links will have the wrong language prefix/domain.
693 $config = CRM_Core_Config::singleton();
694 $config->free();
695
696 return TRUE;
697 }
698
699 return FALSE;
700 }
701
8da6670d 702 /**
703 * @inheritDoc
704 */
705 public function languageNegotiationURL($url, $addLanguagePart = TRUE, $removeLanguagePart = FALSE) {
706 if (empty($url)) {
707 return $url;
708 }
709
c59c5519 710 // Drupal might not be bootstrapped if being called by the REST API.
c5a1e8d2 711 if (!class_exists('Drupal') || !\Drupal::hasContainer()) {
c59c5519
MD
712 return NULL;
713 }
714
8da6670d 715 $language = $this->getCurrentLanguage();
716 if (\Drupal::service('module_handler')->moduleExists('language')) {
717 $config = \Drupal::config('language.negotiation')->get('url');
718
719 //does user configuration allow language
720 //support from the URL (Path prefix or domain)
721 $enabledLanguageMethods = \Drupal::config('language.types')->get('negotiation.language_interface.enabled') ?: [];
722 if (array_key_exists(\Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::METHOD_ID, $enabledLanguageMethods)) {
723 $urlType = $config['source'];
724
725 //url prefix
726 if ($urlType == \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::CONFIG_PATH_PREFIX) {
727 if (!empty($language)) {
c59c5519 728 if ($addLanguagePart && !empty($config['prefixes'][$language])) {
8da6670d 729 $url .= $config['prefixes'][$language] . '/';
730 }
731 if ($removeLanguagePart) {
732 $url = str_replace("/" . $config['prefixes'][$language] . "/", '/', $url);
733 }
734 }
735 }
736 //domain
737 if ($urlType == \Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl::CONFIG_DOMAIN) {
738 if (isset($language->domain) && $language->domain) {
739 if ($addLanguagePart) {
32040f62 740 $url = (CRM_Utils_System::isSSL() ? 'https' : 'http') . '://' . $config['domains'][$language] . base_path();
8da6670d 741 }
742 if ($removeLanguagePart && defined('CIVICRM_UF_BASEURL')) {
743 $url = str_replace('\\', '/', $url);
744 $parseUrl = parse_url($url);
745
746 //kinda hackish but not sure how to do it right
747 //hope http_build_url() will help at some point.
748 if (is_array($parseUrl) && !empty($parseUrl)) {
749 $urlParts = explode('/', $url);
750 $hostKey = array_search($parseUrl['host'], $urlParts);
751 $ufUrlParts = parse_url(CIVICRM_UF_BASEURL);
752 $urlParts[$hostKey] = $ufUrlParts['host'];
753 $url = implode('/', $urlParts);
754 }
755 }
756 }
757 }
758 }
759 }
760
761 return $url;
762 }
763
7e9cadcf 764}