diff --git a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php index 82d988aa9a0..4e041cebc38 100644 --- a/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php +++ b/core/modules/config_translation/src/Access/ConfigTranslationFormAccess.php @@ -2,8 +2,6 @@ namespace Drupal\config_translation\Access; -use Drupal\config_translation\ConfigMapperInterface; -use Drupal\config_translation\Exception\ConfigMapperLanguageException; use Drupal\Core\Access\AccessResult; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; @@ -14,68 +12,27 @@ use Drupal\Core\Session\AccountInterface; class ConfigTranslationFormAccess extends ConfigTranslationOverviewAccess { /** - * Checks access to the overview based on permissions and translatability. - * - * @param \Drupal\Core\Routing\RouteMatchInterface $route_match - * The route_match to check against. - * @param \Drupal\Core\Session\AccountInterface $account - * The account to check access for. - * @param string $langcode - * The language code of the target language. - * - * @return \Drupal\Core\Access\AccessResultInterface - * The access result. + * {@inheritdoc} */ public function access(RouteMatchInterface $route_match, AccountInterface $account, $langcode = NULL) { - $mapper = $this->getMapperFromRouteMatch($route_match); - - try { - $source_langcode = $mapper->getLangcode(); - $source_language = $this->languageManager->getLanguage($source_langcode); - + // For the translation forms we have a target language, so we need some + // checks in addition to the checks performed for the translation overview. + $base_access = parent::access($route_match, $account); + if ($base_access->isAllowed()) { $target_language = $this->languageManager->getLanguage($langcode); - return $this->doCheckAccess($account, $mapper, $source_language, $target_language); + // Make sure that the target language is not locked, and that the target + // language is not the original submission language. Although technically + // configuration can be overlaid with translations in the same language, + // that is logically not a good idea. + $access = + !empty($target_language) && + !$target_language->isLocked() && + (empty($this->sourceLanguage) || ($target_language->getId() != $this->sourceLanguage->getId())); + + return $base_access->andIf(AccessResult::allowedIf($access)); } - catch (ConfigMapperLanguageException $exception) { - return AccessResult::forbidden(); - } - } - - /** - * Checks access given an account, configuration mapper, and source language. - * - * In addition to the checks performed by - * ConfigTranslationOverviewAccess::doCheckAccess() this makes sure the target - * language is not locked and the target language is not the source language. - * - * Although technically configuration can be overlaid with translations in the - * same language, that is logically not a good idea. - * - * @param \Drupal\Core\Session\AccountInterface $account - * The account to check access for. - * @param \Drupal\config_translation\ConfigMapperInterface $mapper - * The configuration mapper to check access for. - * @param \Drupal\Core\Language\LanguageInterface|null $source_language - * The source language to check for, if any. - * @param \Drupal\Core\Language\LanguageInterface|null $target_language - * The target language to check for, if any. - * - * @return \Drupal\Core\Access\AccessResultInterface - * The result of the access check. - * - * @see \Drupal\config_translation\Access\ConfigTranslationOverviewAccess::doCheckAccess() - */ - protected function doCheckAccess(AccountInterface $account, ConfigMapperInterface $mapper, $source_language = NULL, $target_language = NULL) { - $base_access_result = parent::doCheckAccess($account, $mapper, $source_language); - - $access = - $target_language && - !$target_language->isLocked() && - (!$source_language || ($target_language->getId() !== $source_language->getId())); - - return $base_access_result->andIf(AccessResult::allowedIf($access)); - + return $base_access; } } diff --git a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php index 7dea89c8319..91ccf49ad12 100644 --- a/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php +++ b/core/modules/config_translation/src/Access/ConfigTranslationOverviewAccess.php @@ -2,8 +2,7 @@ namespace Drupal\config_translation\Access; -use Drupal\config_translation\ConfigMapperInterface; -use Drupal\config_translation\Exception\ConfigMapperLanguageException; +use Drupal\Core\Language\LanguageManagerInterface; use Drupal\config_translation\ConfigMapperManagerInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Routing\Access\AccessInterface; @@ -29,6 +28,13 @@ class ConfigTranslationOverviewAccess implements AccessInterface { */ protected $languageManager; + /** + * The source language. + * + * @var \Drupal\Core\Language\LanguageInterface + */ + protected $sourceLanguage; + /** * Constructs a ConfigTranslationOverviewAccess object. * @@ -48,66 +54,28 @@ class ConfigTranslationOverviewAccess implements AccessInterface { * @param \Drupal\Core\Routing\RouteMatchInterface $route_match * The route_match to check against. * @param \Drupal\Core\Session\AccountInterface $account - * The account to check access for. + * The currently logged in account. * * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ public function access(RouteMatchInterface $route_match, AccountInterface $account) { - $mapper = $this->getMapperFromRouteMatch($route_match); + $route = $route_match->getRouteObject(); - try { - $langcode = $mapper->getLangcode(); - } - catch (ConfigMapperLanguageException $exception) { - // ConfigTranslationController shows a helpful message if the language - // codes do not match, so do not let that prevent granting access. - $langcode = 'en'; - } - $source_language = $this->languageManager->getLanguage($langcode); - - return $this->doCheckAccess($account, $mapper, $source_language); - } - - /** - * Gets a configuration mapper using a route match. - * - * @param \Drupal\Core\Routing\RouteMatchInterface $route_match - * The route match to populate the mapper with. - * - * @return \Drupal\config_translation\ConfigMapperInterface - * The configuration mapper. - */ - protected function getMapperFromRouteMatch(RouteMatchInterface $route_match) { - $mapper = $this->configMapperManager->createInstance($route_match->getRouteObject() - ->getDefault('plugin_id')); + /** @var \Drupal\config_translation\ConfigMapperInterface $mapper */ + $mapper = $this->configMapperManager->createInstance($route->getDefault('plugin_id')); $mapper->populateFromRouteMatch($route_match); - return $mapper; - } + $this->sourceLanguage = $this->languageManager->getLanguage($mapper->getLangcode()); - /** - * Checks access given an account, configuration mapper, and source language. - * - * Grants access if the proper permission is granted to the account, the - * configuration has translatable pieces, and the source language is not - * locked given it is present. - * - * @param \Drupal\Core\Session\AccountInterface $account - * The account to check access for. - * @param \Drupal\config_translation\ConfigMapperInterface $mapper - * The configuration mapper to check access for. - * @param \Drupal\Core\Language\LanguageInterface|null $source_language - * The source language to check for, if any. - * - * @return \Drupal\Core\Access\AccessResultInterface - * The result of the access check. - */ - protected function doCheckAccess(AccountInterface $account, ConfigMapperInterface $mapper, $source_language = NULL) { + // Allow access to the translation overview if the proper permission is + // granted, the configuration has translatable pieces, and the source + // language is not locked if it is present. + $source_language_access = is_null($this->sourceLanguage) || !$this->sourceLanguage->isLocked(); $access = $account->hasPermission('translate configuration') && $mapper->hasSchema() && $mapper->hasTranslatable() && - (!$source_language || !$source_language->isLocked()); + $source_language_access; return AccessResult::allowedIf($access)->cachePerPermissions(); } diff --git a/core/modules/config_translation/src/ConfigMapperInterface.php b/core/modules/config_translation/src/ConfigMapperInterface.php index 57c1ccd27da..be26d4e7a2a 100644 --- a/core/modules/config_translation/src/ConfigMapperInterface.php +++ b/core/modules/config_translation/src/ConfigMapperInterface.php @@ -202,17 +202,6 @@ interface ConfigMapperInterface { */ public function getLangcode(); - /** - * Returns the language code of a configuration object given its name. - * - * @param string $config_name - * The name of the configuration object. - * - * @return string - * The language code of the configuration object. - */ - public function getLangcodeFromConfig($config_name); - /** * Sets the original language code. * diff --git a/core/modules/config_translation/src/ConfigNamesMapper.php b/core/modules/config_translation/src/ConfigNamesMapper.php index bb82fe57871..5b6028a5a9b 100644 --- a/core/modules/config_translation/src/ConfigNamesMapper.php +++ b/core/modules/config_translation/src/ConfigNamesMapper.php @@ -2,7 +2,6 @@ namespace Drupal\config_translation; -use Drupal\config_translation\Exception\ConfigMapperLanguageException; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Config\TypedConfigManagerInterface; use Drupal\Core\Language\LanguageInterface; @@ -381,26 +380,22 @@ class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, Con * {@inheritdoc} */ public function getLangcode() { - $langcodes = array_map([$this, 'getLangcodeFromConfig'], $this->getConfigNames()); + $config_factory = $this->configFactory; + $langcodes = array_map(function($name) use ($config_factory) { + // Default to English if no language code was provided in the file. + // Although it is a best practice to include a language code, if the + // developer did not think about a multilingual use-case, we fall back + // on assuming the file is English. + return $config_factory->get($name)->get('langcode') ?: 'en'; + }, $this->getConfigNames()); if (count(array_unique($langcodes)) > 1) { - throw new ConfigMapperLanguageException('A config mapper can only contain configuration for a single language.'); + throw new \RuntimeException('A config mapper can only contain configuration for a single language.'); } return reset($langcodes); } - /** - * {@inheritdoc} - */ - public function getLangcodeFromConfig($config_name) { - // Default to English if no language code was provided in the file. - // Although it is a best practice to include a language code, if the - // developer did not think about a multilingual use case, we fall back - // on assuming the file is English. - return $this->configFactory->get($config_name)->get('langcode') ?: 'en'; - } - /** * {@inheritdoc} */ diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationController.php b/core/modules/config_translation/src/Controller/ConfigTranslationController.php index 927a1e2bf58..376def040c2 100644 --- a/core/modules/config_translation/src/Controller/ConfigTranslationController.php +++ b/core/modules/config_translation/src/Controller/ConfigTranslationController.php @@ -3,14 +3,11 @@ namespace Drupal\config_translation\Controller; use Drupal\config_translation\ConfigMapperManagerInterface; -use Drupal\config_translation\Exception\ConfigMapperLanguageException; use Drupal\Core\Access\AccessManagerInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Language\Language; -use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; -use Drupal\Core\Render\RendererInterface; use Drupal\Core\Routing\RouteMatch; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; @@ -66,13 +63,6 @@ class ConfigTranslationController extends ControllerBase { */ protected $languageManager; - /** - * The renderer. - * - * @var \Drupal\Core\Render\RendererInterface - */ - protected $renderer; - /** * Constructs a ConfigTranslationController. * @@ -88,17 +78,14 @@ class ConfigTranslationController extends ControllerBase { * The current user. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. - * @param \Drupal\Core\Render\RendererInterface $renderer - * The renderer. */ - public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager, RendererInterface $renderer) { + public function __construct(ConfigMapperManagerInterface $config_mapper_manager, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, AccountInterface $account, LanguageManagerInterface $language_manager) { $this->configMapperManager = $config_mapper_manager; $this->accessManager = $access_manager; $this->router = $router; $this->pathProcessor = $path_processor; $this->account = $account; $this->languageManager = $language_manager; - $this->renderer = $renderer; } /** @@ -111,8 +98,7 @@ class ConfigTranslationController extends ControllerBase { $container->get('router'), $container->get('path_processor_manager'), $container->get('current_user'), - $container->get('language_manager'), - $container->get('renderer') + $container->get('language_manager') ); } @@ -141,33 +127,7 @@ class ConfigTranslationController extends ControllerBase { if (count($languages) == 1) { drupal_set_message($this->t('In order to translate configuration, the website must have at least two languages.', array(':url' => $this->url('entity.configurable_language.collection'))), 'warning'); } - - try { - $original_langcode = $mapper->getLangcode(); - $operations_access = TRUE; - } - catch (ConfigMapperLanguageException $exception) { - $items = []; - foreach ($mapper->getConfigNames() as $config_name) { - $langcode = $mapper->getLangcodeFromConfig($config_name); - $items[] = $this->t('@name: @langcode', [ - '@name' => $config_name, - '@langcode' => $langcode, - ]); - } - $message = [ - 'message' => ['#markup' => $this->t('The configuration objects have different language codes so they cannot be translated:')], - 'items' => [ - '#theme' => 'item_list', - '#items' => $items, - ], - ]; - drupal_set_message($this->renderer->renderPlain($message), 'warning'); - - $original_langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED; - $operations_access = FALSE; - } - + $original_langcode = $mapper->getLangcode(); if (!isset($languages[$original_langcode])) { // If the language is not configured on the site, create a dummy language // object for this listing only to ensure the user gets useful info. @@ -245,9 +205,6 @@ class ConfigTranslationController extends ControllerBase { $page['languages'][$langcode]['operations'] = array( '#type' => 'operations', '#links' => $operations, - // Even if the mapper contains multiple language codes, the source - // configuration can still be edited. - '#access' => ($langcode == $original_langcode) || $operations_access, ); } return $page; diff --git a/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php b/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php deleted file mode 100644 index db4d202436f..00000000000 --- a/core/modules/config_translation/src/Exception/ConfigMapperLanguageException.php +++ /dev/null @@ -1,9 +0,0 @@ -mapper = $mapper; $this->language = $language; - - // ConfigTranslationFormAccess will not grant access if this raises an - // exception, so we can call this without a try-catch block here. - $langcode = $this->mapper->getLangcode(); - - $this->sourceLanguage = $this->languageManager->getLanguage($langcode); + $this->sourceLanguage = $this->languageManager->getLanguage($this->mapper->getLangcode()); // Get base language configuration to display in the form before setting the // language to use for the form. This avoids repetitively settings and diff --git a/core/modules/node/src/Tests/NodeTypeTranslationTest.php b/core/modules/node/src/Tests/NodeTypeTranslationTest.php index 1c3a768cdfa..f86ccc4504f 100644 --- a/core/modules/node/src/Tests/NodeTypeTranslationTest.php +++ b/core/modules/node/src/Tests/NodeTypeTranslationTest.php @@ -23,9 +23,7 @@ class NodeTypeTranslationTest extends WebTestBase { * @var array */ public static $modules = array( - 'block', 'config_translation', - 'field_ui', 'node', ); @@ -55,8 +53,6 @@ class NodeTypeTranslationTest extends WebTestBase { $admin_permissions = array( 'administer content types', - 'administer node fields', - 'administer languages', 'administer site configuration', 'administer themes', 'translate configuration', @@ -148,29 +144,6 @@ class NodeTypeTranslationTest extends WebTestBase { $this->assertText('Edited title'); $this->drupalGet("$langcode/node/add/$type"); $this->assertText('Translated title'); - - // Add an e-mail field. - $this->drupalPostForm("admin/structure/types/manage/$type/fields/add-field", array('new_storage_type' => 'email', 'label' => 'Email', 'field_name' => 'email'), 'Save and continue'); - $this->drupalPostForm(NULL, array(), 'Save field settings'); - $this->drupalPostForm(NULL, array(), 'Save settings'); - - $type = Unicode::strtolower($this->randomMachineName(16)); - $name = $this->randomString(); - $this->drupalCreateContentType(array('type' => $type, 'name' => $name)); - - // Set tabs. - $this->drupalPlaceBlock('local_tasks_block', array('primary' => TRUE)); - - // Change default language. - $this->drupalPostForm('admin/config/regional/language', array('site_default_language' => 'es'), 'Save configuration'); - - // Try re-using the email field. - $this->drupalGet("es/admin/structure/types/manage/$type/fields/add-field"); - $this->drupalPostForm(NULL, array('existing_storage_name' => 'field_email', 'existing_storage_label' => 'Email'), 'Save and continue'); - $this->assertResponse(200); - $this->drupalGet("es/admin/structure/types/manage/$type/fields/node.$type.field_email/translate"); - $this->assertResponse(200); - $this->assertText("The configuration objects have different language codes so they cannot be translated"); } }