diff --git a/config_translation.config_translation.yml b/config_translation.config_translation.yml deleted file mode 100644 index 0019f71..0000000 --- a/config_translation.config_translation.yml +++ /dev/null @@ -1,35 +0,0 @@ -maintenance: - type: names - base_path: 'admin/config/development/maintenance' - names: - - 'system.maintenance' - title: 'System maintenance' - add_edit_tab: '1' - class: '\Drupal\config_translation\ConfigNamesMapper' - -site_information: - type: names - base_path: 'admin/config/system/site-information' - names: - - 'system.site' - title: 'System information' - add_edit_tab: '1' - class: '\Drupal\config_translation\ConfigNamesMapper' - -rss_publishing: - type: names - base_path: 'admin/config/services/rss-publishing' - names: - - 'system.rss' - title: 'RSS publishing' - add_edit_tab: '1' - class: '\Drupal\config_translation\ConfigNamesMapper' - -people: - type: names - base_path: 'admin/config/people/accounts' - names: - - 'user.settings' - - 'user.mail' - title: 'Account settings' - class: '\Drupal\config_translation\ConfigNamesMapper' diff --git a/config_translation.services.yml b/config_translation.services.yml index 9871fee..30ee2d9 100644 --- a/config_translation.services.yml +++ b/config_translation.services.yml @@ -1,5 +1,5 @@ services: - config_translation.subscriber: + config_translation.route_subscriber: class: Drupal\config_translation\Routing\RouteSubscriber arguments: ['@plugin.manager.config_translation'] tags: @@ -11,9 +11,4 @@ services: - { name: access_check } plugin.manager.config_translation: class: Drupal\config_translation\ConfigMapperManager - arguments: - - '@cache.cache' - - '@language_manager' - - '@module_handler' - - '@entity.manager' - - '@string_translation' + arguments: ['@service_container'] diff --git a/lib/Drupal/config_translation/ConfigMapperManager.php b/lib/Drupal/config_translation/ConfigMapperManager.php index b5549c5..36d94a1 100644 --- a/lib/Drupal/config_translation/ConfigMapperManager.php +++ b/lib/Drupal/config_translation/ConfigMapperManager.php @@ -7,16 +7,13 @@ namespace Drupal\config_translation; use Drupal\Component\Utility\Unicode; -use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityManager; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Language\LanguageManager; +use Drupal\Core\Form\ConfigFormInterface; use Drupal\Core\Plugin\DefaultPluginManager; -use Drupal\Core\Plugin\Discovery\YamlDiscovery; -use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Factory\ContainerFactory; use Drupal\Core\StringTranslation\TranslationInterface; -use Drupal\Component\Plugin\Factory\DefaultFactory; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Manages plugins for configuration translation mappers. @@ -24,6 +21,16 @@ use Drupal\Component\Plugin\Factory\DefaultFactory; class ConfigMapperManager extends DefaultPluginManager { /** + * The dependency injection container. + * + * This is needed to instantiate form objects from the '_form' definition of + * routes. + * + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** * The entity manager. * * @var \Drupal\Core\Entity\EntityManager @@ -31,6 +38,15 @@ class ConfigMapperManager extends DefaultPluginManager { protected $entityManager; /** + * A database connection. + * + * Used to query the {router} table for routes. + * + * @var \Drupal\Core\Database\Connection + */ + protected $connection; + + /** * The string translation manager. * * @var \Drupal\Core\StringTranslation\TranslationInterface @@ -59,15 +75,18 @@ class ConfigMapperManager extends DefaultPluginManager { * @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager * The string translation manager. */ - public function __construct(CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, EntityManager $entity_manager, TranslationInterface $translation_manager) { - $this->entityManager = $entity_manager; - $this->translationManager = $translation_manager; + public function __construct(ContainerInterface $container) { + $this->container = $container; + + $this->entityManager = $this->container->get('entity.manager'); + $this->connection = $this->container->get('database'); + $this->translationManager = $this->container->get('string_translation'); $this->factory = new ContainerFactory($this); // Let others alter definitions with hook_config_translation_info_alter(). - $this->alterInfo($module_handler, 'config_translation_info'); - $this->setCacheBackend($cache_backend, $language_manager, 'config_translation_info'); + $this->alterInfo($this->container->get('module_handler'), 'config_translation_info'); + $this->setCacheBackend($this->container->get('cache.cache'), $this->container->get('language_manager'), 'config_translation_info'); } /** @@ -96,22 +115,11 @@ class ConfigMapperManager extends DefaultPluginManager { * List of definitions to store in cache. */ protected function findDefinitions() { - $definitions = $this->findConfigEntityDefinitions(); + $definitions = array(); - // Look at all themes and modules. - $directories = array(); - foreach ($this->moduleHandler->getModuleList() as $module => $filename) { - $directories[$module] = dirname($filename); - } - foreach (list_themes() as $theme_id => $theme) { - $directories[$theme->name] = drupal_get_path('theme', $theme->name); - } + $definitions += $this->findConfigEntityDefinitions(); + $definitions += $this->findConfigFormDefinitions(); - // Check for files named MODULE.config_translation.yml and - // THEME.config_translation.yml in module/theme roots. - $discovery = new YamlDiscovery('config_translation', $directories); - $discovery_decorator = new ContainerDerivativeDiscoveryDecorator($discovery); - $definitions += $discovery_decorator->getDefinitions(); foreach ($definitions as $plugin_id => &$definition) { $this->processDefinition($definition, $plugin_id); @@ -143,8 +151,8 @@ class ConfigMapperManager extends DefaultPluginManager { $base_path = $entity_info['links']['edit-form']; - // Use the entity type as the plugin ID. - $definitions[$entity_type] = array( + // Use the entity type as part of the plugin ID. + $definitions['entity.' . $entity_type] = array( 'class' => '\Drupal\config_translation\ConfigEntityMapper', 'base_path' => $base_path, 'title' => $this->t('@label @entity_type', array('@entity_type' => Unicode::strtolower($entity_type))), @@ -156,6 +164,77 @@ class ConfigMapperManager extends DefaultPluginManager { } /** + * Finds plugin definitions by scanning configuration entity information. + */ + protected function findConfigFormDefinitions() { + $definitions = array(); + // First we gather all routes and see whether they are configuration forms. + // @todo \Drupal\Core\Routing\RouteProvider should provide a getAllRoutes() + // method. + $routes = $this->connection->query('SELECT name, route FROM {router}')->fetchAllKeyed(); + array_walk($routes, function (&$route) { $route = unserialize($route); }); + + foreach ($routes as $route_name => $route) { + /** @var \Symfony\Component\Routing\Route $route */ + if (!$route->hasDefault('_form')) { + continue; + } + + $form_definition = $route->getDefault('_form'); + // See \Drupal\Core\Controller\HtmlFormController::getFormObject() + // If this is a class, instantiate it. + if (class_exists($form_definition)) { + $interfaces = class_implements($form_definition); + $implements = in_array('Drupal\Core\DependencyInjection\ContainerInjectionInterface', class_implements($form_definition)); + if (in_array('Drupal\Core\DependencyInjection\ContainerInjectionInterface', class_implements($form_definition))) { + $form = $form_definition::create($this->container); + } + else { + $form = new $form_definition(); + } + } + // Otherwise, it is a service. + else { + $form = $this->container->get($form_definition); + } + + if (!($form instanceof ConfigFormInterface)) { + continue; + } + + $config_names = $form->getConfigNames(); + + // Check whether the configuration contains translatable keys + // by checking the configuration schema. + $config_names = array_filter($config_names, 'config_translation_has_translatable'); + + if (empty($config_names)) { + continue; + } + + // \Drupal\Core\Controller\TitleResolver requires a request, so we + // cannot use it to generate the title. We check the static '_title' as + // a best effort. + // Should there be a FormInterface::getTitle()? + if ($route->hasDefault('_title')) { + $title = $route->getDefault('_title'); + } + else { + $title = $this->t('Translation form for @config_names', array('@config_names' => implode(', ', $config_names))); + } + + $definitions['form_route.' . $form->getFormId()] = array( + 'class' => '\Drupal\config_translation\ConfigNamesMapper', + 'base_path' => $route->getPath(), + 'title' => $title, + 'names' => $config_names, + ); + } + + return $definitions; + } + + /** * Translates a string to the current language or to a given language. * * See the t() documentation for details. @@ -163,4 +242,5 @@ class ConfigMapperManager extends DefaultPluginManager { protected function t($string, array $args = array(), array $options = array()) { return $this->translationManager->translate($string, $args, $options); } + } diff --git a/lib/Drupal/config_translation/ConfigNamesMapper.php b/lib/Drupal/config_translation/ConfigNamesMapper.php index 92df383..5811691 100644 --- a/lib/Drupal/config_translation/ConfigNamesMapper.php +++ b/lib/Drupal/config_translation/ConfigNamesMapper.php @@ -307,11 +307,12 @@ class ConfigNamesMapper extends DependencySerialization implements ConfigMapperI $name = $this->getRouteName(); return array( $name => new Route($path . '/translate', array( - '_controller' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage', - 'mapper_plugin' => array('plugin_id' => $this->getId(), 'plugin_definition' => $this->pluginDefinition), - ),array( - '_config_translation_config_name_access' => 'TRUE', - )) + '_controller' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage', + 'mapper_plugin' => array('plugin_id' => $this->getId(), 'plugin_definition' => $this->pluginDefinition), + ),array( + '_config_translation_config_name_access' => 'TRUE', + ) + ), ); }