delivery-8.x-1.x-dev/modules/workspaces_negotiator_path/src/Plugin/LanguageNegotiation/LanguageNegotiationWorkspaceAndUrl.php
modules/workspaces_negotiator_path/src/Plugin/LanguageNegotiation/LanguageNegotiationWorkspaceAndUrl.php
<?php
namespace Drupal\workspaces_negotiator_path\Plugin\LanguageNegotiation;
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Drupal\workspaces\WorkspaceManagerInterface;
use Drupal\workspaces_negotiator_path\Utils\PathPrefixHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class for identifying language via URL prefix or domain.
*
* @LanguageNegotiation(
* id = \Drupal\workspaces_negotiator_path\Plugin\LanguageNegotiation\LanguageNegotiationWorkspaceAndUrl::METHOD_ID,
* types = {\Drupal\Core\Language\LanguageInterface::TYPE_INTERFACE,
* \Drupal\Core\Language\LanguageInterface::TYPE_CONTENT,
* \Drupal\Core\Language\LanguageInterface::TYPE_URL},
* weight = -10,
* name = @Translation("Workspace prefix and URL"),
* description = @Translation("Language from the workspace path prefix and the URL (Path prefix or domain). All the settings can be provided in the URL language negotiation.")
* )
*/
class LanguageNegotiationWorkspaceAndUrl extends LanguageNegotiationUrl implements ContainerFactoryPluginInterface, OutboundPathProcessorInterface {
/**
* The language negotiation method id.
*/
const METHOD_ID = 'language-workspace-and-url';
/**
* @var \Drupal\workspaces\WorkspaceManagerInterface
* The workspace manager service.
*/
protected $workspaceManager;
/**
* LanguageNegotiationWorkspaceAndUrl constructor.
*/
public function __construct(WorkspaceManagerInterface $workspace_manager) {
$this->workspaceManager = $workspace_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$container->get('workspaces.manager')
);
}
/**
* {@inheritdoc}
*
* @todo: Find a way to not duplicate this pile of code.
*/
public function getLangcode(Request $request = NULL) {
$langcode = NULL;
if ($request && $this->languageManager) {
$languages = $this->languageManager->getLanguages();
$config = $this->config->get('language.negotiation')->get('url');
switch ($config['source']) {
case LanguageNegotiationUrl::CONFIG_DOMAIN:
$langcode = parent::getLangcode($request);
break;
case LanguageNegotiationUrl::CONFIG_PATH_PREFIX:
// In some cases (when the field storage needs to be updated for
// example because of a new field), loading a workspace may generate
// a database exception, because the field is not yet there. To fix
// this we just catch the exception and fallback to the parent
// implementation.
// Another case is when the this is called during a workspace
// negotiation (that can happen in some cases when importing
// configuration) when it will generate a
// ServiceCircularReferenceException because a call to get the active
// workspace will also trigger another workspace negotiation.
try {
$current_workspace = $this->workspaceManager->getActiveWorkspace();
}
catch (\RuntimeException $e) {
watchdog_exception('workspace_language_negotiation', $e);
return parent::getLangcode($request);
}
$path_prefix = $current_workspace->get('path_prefix')->getValue();
$request_path = urldecode($request->getPathInfo());
if (!empty($path_prefix[0]['value']) && $path_prefix[0]['value'] != '/') {
// Check first if the path prefix of the workspace is really a
// prefix for the current workspace. Only in that case we will
// remove the path prefix.
if (PathPrefixHelper::pathPrefixMatch($request_path, $path_prefix[0]['value'])) {
$request_path = substr($request_path, strlen($path_prefix[0]['value']));
}
}
$request_path = trim($request_path, '/');
$path_args = explode('/', $request_path);
$prefix = array_shift($path_args);
// Search prefix within added languages.
$negotiated_language = FALSE;
foreach ($languages as $language) {
if (isset($config['prefixes'][$language->getId()]) && $config['prefixes'][$language->getId()] == $prefix) {
$negotiated_language = $language;
break;
}
}
if ($negotiated_language) {
$langcode = $negotiated_language->getId();
}
break;
}
}
return $langcode;
}
/**
* {@inheritdoc}
*/
public function processOutbound($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
// Make sure that we actually use the interface language, in case no
// language is specified in the options. Otherwise, the parent method will
// use the url language detection, which is actually not configurable.
if (!isset($options['language'])) {
$language = $this->languageManager->getCurrentLanguage();
$options['language'] = $language;
}
// No need to actually call the parent processor here because it should be
// called by the language manager.
return parent::processOutbound($path, $options, $request, $bubbleable_metadata);
}
}
