diff --git a/core/modules/config_translation/src/ConfigEntityMapper.php b/core/modules/config_translation/src/ConfigEntityMapper.php index 7caf72c..8bf8cd4 100644 --- a/core/modules/config_translation/src/ConfigEntityMapper.php +++ b/core/modules/config_translation/src/ConfigEntityMapper.php @@ -7,6 +7,7 @@ namespace Drupal\config_translation; +use Drupal\config_translation\Event\ConfigTranslationEvents; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\Entity\ConfigEntityInterface; use Drupal\Core\Config\TypedConfigManagerInterface; @@ -18,6 +19,7 @@ use Drupal\Core\Url; use Drupal\locale\LocaleConfigManager; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Routing\Route; /** @@ -74,13 +76,15 @@ class ConfigEntityMapper extends ConfigNamesMapper { * The route provider. * @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager * The string translation manager. - * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager - * The entity manager. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. */ - 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 $translation_manager, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) { - parent::__construct($plugin_id, $plugin_definition, $config_factory, $typed_config, $locale_config_manager, $config_mapper_manager, $route_provider, $translation_manager, $language_manager); + 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 $translation_manager, LanguageManagerInterface $language_manager, EventDispatcherInterface $event_dispatcher, EntityManagerInterface $entity_manager) { + parent::__construct($plugin_id, $plugin_definition, $config_factory, $typed_config, $locale_config_manager, $config_mapper_manager, $route_provider, $translation_manager, $language_manager, $event_dispatcher); $this->setType($plugin_definition['entity_type']); $this->entityManager = $entity_manager; @@ -101,8 +105,9 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('plugin.manager.config_translation.mapper'), $container->get('router.route_provider'), $container->get('string_translation'), - $container->get('entity.manager'), - $container->get('language_manager') + $container->get('language_manager'), + $container->get('event_dispatcher'), + $container->get('entity.manager') ); } @@ -110,9 +115,12 @@ public static function create(ContainerInterface $container, array $configuratio * {@inheritdoc} */ public function populateFromRouteMatch(RouteMatchInterface $route_match) { - parent::populateFromRouteMatch($route_match); + $this->setLangcode($route_match->getParameter('langcode')); + $entity = $route_match->getParameter($this->entityType); $this->setEntity($entity); + + $this->dispatchMapperEvent(ConfigTranslationEvents::POPULATE_MAPPER); } /** diff --git a/core/modules/config_translation/src/ConfigMapperInterface.php b/core/modules/config_translation/src/ConfigMapperInterface.php index 507b191..fa59b27 100644 --- a/core/modules/config_translation/src/ConfigMapperInterface.php +++ b/core/modules/config_translation/src/ConfigMapperInterface.php @@ -282,6 +282,8 @@ public function hasTranslation(LanguageInterface $language); * * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route match. + * + * @see \Drupal\config_translation\Event\ConfigTranslationEvents::POPULATE_MAPPER */ public function populateFromRouteMatch(RouteMatchInterface $route_match); diff --git a/core/modules/config_translation/src/ConfigNamesMapper.php b/core/modules/config_translation/src/ConfigNamesMapper.php index 5d15dd5..dc11df2 100644 --- a/core/modules/config_translation/src/ConfigNamesMapper.php +++ b/core/modules/config_translation/src/ConfigNamesMapper.php @@ -7,6 +7,8 @@ namespace Drupal\config_translation; +use Drupal\config_translation\Event\ConfigMapperEvent; +use Drupal\config_translation\Event\ConfigTranslationEvents; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Language\LanguageInterface; @@ -19,6 +21,7 @@ use Drupal\Core\Url; use Drupal\locale\LocaleConfigManager; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -91,6 +94,13 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con protected $languageManager; /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** * Constructs a ConfigNamesMapper. * * @param $plugin_id @@ -119,12 +129,14 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con * The string translation manager. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. * * @throws \Symfony\Component\Routing\Exception\RouteNotFoundException * Throws an exception if the route specified by the 'base_route_name' in * the plugin definition could not be found by the route provider. */ - 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) { + 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) { $this->pluginId = $plugin_id; $this->pluginDefinition = $plugin_definition; $this->routeProvider = $route_provider; @@ -136,6 +148,8 @@ public function __construct($plugin_id, $plugin_definition, ConfigFactoryInterfa $this->stringTranslation = $string_translation; $this->languageManager = $language_manager; + + $this->eventDispatcher = $event_dispatcher; } /** @@ -153,7 +167,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('plugin.manager.config_translation.mapper'), $container->get('router.route_provider'), $container->get('string_translation'), - $container->get('language_manager') + $container->get('language_manager'), + $container->get('event_dispatcher') ); } @@ -371,7 +386,21 @@ public function getWeight() { * {@inheritdoc} */ public function populateFromRouteMatch(RouteMatchInterface $route_match) { - $this->langcode = $route_match->getParameter('langcode'); + $this->setLangcode($route_match->getParameter('langcode')); + $this->dispatchMapperEvent(ConfigTranslationEvents::POPULATE_MAPPER); + } + + /** + * Dispatches the ConfigTranslationEvents::POPULATE_MAPPER event. + * + * @param string $event_name + * The event name of the configuration mapper event to dispatch. + * + * @see \Drupal\config_translation\Event\ConfigTranslationEvents + */ + protected function dispatchMapperEvent($event_name) { + $event = new ConfigMapperEvent($this); + $this->eventDispatcher->dispatch($event_name, $event); } /** diff --git a/core/modules/config_translation/src/Event/ConfigMapperEvent.php b/core/modules/config_translation/src/Event/ConfigMapperEvent.php new file mode 100644 index 0000000..5966563 --- /dev/null +++ b/core/modules/config_translation/src/Event/ConfigMapperEvent.php @@ -0,0 +1,45 @@ +mapper = $mapper; + } + + /** + * Gets the configuration mapper this event is related to. + * + * @return \Drupal\config_translation\ConfigMapperInterface + * The configuration mapper this event is related to. + */ + public function getMapper() { + return $this->mapper; + } + +} diff --git a/core/modules/config_translation/src/Event/ConfigTranslationEvents.php b/core/modules/config_translation/src/Event/ConfigTranslationEvents.php new file mode 100644 index 0000000..a4bd1a6 --- /dev/null +++ b/core/modules/config_translation/src/Event/ConfigTranslationEvents.php @@ -0,0 +1,23 @@ +getMapper(); + if ($mapper->getBaseRouteName() === 'system.site_information_settings' && $mapper->getLangcode() === 'en') { + $mapper->addConfigName('config_translation_test.content'); + } + } + +} diff --git a/core/modules/config_translation/tests/src/Kernel/ConfigMapperTest.php b/core/modules/config_translation/tests/src/Kernel/ConfigMapperTest.php new file mode 100644 index 0000000..681ce7c --- /dev/null +++ b/core/modules/config_translation/tests/src/Kernel/ConfigMapperTest.php @@ -0,0 +1,52 @@ +getMappers(); + $mapper = $mappers['system.site_information_settings']; + + // Test that it doesn't contain a config name from config_translation_test. + $config_names = $mapper->getConfigNames(); + $this->assertFalse(in_array('config_translation_test.content', $config_names)); + + // Call populateFromRouteMatch() to dispatch an event. + $mapper->populateFromRouteMatch(new RouteMatch('test', new Route('/'))); + + // Test that it now contains the new config name from config_translation_test. + $config_names = $mapper->getConfigNames(); + $this->assertTrue(in_array('config_translation_test.content', $config_names)); + } + +} diff --git a/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php index f80677f..d9903d5 100644 --- a/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php +++ b/core/modules/config_translation/tests/src/Unit/ConfigEntityMapperTest.php @@ -54,6 +54,13 @@ class ConfigEntityMapperTest extends UnitTestCase { */ protected $languageManager; + /** + * The mocked event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eventDispatcher; + protected function setUp() { $this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface'); @@ -84,6 +91,8 @@ protected function setUp() { $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface'); + $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->configEntityMapper = new ConfigEntityMapper( 'configurable_language', $definition, @@ -93,8 +102,9 @@ protected function setUp() { $this->getMock('Drupal\config_translation\ConfigMapperManagerInterface'), $this->routeProvider, $this->getStringTranslationStub(), - $this->entityManager, - $this->languageManager + $this->languageManager, + $this->eventDispatcher, + $this->entityManager ); } diff --git a/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php index 3a78357..7ccf0b8 100644 --- a/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php +++ b/core/modules/config_translation/tests/src/Unit/ConfigFieldMapperTest.php @@ -41,6 +41,13 @@ class ConfigFieldMapperTest extends UnitTestCase { protected $entityManager; /** + * The mocked event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eventDispatcher; + + /** * {@inheritdoc} */ protected function setUp() { @@ -59,6 +66,8 @@ protected function setUp() { ->disableOriginalConstructor() ->getMock(); + $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->configFieldMapper = new ConfigFieldMapper( 'node_fields', $definition, @@ -68,8 +77,9 @@ protected function setUp() { $this->getMock('Drupal\config_translation\ConfigMapperManagerInterface'), $this->getMock('Drupal\Core\Routing\RouteProviderInterface'), $this->getStringTranslationStub(), - $this->entityManager, - $this->getMock('Drupal\Core\Language\LanguageManagerInterface') + $this->getMock('Drupal\Core\Language\LanguageManagerInterface'), + $this->eventDispatcher, + $this->entityManager ); } diff --git a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php index 4d5765f..4d82ccc 100644 --- a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php +++ b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php @@ -88,6 +88,13 @@ class ConfigNamesMapperTest extends UnitTestCase { */ protected $languageManager; + /** + * The mocked event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eventDispatcher; + protected function setUp() { $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface'); @@ -122,6 +129,8 @@ protected function setUp() { $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface'); + $this->eventDispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + $this->configNamesMapper = new TestConfigNamesMapper( 'system.site_information_settings', $this->pluginDefinition, @@ -131,7 +140,8 @@ protected function setUp() { $this->configMapperManager, $this->routeProvider, $this->getStringTranslationStub(), - $this->languageManager + $this->languageManager, + $this->eventDispatcher ); } diff --git a/core/modules/field_ui/field_ui.services.yml b/core/modules/field_ui/field_ui.services.yml index f6744eb..7887e39 100644 --- a/core/modules/field_ui/field_ui.services.yml +++ b/core/modules/field_ui/field_ui.services.yml @@ -19,3 +19,8 @@ services: arguments: ['@entity.manager'] tags: - { name: access_check, applies_to: _field_ui_form_mode_access } + field_ui.config_translation_subscriber: + class: Drupal\field_ui\ConfigTranslation\EntityDisplaySubscriber + arguments: ['@config.factory'] + tags: + - { name: event_subscriber } diff --git a/core/modules/field_ui/src/ConfigTranslation/EntityDisplaySubscriber.php b/core/modules/field_ui/src/ConfigTranslation/EntityDisplaySubscriber.php new file mode 100644 index 0000000..4039c5e --- /dev/null +++ b/core/modules/field_ui/src/ConfigTranslation/EntityDisplaySubscriber.php @@ -0,0 +1,91 @@ +configFactory = $config_factory; + } + + /** + * Reacts to the population of a configuration mapper. + * + * @param \Drupal\config_translation\Event\ConfigMapperEvent $event + * The configuration mapper event. + * + * @see \Drupal\field_ui\Routing\RouteSubscriber::alterRoutes() + */ + public function onMapperPopulate(ConfigMapperEvent $event) { + $mapper = $event->getMapper(); + $base_route = $mapper->getBaseRoute(); + + if ( + !($mapper instanceof ConfigEntityMapper) || + !($entity_type_id = $base_route->getOption('_field_ui_base_route')) + ) { + return; + } + $entity = $mapper->getEntity(); + + // Determine the bundle (if any) of the route. + $bundle = NULL; + if ($entity_type_id === $entity->getEntityType()->getBundleOf()) { + $bundle = $entity->id(); + } + elseif ($base_route->getDefault('bundle')) { + $bundle = $base_route->getDefault('bundle'); + } + + // Add all form and view displays of the respective entity type and bundle + // (if any) to the mapper. + foreach (['entity_form_display', 'entity_view_display'] as $display_type) { + $prefix = "core.$display_type.$entity_type_id."; + if ($bundle) { + $prefix .= "$bundle."; + } + + $config_names = $this->configFactory->listAll($prefix); + foreach ($config_names as $config_name) { + $mapper->addConfigName($config_name); + } + } + + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return [ConfigTranslationEvents::POPULATE_MAPPER => 'onMapperPopulate']; + } + +} diff --git a/core/modules/field_ui/src/Routing/RouteSubscriber.php b/core/modules/field_ui/src/Routing/RouteSubscriber.php index 8f1b8f1..de6a286 100644 --- a/core/modules/field_ui/src/Routing/RouteSubscriber.php +++ b/core/modules/field_ui/src/Routing/RouteSubscriber.php @@ -45,6 +45,12 @@ protected function alterRoutes(RouteCollection $collection) { if (!$entity_route = $collection->get($route_name)) { continue; } + // Set a route option to easily identify all Field UI base routes and to + // determine the entity type the route is for. + $entity_route->setOption('_field_ui_base_route', $entity_type_id); + // RouteCollection::add() overwrites exiting routes with the same name. + $collection->add($route_name, $entity_route); + $path = $entity_route->getPath(); $options = $entity_route->getOptions(); @@ -53,7 +59,11 @@ protected function alterRoutes(RouteCollection $collection) { 'type' => 'entity:' . $bundle_entity_type, ); } - // Special parameter used to easily recognize all Field UI routes. + // Set a route option to easily identify all Field UI base routes and to + // determine the entity type the routes are for. + $options['_field_ui_route'] = $entity_type_id; + // This is retained for backwards-compatibility. + // @todo Remove in Drupal 9 $options['_field_ui'] = TRUE; $defaults = array(