"Fossies" - the Fresh Open Source Software Archive

Member "drupal-8.9.9/core/modules/language/src/LanguageNegotiator.php" (18 Nov 2020, 12050 Bytes) of package /linux/www/drupal-8.9.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "LanguageNegotiator.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Drupal\language;
    4 
    5 use Drupal\Component\Plugin\PluginManagerInterface;
    6 use Drupal\Core\Config\ConfigFactoryInterface;
    7 use Drupal\Core\Session\AccountInterface;
    8 use Drupal\Core\Site\Settings;
    9 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUI;
   10 use Symfony\Component\HttpFoundation\RequestStack;
   11 
   12 /**
   13  * Class responsible for performing language negotiation.
   14  */
   15 class LanguageNegotiator implements LanguageNegotiatorInterface {
   16 
   17   /**
   18    * The language negotiation method plugin manager.
   19    *
   20    * @var \Drupal\Component\Plugin\PluginManagerInterface
   21    */
   22   protected $negotiatorManager;
   23 
   24   /**
   25    * The language manager.
   26    *
   27    * @var \Drupal\language\ConfigurableLanguageManagerInterface
   28    */
   29   protected $languageManager;
   30 
   31   /**
   32    * The configuration factory.
   33    *
   34    * @var \Drupal\Core\Config\ConfigFactoryInterface
   35    */
   36   protected $configFactory;
   37 
   38   /**
   39    * The settings instance.
   40    *
   41    * @var \Drupal\Core\Site\Settings
   42    */
   43   protected $settings;
   44 
   45   /**
   46    * The request stack object.
   47    *
   48    * @var \Symfony\Component\HttpFoundation\RequestStack
   49    */
   50   protected $requestStack;
   51 
   52   /**
   53    * The current active user.
   54    *
   55    * @var \Drupal\Core\Session\AccountInterface
   56    */
   57   protected $currentUser;
   58 
   59   /**
   60    * Local cache for language negotiation method instances.
   61    *
   62    * @var array
   63    */
   64   protected $methods;
   65 
   66   /**
   67    * An array of language objects keyed by method id.
   68    *
   69    * @var \Drupal\Core\Language\LanguageInterface[]
   70    */
   71   protected $negotiatedLanguages = [];
   72 
   73   /**
   74    * Constructs a new LanguageNegotiator object.
   75    *
   76    * @param \Drupal\language\ConfigurableLanguageManagerInterface $language_manager
   77    *   The language manager.
   78    * @param \Drupal\Component\Plugin\PluginManagerInterface $negotiator_manager
   79    *   The language negotiation methods plugin manager
   80    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   81    *   The configuration factory.
   82    * @param \Drupal\Core\Site\Settings $settings
   83    *   The settings instance.
   84    */
   85   public function __construct(ConfigurableLanguageManagerInterface $language_manager, PluginManagerInterface $negotiator_manager, ConfigFactoryInterface $config_factory, Settings $settings, RequestStack $requestStack) {
   86     $this->languageManager = $language_manager;
   87     $this->negotiatorManager = $negotiator_manager;
   88     $this->configFactory = $config_factory;
   89     $this->settings = $settings;
   90     $this->requestStack = $requestStack;
   91   }
   92 
   93   /**
   94    * Initializes the injected language manager with the negotiator.
   95    *
   96    * This should be called right after instantiating the negotiator to make it
   97    * available to the language manager without introducing a circular
   98    * dependency.
   99    */
  100   public function initLanguageManager() {
  101     $this->languageManager->setNegotiator($this);
  102   }
  103 
  104   /**
  105    * {@inheritdoc}
  106    */
  107   public function reset() {
  108     $this->negotiatedLanguages = [];
  109     $this->methods = [];
  110   }
  111 
  112   /**
  113    * {@inheritdoc}
  114    */
  115   public function setCurrentUser(AccountInterface $current_user) {
  116     $this->currentUser = $current_user;
  117     $this->reset();
  118   }
  119 
  120   /**
  121    * {@inheritdoc}
  122    */
  123   public function initializeType($type) {
  124     $language = NULL;
  125 
  126     if ($this->currentUser) {
  127       // Execute the language negotiation methods in the order they were set up
  128       // and return the first valid language found.
  129       foreach ($this->getEnabledNegotiators($type) as $method_id => $info) {
  130         if (!isset($this->negotiatedLanguages[$method_id])) {
  131           $this->negotiatedLanguages[$method_id] = $this->negotiateLanguage($type, $method_id);
  132         }
  133 
  134         // Since objects are references, we need to return a clone to prevent
  135         // the language negotiation method cache from being unintentionally
  136         // altered. The same methods might be used with different language types
  137         // based on configuration.
  138         $language = !empty($this->negotiatedLanguages[$method_id]) ? clone($this->negotiatedLanguages[$method_id]) : NULL;
  139 
  140         if ($language) {
  141           $this->getNegotiationMethodInstance($method_id)->persist($language);
  142           break;
  143         }
  144       }
  145     }
  146 
  147     if (!$language) {
  148       // If no other language was found use the default one.
  149       $language = $this->languageManager->getDefaultLanguage();
  150       $method_id = static::METHOD_ID;
  151     }
  152 
  153     return [$method_id => $language];
  154   }
  155 
  156   /**
  157    * Gets enabled detection methods for the provided language type.
  158    *
  159    * @param string $type
  160    *   The language type.
  161    *
  162    * @return array
  163    *   An array of enabled detection methods for the provided language type.
  164    */
  165   protected function getEnabledNegotiators($type) {
  166     return $this->configFactory->get('language.types')->get('negotiation.' . $type . '.enabled') ?: [];
  167   }
  168 
  169   /**
  170    * Performs language negotiation using the specified negotiation method.
  171    *
  172    * @param string $type
  173    *   The language type to be initialized.
  174    * @param string $method_id
  175    *   The string identifier of the language negotiation method to use to detect
  176    *   language.
  177    *
  178    * @return \Drupal\Core\Language\LanguageInterface|null
  179    *   Negotiated language object for given type and method, FALSE otherwise.
  180    */
  181   protected function negotiateLanguage($type, $method_id) {
  182     $langcode = NULL;
  183     $method = $this->negotiatorManager->getDefinition($method_id);
  184 
  185     if (!isset($method['types']) || in_array($type, $method['types'])) {
  186       $langcode = $this->getNegotiationMethodInstance($method_id)->getLangcode($this->requestStack->getCurrentRequest());
  187     }
  188 
  189     $languages = $this->languageManager->getLanguages();
  190     return isset($languages[$langcode]) ? $languages[$langcode] : NULL;
  191   }
  192 
  193   /**
  194    * {@inheritdoc}
  195    */
  196   public function getNegotiationMethods($type = NULL) {
  197     $definitions = $this->negotiatorManager->getDefinitions();
  198     if (isset($type)) {
  199       $enabled_methods = $this->getEnabledNegotiators($type);
  200       $definitions = array_intersect_key($definitions, $enabled_methods);
  201     }
  202     return $definitions;
  203   }
  204 
  205   /**
  206    * {@inheritdoc}
  207    */
  208   public function getNegotiationMethodInstance($method_id) {
  209     if (!isset($this->methods[$method_id])) {
  210       $instance = $this->negotiatorManager->createInstance($method_id, []);
  211       $instance->setLanguageManager($this->languageManager);
  212       $instance->setConfig($this->configFactory);
  213       $instance->setCurrentUser($this->currentUser);
  214       $this->methods[$method_id] = $instance;
  215     }
  216     return $this->methods[$method_id];
  217   }
  218 
  219   /**
  220    * {@inheritdoc}
  221    */
  222   public function getPrimaryNegotiationMethod($type) {
  223     $enabled_methods = $this->getEnabledNegotiators($type);
  224     return empty($enabled_methods) ? LanguageNegotiatorInterface::METHOD_ID : key($enabled_methods);
  225   }
  226 
  227   /**
  228    * {@inheritdoc}
  229    */
  230   public function isNegotiationMethodEnabled($method_id, $type = NULL) {
  231     $enabled = FALSE;
  232     $language_types = !empty($type) ? [$type] : $this->languageManager->getLanguageTypes();
  233 
  234     foreach ($language_types as $type) {
  235       $enabled_methods = $this->getEnabledNegotiators($type);
  236       if (isset($enabled_methods[$method_id])) {
  237         $enabled = TRUE;
  238         break;
  239       }
  240     }
  241 
  242     return $enabled;
  243   }
  244 
  245   /**
  246    * {@inheritdoc}
  247    */
  248   public function saveConfiguration($type, $enabled_methods) {
  249     // As configurable language types might have changed, we reset the cache.
  250     $this->languageManager->reset();
  251     $definitions = $this->getNegotiationMethods();
  252     $default_types = $this->languageManager->getLanguageTypes();
  253 
  254     // Ensure that the weights are integers.
  255     $enabled_methods = array_map('intval', $enabled_methods);
  256 
  257     // Order the language negotiation method list by weight.
  258     asort($enabled_methods);
  259     foreach ($enabled_methods as $method_id => $weight) {
  260       if (isset($definitions[$method_id])) {
  261         $method = $definitions[$method_id];
  262         // If the language negotiation method does not express any preference
  263         // about types, make it available for any configurable type.
  264         $types = array_flip(!empty($method['types']) ? $method['types'] : $default_types);
  265         // Check whether the method is defined and has the right type.
  266         if (!isset($types[$type])) {
  267           unset($enabled_methods[$method_id]);
  268         }
  269       }
  270       else {
  271         unset($enabled_methods[$method_id]);
  272       }
  273     }
  274     $this->configFactory->getEditable('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save(TRUE);
  275   }
  276 
  277   /**
  278    * {@inheritdoc}
  279    */
  280   public function purgeConfiguration() {
  281     // Ensure that we are getting the defined language negotiation information.
  282     // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or
  283     // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the
  284     // cached information.
  285     $this->negotiatorManager->clearCachedDefinitions();
  286     $this->languageManager->reset();
  287     foreach ($this->languageManager->getDefinedLanguageTypesInfo() as $type => $info) {
  288       $this->saveConfiguration($type, $this->getEnabledNegotiators($type));
  289     }
  290   }
  291 
  292   /**
  293    * {@inheritdoc}
  294    */
  295   public function updateConfiguration(array $types) {
  296     // Ensure that we are getting the defined language negotiation information.
  297     // An invocation of \Drupal\Core\Extension\ModuleInstaller::install() or
  298     // \Drupal\Core\Extension\ModuleInstaller::uninstall() could invalidate the
  299     // cached information.
  300     $this->negotiatorManager->clearCachedDefinitions();
  301     $this->languageManager->reset();
  302 
  303     $language_types = [];
  304     $language_types_info = $this->languageManager->getDefinedLanguageTypesInfo();
  305     $method_definitions = $this->getNegotiationMethods();
  306 
  307     foreach ($language_types_info as $type => $info) {
  308       $configurable = in_array($type, $types);
  309 
  310       // The default language negotiation settings, if available, are stored in
  311       // $info['fixed'].
  312       $has_default_settings = !empty($info['fixed']);
  313       // Check whether the language type is unlocked. Only the status of
  314       // unlocked language types can be toggled between configurable and
  315       // non-configurable.
  316       if (empty($info['locked'])) {
  317         if (!$configurable && !$has_default_settings) {
  318           // If we have an unlocked non-configurable language type without
  319           // default language negotiation settings, we use the values
  320           // negotiated for the interface language which, should always be
  321           // available.
  322           $method_weights = [LanguageNegotiationUI::METHOD_ID];
  323           $method_weights = array_flip($method_weights);
  324           $this->saveConfiguration($type, $method_weights);
  325         }
  326       }
  327       else {
  328         // The language type is locked. Locked language types with default
  329         // settings are always considered non-configurable. In turn if default
  330         // settings are missing, the language type is always considered
  331         // configurable.
  332 
  333         // If the language type is locked we can just store its default language
  334         // negotiation settings if it has some, since it is not configurable.
  335         if ($has_default_settings) {
  336           $method_weights = [];
  337           // Default settings are in $info['fixed'].
  338 
  339           foreach ($info['fixed'] as $weight => $method_id) {
  340             if (isset($method_definitions[$method_id])) {
  341               $method_weights[$method_id] = $weight;
  342             }
  343           }
  344           $this->saveConfiguration($type, $method_weights);
  345         }
  346         else {
  347           // It was missing default settings, so force it to be configurable.
  348           $configurable = TRUE;
  349         }
  350       }
  351 
  352       // Accumulate information for each language type so it can be saved later.
  353       $language_types[$type] = $configurable;
  354     }
  355 
  356     // Store the language type configuration.
  357     $config = [
  358       'configurable' => array_keys(array_filter($language_types)),
  359       'all' => array_keys($language_types),
  360     ];
  361     $this->languageManager->saveLanguageTypesConfiguration($config);
  362   }
  363 
  364 }