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