3 namespace Drupal\config_translation;
5 use Drupal\config_translation\Event\ConfigMapperPopulateEvent;
6 use Drupal\config_translation\Event\ConfigTranslationEvents;
7 use Drupal\config_translation\Exception\ConfigMapperLanguageException;
8 use Drupal\Core\Config\ConfigFactoryInterface;
9 use Drupal\Core\Config\TypedConfigManagerInterface;
10 use Drupal\Core\Language\LanguageInterface;
11 use Drupal\Core\Language\LanguageManagerInterface;
12 use Drupal\Core\Plugin\PluginBase;
13 use Drupal\Core\Routing\RouteMatchInterface;
14 use Drupal\Core\Routing\RouteProviderInterface;
15 use Drupal\Core\StringTranslation\TranslationInterface;
16 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
18 use Drupal\locale\LocaleConfigManager;
19 use Symfony\Component\DependencyInjection\ContainerInterface;
20 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21 use Symfony\Component\Routing\Route;
22 use Symfony\Component\Routing\RouteCollection;
25 * Configuration mapper base implementation.
27 class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, ContainerFactoryPluginInterface {
30 * The configuration factory.
32 * @var \Drupal\Core\Config\ConfigFactoryInterface
34 protected $configFactory;
37 * The typed config manager.
39 * @var \Drupal\Core\Config\TypedConfigManagerInterface
41 protected $typedConfigManager;
44 * The typed configuration manager.
46 * @var \Drupal\locale\LocaleConfigManager
48 protected $localeConfigManager;
51 * The mapper plugin discovery service.
53 * @var \Drupal\config_translation\ConfigMapperManagerInterface
55 protected $configMapperManager;
60 * @var \Drupal\Core\Routing\RouteProviderInterface
62 protected $routeProvider;
65 * The base route object that the mapper is attached to.
67 * @var \Symfony\Component\Routing\Route
72 * The available routes.
74 * @var \Symfony\Component\Routing\RouteCollection
76 protected $routeCollection;
79 * The language code of the language this mapper, if any.
83 protected $langcode = NULL;
86 * The language manager.
88 * @var \Drupal\Core\Language\LanguageManagerInterface
90 protected $languageManager;
93 * The event dispatcher.
95 * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
97 protected $eventDispatcher;
100 * Constructs a ConfigNamesMapper.
103 * The config mapper plugin ID.
104 * @param mixed $plugin_definition
105 * An array of plugin information with the following keys:
106 * - title: The title of the mapper, used for generating page titles.
107 * - base_route_name: The route name of the base route this mapper is
109 * - names: (optional) An array of configuration names.
110 * - weight: (optional) The weight of this mapper, used in mapper listings.
112 * - list_controller: (optional) Class name for list controller used to
113 * generate lists of this type of configuration.
114 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
115 * The configuration factory.
116 * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config
117 * The typed configuration manager.
118 * @param \Drupal\locale\LocaleConfigManager $locale_config_manager
119 * The locale configuration manager.
120 * @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
121 * The mapper plugin discovery service.
122 * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
123 * The route provider.
124 * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
125 * The string translation manager.
126 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
127 * The language manager.
128 * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
129 * (optional) The event dispatcher.
131 * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException
132 * Throws an exception if the route specified by the 'base_route_name' in
133 * the plugin definition could not be found by the route provider.
135 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, EventDispatcherInterface $event_dispatcher = NULL) {
136 $this->pluginId = $plugin_id;
137 $this->pluginDefinition = $plugin_definition;
138 $this->routeProvider = $route_provider;
140 $this->configFactory = $config_factory;
141 $this->typedConfigManager = $typed_config;
142 $this->localeConfigManager = $locale_config_manager;
143 $this->configMapperManager = $config_mapper_manager;
145 $this->stringTranslation = $string_translation;
146 $this->languageManager = $language_manager;
147 $this->eventDispatcher = $event_dispatcher ?: \Drupal::service('event_dispatcher');
153 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
154 // Note that we ignore the plugin $configuration because mappers have
155 // nothing to configure in themselves.
159 $container->get('config.factory'),
160 $container->get('config.typed'),
161 $container->get('locale.config_manager'),
162 $container->get('plugin.manager.config_translation.mapper'),
163 $container->get('router.route_provider'),
164 $container->get('string_translation'),
165 $container->get('language_manager'),
166 $container->get('event_dispatcher')
173 public function setRouteCollection(RouteCollection $collection) {
174 $this->routeCollection = $collection;
180 public function getTitle() {
181 // A title from a *.config_translation.yml. Should be translated for
182 // display in the current page language.
183 return $this->t($this->pluginDefinition['title']);
189 public function getBaseRouteName() {
190 return $this->pluginDefinition['base_route_name'];
196 public function getBaseRouteParameters() {
203 public function getBaseRoute() {
204 if ($this->routeCollection) {
205 return $this->routeCollection->get($this->getBaseRouteName());
208 return $this->routeProvider->getRouteByName($this->getBaseRouteName());
213 * Allows to process all config translation routes.
215 * @param \Symfony\Component\Routing\Route $route
216 * The route object to process.
218 protected function processRoute(Route $route) {
224 public function getBasePath() {
225 return Url::fromRoute($this->getBaseRouteName(), $this->getBaseRouteParameters())->getInternalPath();
231 public function getOverviewRouteName() {
232 return 'config_translation.item.overview.' . $this->getBaseRouteName();
238 public function getOverviewRouteParameters() {
239 return $this->getBaseRouteParameters();
245 public function getOverviewRoute() {
247 $this->getBaseRoute()->getPath() . '/translate',
249 '_controller' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage',
250 'plugin_id' => $this->getPluginId(),
252 ['_config_translation_overview_access' => 'TRUE']
254 $this->processRoute($route);
261 public function getOverviewPath() {
262 return Url::fromRoute($this->getOverviewRouteName(), $this->getOverviewRouteParameters())->getInternalPath();
268 public function getAddRouteName() {
269 return 'config_translation.item.add.' . $this->getBaseRouteName();
275 public function getAddRouteParameters() {
276 // If sub-classes provide route parameters in getBaseRouteParameters(), they
277 // probably also want to provide those for the add, edit, and delete forms.
278 $parameters = $this->getBaseRouteParameters();
279 $parameters['langcode'] = $this->langcode;
286 public function getAddRoute() {
288 $this->getBaseRoute()->getPath() . '/translate/{langcode}/add',
290 '_form' => '\Drupal\config_translation\Form\ConfigTranslationAddForm',
291 'plugin_id' => $this->getPluginId(),
293 ['_config_translation_form_access' => 'TRUE']
295 $this->processRoute($route);
302 public function getEditRouteName() {
303 return 'config_translation.item.edit.' . $this->getBaseRouteName();
309 public function getEditRouteParameters() {
310 return $this->getAddRouteParameters();
316 public function getEditRoute() {
318 $this->getBaseRoute()->getPath() . '/translate/{langcode}/edit',
320 '_form' => '\Drupal\config_translation\Form\ConfigTranslationEditForm',
321 'plugin_id' => $this->getPluginId(),
323 ['_config_translation_form_access' => 'TRUE']
325 $this->processRoute($route);
332 public function getDeleteRouteName() {
333 return 'config_translation.item.delete.' . $this->getBaseRouteName();
339 public function getDeleteRouteParameters() {
340 return $this->getAddRouteParameters();
346 public function getDeleteRoute() {
348 $this->getBaseRoute()->getPath() . '/translate/{langcode}/delete',
350 '_form' => '\Drupal\config_translation\Form\ConfigTranslationDeleteForm',
351 'plugin_id' => $this->getPluginId(),
353 ['_config_translation_form_access' => 'TRUE']
355 $this->processRoute($route);
362 public function getConfigNames() {
363 return $this->pluginDefinition['names'];
369 public function addConfigName($name) {
370 $this->pluginDefinition['names'][] = $name;
376 public function getWeight() {
377 return $this->pluginDefinition['weight'];
383 public function populateFromRouteMatch(RouteMatchInterface $route_match) {
384 $this->langcode = $route_match->getParameter('langcode');
386 $event = new ConfigMapperPopulateEvent($this, $route_match);
387 $this->eventDispatcher->dispatch(ConfigTranslationEvents::POPULATE_MAPPER, $event);
393 public function getTypeLabel() {
394 return $this->getTitle();
400 public function getLangcode() {
401 $langcodes = array_map([$this, 'getLangcodeFromConfig'], $this->getConfigNames());
403 if (count(array_unique($langcodes)) > 1) {
404 throw new ConfigMapperLanguageException('A config mapper can only contain configuration for a single language.');
407 return reset($langcodes);
413 public function getLangcodeFromConfig($config_name) {
414 // Default to English if no language code was provided in the file.
415 // Although it is a best practice to include a language code, if the
416 // developer did not think about a multilingual use case, we fall back
417 // on assuming the file is English.
418 return $this->configFactory->get($config_name)->get('langcode') ?: 'en';
424 public function setLangcode($langcode) {
425 $this->langcode = $langcode;
432 public function getConfigData() {
434 foreach ($this->getConfigNames() as $name) {
435 $config_data[$name] = $this->configFactory->getEditable($name)->get();
443 public function hasSchema() {
444 foreach ($this->getConfigNames() as $name) {
445 if (!$this->typedConfigManager->hasConfigSchema($name)) {
455 public function hasTranslatable() {
456 foreach ($this->getConfigNames() as $name) {
457 if ($this->configMapperManager->hasTranslatable($name)) {
467 public function hasTranslation(LanguageInterface $language) {
468 foreach ($this->getConfigNames() as $name) {
469 if ($this->localeConfigManager->hasTranslation($name, $language->getId())) {
479 public function getTypeName() {
480 return $this->t('Settings');
486 public function getOperations() {
489 'title' => $this->t('Translate'),
490 'url' => Url::fromRoute($this->getOverviewRouteName(), $this->getOverviewRouteParameters()),
498 public function getContextualLinkGroup() {