3 namespace Drupal\config_translation;
5 use Drupal\config_translation\Exception\ConfigMapperLanguageException;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\Config\TypedConfigManagerInterface;
8 use Drupal\Core\Language\LanguageInterface;
9 use Drupal\Core\Language\LanguageManagerInterface;
10 use Drupal\Core\Plugin\PluginBase;
11 use Drupal\Core\Routing\RouteMatchInterface;
12 use Drupal\Core\Routing\RouteProviderInterface;
13 use Drupal\Core\StringTranslation\TranslationInterface;
14 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
16 use Drupal\locale\LocaleConfigManager;
17 use Symfony\Component\DependencyInjection\ContainerInterface;
18 use Symfony\Component\Routing\Route;
19 use Symfony\Component\Routing\RouteCollection;
22 * Configuration mapper base implementation.
24 class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, ContainerFactoryPluginInterface {
27 * The configuration factory.
29 * @var \Drupal\Core\Config\ConfigFactoryInterface
31 protected $configFactory;
34 * The typed config manager.
36 * @var \Drupal\Core\Config\TypedConfigManagerInterface
38 protected $typedConfigManager;
41 * The typed configuration manager.
43 * @var \Drupal\locale\LocaleConfigManager
45 protected $localeConfigManager;
48 * The mapper plugin discovery service.
50 * @var \Drupal\config_translation\ConfigMapperManagerInterface
52 protected $configMapperManager;
57 * @var \Drupal\Core\Routing\RouteProviderInterface
59 protected $routeProvider;
62 * The base route object that the mapper is attached to.
64 * @return \Symfony\Component\Routing\Route
69 * The available routes.
71 * @var \Symfony\Component\Routing\RouteCollection
73 protected $routeCollection;
76 * The language code of the language this mapper, if any.
80 protected $langcode = NULL;
83 * The language manager.
85 * @var \Drupal\Core\Language\LanguageManagerInterface
87 protected $languageManager;
90 * Constructs a ConfigNamesMapper.
93 * The config mapper plugin ID.
94 * @param mixed $plugin_definition
95 * An array of plugin information with the following keys:
96 * - title: The title of the mapper, used for generating page titles.
97 * - base_route_name: The route name of the base route this mapper is
99 * - names: (optional) An array of configuration names.
100 * - weight: (optional) The weight of this mapper, used in mapper listings.
102 * - list_controller: (optional) Class name for list controller used to
103 * generate lists of this type of configuration.
104 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
105 * The configuration factory.
106 * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
107 * The typed configuration manager.
108 * @param \Drupal\locale\LocaleConfigManager $locale_config_manager
109 * The locale configuration manager.
110 * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
111 * The mapper plugin discovery service.
112 * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
113 * The route provider.
114 * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
115 * The string translation manager.
116 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
117 * The language manager.
119 * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
120 * Throws an exception if the route specified by the 'base_route_name' in
121 * the plugin definition could not be found by the route provider.
123 public function __construct($plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typed_config, LocaleConfigManager $locale_config_manager, ConfigMapperManagerInterface $config_mapper_manager, RouteProviderInterface $route_provider, TranslationInterface $string_translation, LanguageManagerInterface $language_manager) {
124 $this->pluginId = $plugin_id;
125 $this->pluginDefinition = $plugin_definition;
126 $this->routeProvider = $route_provider;
128 $this->configFactory = $config_factory;
129 $this->typedConfigManager = $typed_config;
130 $this->localeConfigManager = $locale_config_manager;
131 $this->configMapperManager = $config_mapper_manager;
133 $this->stringTranslation = $string_translation;
134 $this->languageManager = $language_manager;
140 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
141 // Note that we ignore the plugin $configuration because mappers have
142 // nothing to configure in themselves.
146 $container->get('config.factory'),
147 $container->get('config.typed'),
148 $container->get('locale.config_manager'),
149 $container->get('plugin.manager.config_translation.mapper'),
150 $container->get('router.route_provider'),
151 $container->get('string_translation'),
152 $container->get('language_manager')
159 public function setRouteCollection(RouteCollection $collection) {
160 $this->routeCollection = $collection;
166 public function getTitle() {
167 // A title from a *.config_translation.yml. Should be translated for
168 // display in the current page language.
169 return $this->t($this->pluginDefinition['title']);
175 public function getBaseRouteName() {
176 return $this->pluginDefinition['base_route_name'];
182 public function getBaseRouteParameters() {
189 public function getBaseRoute() {
190 if ($this->routeCollection) {
191 return $this->routeCollection->get($this->getBaseRouteName());
194 return $this->routeProvider->getRouteByName($this->getBaseRouteName());
199 * Allows to process all config translation routes.
201 * @param \Symfony\Component\Routing\Route $route
202 * The route object to process.
204 protected function processRoute(Route $route) {
210 public function getBasePath() {
211 return Url::fromRoute($this->getBaseRouteName(), $this->getBaseRouteParameters())->getInternalPath();
217 public function getOverviewRouteName() {
218 return 'config_translation.item.overview.' . $this->getBaseRouteName();
224 public function getOverviewRouteParameters() {
225 return $this->getBaseRouteParameters();
231 public function getOverviewRoute() {
233 $this->getBaseRoute()->getPath() . '/translate',
235 '_controller' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage',
236 'plugin_id' => $this->getPluginId(),
238 ['_config_translation_overview_access' => 'TRUE']
240 $this->processRoute($route);
247 public function getOverviewPath() {
248 return Url::fromRoute($this->getOverviewRouteName(), $this->getOverviewRouteParameters())->getInternalPath();
254 public function getAddRouteName() {
255 return 'config_translation.item.add.' . $this->getBaseRouteName();
261 public function getAddRouteParameters() {
262 // If sub-classes provide route parameters in getBaseRouteParameters(), they
263 // probably also want to provide those for the add, edit, and delete forms.
264 $parameters = $this->getBaseRouteParameters();
265 $parameters['langcode'] = $this->langcode;
272 public function getAddRoute() {
274 $this->getBaseRoute()->getPath() . '/translate/{langcode}/add',
276 '_form' => '\Drupal\config_translation\Form\ConfigTranslationAddForm',
277 'plugin_id' => $this->getPluginId(),
279 ['_config_translation_form_access' => 'TRUE']
281 $this->processRoute($route);
288 public function getEditRouteName() {
289 return 'config_translation.item.edit.' . $this->getBaseRouteName();
295 public function getEditRouteParameters() {
296 return $this->getAddRouteParameters();
302 public function getEditRoute() {
304 $this->getBaseRoute()->getPath() . '/translate/{langcode}/edit',
306 '_form' => '\Drupal\config_translation\Form\ConfigTranslationEditForm',
307 'plugin_id' => $this->getPluginId(),
309 ['_config_translation_form_access' => 'TRUE']
311 $this->processRoute($route);
318 public function getDeleteRouteName() {
319 return 'config_translation.item.delete.' . $this->getBaseRouteName();
325 public function getDeleteRouteParameters() {
326 return $this->getAddRouteParameters();
332 public function getDeleteRoute() {
334 $this->getBaseRoute()->getPath() . '/translate/{langcode}/delete',
336 '_form' => '\Drupal\config_translation\Form\ConfigTranslationDeleteForm',
337 'plugin_id' => $this->getPluginId(),
339 ['_config_translation_form_access' => 'TRUE']
341 $this->processRoute($route);
348 public function getConfigNames() {
349 return $this->pluginDefinition['names'];
355 public function addConfigName($name) {
356 $this->pluginDefinition['names'][] = $name;
362 public function getWeight() {
363 return $this->pluginDefinition['weight'];
369 public function populateFromRouteMatch(RouteMatchInterface $route_match) {
370 $this->langcode = $route_match->getParameter('langcode');
376 public function getTypeLabel() {
377 return $this->getTitle();
383 public function getLangcode() {
384 $langcodes = array_map([$this, 'getLangcodeFromConfig'], $this->getConfigNames());
386 if (count(array_unique($langcodes)) > 1) {
387 throw new ConfigMapperLanguageException('A config mapper can only contain configuration for a single language.');
390 return reset($langcodes);
396 public function getLangcodeFromConfig($config_name) {
397 // Default to English if no language code was provided in the file.
398 // Although it is a best practice to include a language code, if the
399 // developer did not think about a multilingual use case, we fall back
400 // on assuming the file is English.
401 return $this->configFactory->get($config_name)->get('langcode') ?: 'en';
407 public function setLangcode($langcode) {
408 $this->langcode = $langcode;
415 public function getConfigData() {
417 foreach ($this->getConfigNames() as $name) {
418 $config_data[$name] = $this->configFactory->getEditable($name)->get();
426 public function hasSchema() {
427 foreach ($this->getConfigNames() as $name) {
428 if (!$this->typedConfigManager->hasConfigSchema($name)) {
438 public function hasTranslatable() {
439 foreach ($this->getConfigNames() as $name) {
440 if ($this->configMapperManager->hasTranslatable($name)) {
450 public function hasTranslation(LanguageInterface $language) {
451 foreach ($this->getConfigNames() as $name) {
452 if ($this->localeConfigManager->hasTranslation($name, $language->getId())) {
462 public function getTypeName() {
463 return $this->t('Settings');
469 public function getOperations() {
472 'title' => $this->t('Translate'),
473 'url' => Url::fromRoute($this->getOverviewRouteName(), $this->getOverviewRouteParameters()),
481 public function getContextualLinkGroup() {