Commit 7bbcc3ee authored by catch's avatar catch

Revert "Issue #2595535 by tstoeckler, swentel, vijaycs85, alvar0hurtad0,

esolitos: Show helpful message (do not fatal!) when configuration files
have different source language codes and cannot be translated"uthor:
Nathaniel

This reverts commit ef3700fa.
parent ef3700fa
......@@ -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 @@
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);
}
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));
// 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));
}
return $base_access;
}
}
......@@ -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 @@ public function __construct(ConfigMapperManagerInterface $config_mapper_manager,
* @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);
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);
$route = $route_match->getRouteObject();
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();
}
......
......@@ -202,17 +202,6 @@ public function getConfigData();
*/
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.
*
......
......@@ -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 @@ public function getTypeLabel() {
* {@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}
*/
......
......@@ -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 @@ public static function create(ContainerInterface $container) {
$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 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
if (count($languages) == 1) {
drupal_set_message($this->t('In order to translate configuration, the website must have at least two <a href=":url">languages</a>.', 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 @@ public function itemPage(Request $request, RouteMatchInterface $route_match, $pl
$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;
......
<?php
namespace Drupal\config_translation\Exception;
/**
* Provides an exception for configuration mappers with multiple languages.
*/
class ConfigMapperLanguageException extends \RuntimeException {
}
......@@ -138,12 +138,7 @@ public function buildForm(array $form, FormStateInterface $form_state, RouteMatc
$this->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
......
......@@ -23,9 +23,7 @@ class NodeTypeTranslationTest extends WebTestBase {
* @var array
*/
public static $modules = array(
'block',
'config_translation',
'field_ui',
'node',
);
......@@ -55,8 +53,6 @@ protected function setUp() {
$admin_permissions = array(
'administer content types',
'administer node fields',
'administer languages',
'administer site configuration',
'administer themes',
'translate configuration',
......@@ -148,29 +144,6 @@ public function testNodeTypeTitleLabelTranslation() {
$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");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment