Skip to content
<?php
/**
* @file
* Contains \Drupal\config_translation\Access\ConfigTranslationOverviewAccess.
*/
namespace Drupal\config_translation\Access;
use Drupal\config_translation\ConfigMapperManagerInterface;
use Drupal\Core\Access\StaticAccessCheckInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Checks access for displaying the configuration translation overview.
*/
class ConfigTranslationOverviewAccess implements StaticAccessCheckInterface {
/**
* The mapper plugin discovery service.
*
* @var \Drupal\config_translation\ConfigMapperManagerInterface
*/
protected $configMapperManager;
/**
* The source language.
*
* @var \Drupal\Core\Language\Language
*/
protected $sourceLanguage;
/**
* Constructs a ConfigNameCheck object.
*
* @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
* The mapper plugin discovery service.
*/
public function __construct(ConfigMapperManagerInterface $config_mapper_manager) {
$this->configMapperManager = $config_mapper_manager;
}
/**
* {@inheritdoc}
*/
public function appliesTo() {
return array('_config_translation_overview_access');
}
/**
* {@inheritdoc}
*/
public function access(Route $route, Request $request, AccountInterface $account) {
/** @var \Drupal\config_translation\ConfigMapperInterface $mapper */
$mapper = $this->configMapperManager->createInstance($route->getDefault('plugin_id'));
$mapper->populateFromRequest($request);
$this->sourceLanguage = $mapper->getLanguageWithFallback();
// Allow access to the translation overview if the proper permission is
// granted, the configuration has translatable pieces, and the source
// language is not locked.
$access =
$account->hasPermission('translate configuration') &&
$mapper->hasSchema() &&
$mapper->hasTranslatable() &&
!$this->sourceLanguage->locked;
return $access ? static::ALLOW : static::DENY;
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigEntityMapper.
*/
namespace Drupal\config_translation;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityManager;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\locale\LocaleConfigManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Configuration mapper for configuration entities.
*/
class ConfigEntityMapper extends ConfigNamesMapper {
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManager
*/
protected $entityManager;
/**
* Configuration entity type name.
*
* @var string
*/
protected $entityType;
/**
* Loaded entity instance to help produce the translation interface.
*
* @var \Drupal\Core\Entity\EntityInterface
*/
protected $entity;
/**
* The label for the entity type.
*
* @var string
*/
protected $typeLabel;
/**
* Constructs a ConfigEntityMapper.
*
* @param string $plugin_id
* The config mapper plugin ID.
* @param array $plugin_definition
* An array of plugin information as documented in
* ConfigNamesMapper::__construct() with the following additional keys:
* - entity_type: The name of the entity type this mapper belongs to.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The configuration factory.
* @param \Drupal\locale\LocaleConfigManager $locale_config_manager
* The locale configuration manager.
* @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
* The mapper plugin discovery service.
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
* The string translation manager.
* @param \Drupal\Core\Entity\EntityManager $entity_manager
* The entity manager.
*/
public function __construct($plugin_id, array $plugin_definition, ConfigFactory $config_factory, LocaleConfigManager $locale_config_manager, ConfigMapperManagerInterface $config_mapper_manager, RouteProviderInterface $route_provider, TranslationInterface $translation_manager, EntityManager $entity_manager) {
parent::__construct($plugin_id, $plugin_definition, $config_factory, $locale_config_manager, $config_mapper_manager, $route_provider, $translation_manager);
$this->setType($plugin_definition['entity_type']);
$this->entityManager = $entity_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
// Note that we ignore the plugin $configuration because mappers have
// nothing to configure in themselves.
return new static (
$plugin_id,
$plugin_definition,
$container->get('config.factory'),
$container->get('locale.config.typed'),
$container->get('plugin.manager.config_translation.mapper'),
$container->get('router.route_provider'),
$container->get('string_translation'),
$container->get('entity.manager')
);
}
/**
* {@inheritdoc}
*/
public function populateFromRequest(Request $request) {
parent::populateFromRequest($request);
$entity = $request->attributes->get($this->entityType);
$this->setEntity($entity);
}
/**
* Sets the entity instance for this mapper.
*
* This method can only be invoked when the concrete entity is known, that is
* in a request for an entity translation path. After this method is called,
* the mapper is fully populated with the proper display title and
* configuration names to use to check permissions or display a translation
* screen.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to set.
*
* @return bool
* TRUE, if the entity was set successfully; FALSE otherwise.
*/
public function setEntity(EntityInterface $entity) {
if (isset($this->entity)) {
return FALSE;
}
$this->entity = $entity;
// Add the list of configuration IDs belonging to this entity. We add on a
// possibly existing list of names. This allows modules to alter the entity
// page with more names if form altering added more configuration to an
// entity. This is not a Drupal 8 best practice (ideally the configuration
// would have pluggable components), but this may happen as well.
$entity_type_info = $this->entityManager->getDefinition($this->entityType);
$this->addConfigName($entity_type_info['config_prefix'] . '.' . $entity->id());
return TRUE;
}
/**
* {@inheritdoc}
*/
public function getTitle() {
// Title based on the entity label. Should be translated for display in the
// current page language. The title placeholder is later escaped for
// display.
$entity_type_info = $this->entityManager->getDefinition($this->entityType);
return $this->t($this->pluginDefinition['title'], array('!label' => $this->entity->label(), '!entity_type' => Unicode::strtolower($entity_type_info['label'])));
}
/**
* {@inheritdoc}
*/
public function getBaseRouteParameters() {
return array($this->entityType => $this->entity->id());
}
/**
* Set entity type for this mapper.
*
* This should be set in initialization. A mapper that knows its type but
* not yet its names is still useful for router item and tab generation. The
* concrete entity only turns out later with actual controller invocations,
* when the setEntity() method is invoked before the rest of the methods are
* used.
*
* @param string $entity_type
* The entity type to set.
*
* @return bool
* TRUE if the entity type was set correctly; FALSE otherwise.
*/
public function setType($entity_type) {
if (isset($this->entityType)) {
return FALSE;
}
$this->entityType = $entity_type;
return TRUE;
}
/**
* Gets the entity type from this mapper.
*
* @return string
*/
public function getType() {
return $this->entityType;
}
/**
* {@inheritdoc}
*/
public function getTypeName() {
$entity_type_info = $this->entityManager->getDefinition($this->entityType);
return $entity_type_info['label'];
}
/**
* {@inheritdoc}
*/
public function getTypeLabel() {
$entityType = $this->entityManager->getDefinition($this->entityType);
return $entityType['label'];
}
/**
* {@inheritdoc}
*/
public function getOperations() {
return array(
'list' => array(
'title' => $this->t('List'),
'href' => 'admin/config/regional/config-translation/' . $this->getPluginId(),
),
);
}
/**
* {@inheritdoc}
*/
public function getContextualLinkGroup() {
// @todo Contextual groups do not map to entity types in a predictable
// way. See https://drupal.org/node/2134841 to make them predictable.
switch ($this->entityType) {
case 'menu':
case 'block':
return $this->entityType;
case 'view':
return 'views_ui_edit';
default:
return NULL;
}
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigFieldInstanceMapper.
*/
namespace Drupal\config_translation;
/**
* Configuration mapper for field instances.
*
* On top of plugin definition values on ConfigEntityMapper, the plugin
* definition for field instance mappers are required to contain the following
* additional keys:
* - base_entity_type: The name of the entity type the field instances are
* attached to.
*/
class ConfigFieldInstanceMapper extends ConfigEntityMapper {
/**
* {@inheritdoc}
*/
public function getBaseRouteParameters() {
$parameters = parent::getBaseRouteParameters();
$base_entity_info = $this->entityManager->getDefinition($this->pluginDefinition['base_entity_type']);
// @todo Field instances have no method to return the bundle the instance is
// attached to. See https://drupal.org/node/2134861
$parameters[$base_entity_info['bundle_entity_type']] = $this->entity->bundle;
return $parameters;
}
/**
* {@inheritdoc}
*/
public function getTypeLabel() {
$base_entity_info = $this->entityManager->getDefinition($this->pluginDefinition['base_entity_type']);
return $this->t('@label fields', array('@label' => $base_entity_info['label']));
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigMapperInterface.
*/
namespace Drupal\config_translation;
use Drupal\Core\Language\Language;
use Symfony\Component\HttpFoundation\Request;
/**
* Defines an interface for configuration mapper.
*/
interface ConfigMapperInterface {
/**
* Returns title of this translation page.
*
* @return string
* The page title.
*/
public function getTitle();
/**
* Returns the name of the base route the mapper is attached to.
*
* @return string
* The name of the base route the mapper is attached to.
*/
public function getBaseRouteName();
/**
* Returns the route parameters for the base route the mapper is attached to.
*
* @return array
*/
public function getBaseRouteParameters();
/**
* Returns the base route object the mapper is attached to.
*
* @return \Symfony\Component\Routing\Route
* The base route object the mapper is attached to.
*/
public function getBaseRoute();
/**
* Returns a processed path for the base route the mapper is attached to.
*
* @return string
* Processed path with placeholders replaced.
*/
public function getBasePath();
/**
* Returns route name for the translation overview route.
*
* @return string
* Route name for the mapper.
*/
public function getOverviewRouteName();
/**
* Returns the route parameters for the translation overview route.
*
* @return array
*/
public function getOverviewRouteParameters();
/**
* Returns the route object for a translation overview route.
*
* @return \Symfony\Component\Routing\Route
* The route object for the translation page.
*/
public function getOverviewRoute();
/**
* Returns a processed path for the translation overview route.
*
* @return string
* Processed path with placeholders replaced.
*/
public function getOverviewPath();
/**
* Returns route name for the translation add form route.
*
* @return string
* Route name for the mapper.
*/
public function getAddRouteName();
/**
* Returns the route parameters for the translation add form route.
*
* @return array
*/
public function getAddRouteParameters();
/**
* Returns the route object for a translation add form route.
*
* @return \Symfony\Component\Routing\Route
* The route object for the translation page.
*/
public function getAddRoute();
/**
* Returns route name for the translation edit form route.
*
* @return string
* Route name for the mapper.
*/
public function getEditRouteName();
/**
* Returns the route parameters for the translation edit form route.
*
* @return array
*/
public function getEditRouteParameters();
/**
* Returns the route object for a translation edit form route.
*
* @return \Symfony\Component\Routing\Route
* The route object for the translation page.
*/
public function getEditRoute();
/**
* Returns route name for the translation deletion route.
*
* @return string
* Route name for the mapper.
*/
public function getDeleteRouteName();
/**
* Returns the route parameters for the translation deletion route.
*
* @return array
*/
public function getDeleteRouteParameters();
/**
* Returns the route object for the translation deletion route.
*
* @return \Symfony\Component\Routing\Route
* The route object for the translation page.
*/
public function getDeleteRoute();
/**
* Returns an array of configuration names for the mapper.
*
* @return array
* An array of configuration names for the mapper.
*/
public function getConfigNames();
/**
* Adds the given configuration name to the list of names.
*
* @param string $name
* Configuration name.
*/
public function addConfigName($name);
/**
* Returns the weight of the mapper.
*
* @return int
* The weight of the mapper.
*/
public function getWeight();
/**
* Returns an array with all configuration data.
*
* @return array
* Configuration data keyed by configuration names.
*/
public function getConfigData();
/**
* Returns the original language code of the configuration.
*
* @throws \RuntimeException
* Throws an exception if the language codes in the config files don't
* match.
*/
public function getLangcode();
/**
* Returns language object for the configuration.
*
* If the language of the configuration files is not a configured language on
* the site and it is English, we return a dummy language object to represent
* the built-in language.
*
* @return \Drupal\Core\Language\Language
* A configured language object instance or a dummy English language object.
*
* @throws \RuntimeException
* Throws an exception if the language codes in the config files don't
* match.
*/
public function getLanguageWithFallback();
/**
* Returns the name of the type of data the mapper encapsulates.
*
* @return string
* The name of the type of data the mapper encapsulates.
*/
public function getTypeName();
/**
* Provides an array of information to build a list of operation links.
*
* @return array
* An associative array of operation link data for this list, keyed by
* operation name, containing the following key-value pairs:
* - title: The localized title of the operation.
* - href: The path for the operation.
* - options: An array of URL options for the path.
* - weight: The weight of this operation.
*/
public function getOperations();
/**
* Returns the label of the type of data the mapper encapsulates.
*
* @return string
* The label of the type of data the mapper encapsulates.
*/
public function getTypeLabel();
/**
* Checks that all pieces of this configuration mapper have a schema.
*
* @return bool
* TRUE if all of the elements have schema, FALSE otherwise.
*/
public function hasSchema();
/**
* Checks that all pieces of this configuration mapper have translatables.
*
* @return bool
* TRUE if all of the configuration elements have translatables, FALSE
* otherwise.
*/
public function hasTranslatable();
/**
* Checks whether there is already a translation for this mapper.
*
* @param \Drupal\Core\Language\Language $language
* A language object.
*
* @return bool
* TRUE if any of the configuration elements have a translation in the
* given language, FALSE otherwise.
*/
public function hasTranslation(Language $language);
/**
* Populate the config mapper with request data.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* Page request object.
*/
public function populateFromRequest(Request $request);
/**
* Returns the name of the contextual link group to add contextual links to.
*
* @return string|null
* A contextual link group name or null if no link should be added.
*/
public function getContextualLinkGroup();
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigMapperManager.
*/
namespace Drupal\config_translation;
use Drupal\Component\Utility\String;
use Drupal\config_translation\Exception\InvalidMapperDefinitionException;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\Schema\ArrayElement;
use Drupal\Core\Config\TypedConfigManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageManager;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\Core\Plugin\Discovery\InfoHookDecorator;
use Drupal\Core\Plugin\Discovery\YamlDiscovery;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
use Drupal\Core\Plugin\Factory\ContainerFactory;
use Drupal\Core\TypedData\TypedDataInterface;
/**
* Manages plugins for configuration translation mappers.
*/
class ConfigMapperManager extends DefaultPluginManager implements ConfigMapperManagerInterface {
/**
* The typed config manager.
*
* @var \Drupal\Core\Config\TypedConfigManager
*/
protected $typedConfigManager;
/**
* {@inheritdoc}
*/
protected $defaults = array(
'title' => '',
'names' => array(),
'weight' => 20,
'class' => '\Drupal\config_translation\ConfigNamesMapper',
'list_controller' => 'Drupal\config_translation\Controller\ConfigTranslationEntityListController',
);
/**
* Constructs a ConfigMapperManager.
*
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
* The cache backend.
* @param \Drupal\Core\Language\LanguageManager $language_manager
* The language manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Config\TypedConfigManager $typed_config_manager
* The typed config manager.
*/
public function __construct(CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler, TypedConfigManager $typed_config_manager) {
$this->typedConfigManager = $typed_config_manager;
// Look at all themes and modules.
$directories = array();
foreach ($module_handler->getModuleList() as $module => $filename) {
$directories[$module] = dirname($filename);
}
foreach ($this->getThemeList() as $theme) {
$directories[$theme->name] = drupal_get_path('theme', $theme->name);
}
// Check for files named MODULE.config_translation.yml and
// THEME.config_translation.yml in module/theme roots.
$this->discovery = new YamlDiscovery('config_translation', $directories);
$this->discovery = new InfoHookDecorator($this->discovery, 'config_translation_info');
$this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
$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_plugins');
}
/**
* Returns the list of themes on the site.
*
* @param bool $refresh
* Whether to refresh the cached theme list.
*
* @return array
* An associative array of the currently available themes. The keys are the
* themes' machine names and the values are objects. See list_themes() for
* documentation on those objects.
*
* @todo Remove this once https://drupal.org/node/2109287 is fixed in core.
*/
protected function getThemeList($refresh = FALSE) {
return list_themes($refresh);
}
/**
* {@inheritdoc}
*/
public function getMappers() {
$mappers = array();
foreach($this->getDefinitions() as $id => $definition) {
$mappers[$id] = $this->createInstance($id);
}
return $mappers;
}
/**
* {@inheritdoc}
*/
public function processDefinition(&$definition, $plugin_id) {
parent::processDefinition($definition, $plugin_id);
if (!isset($definition['base_route_name'])) {
throw new InvalidMapperDefinitionException($plugin_id, String::format("The plugin definition of the mapper '%plugin_id' does not contain a base_route_name.", array('%plugin_id' => $plugin_id)));
}
if (!is_subclass_of($definition['list_controller'], 'Drupal\config_translation\Controller\ConfigTranslationEntityListControllerInterface')) {
throw new InvalidMapperDefinitionException($plugin_id, String::format("The list_controller '%list_controller' for plugin '%plugin_id' does not implement the expected interface Drupal\config_translation\Controller\ConfigTranslationEntityListControllerInterface.", array('%list_controller' => $definition['list_controller'], '%plugin_id' => $plugin_id)));
}
}
/**
* {@inheritdoc}
*/
public function hasTranslatable($name) {
return $this->findTranslatable($this->typedConfigManager->get($name));
}
/**
* Returns TRUE if at least one translatable element is found.
*
* @param \Drupal\Core\TypedData\TypedDataInterface $element
* Configuration schema element.
*
* @return bool
* A boolean indicating if there is at least one translatable element.
*/
protected function findTranslatable(TypedDataInterface $element) {
// In case this is a sequence or a mapping check whether any child element
// is translatable.
if ($element instanceof ArrayElement) {
foreach ($element as $child_element) {
if ($this->findTranslatable($child_element)) {
return TRUE;
}
}
// If none of the child elements are translatable, return FALSE.
return FALSE;
}
else {
$definition = $element->getDefinition();
return isset($definition['translatable']) && $definition['translatable'];
}
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigMapperManagerInterface.
*/
namespace Drupal\config_translation;
use Drupal\Component\Plugin\PluginManagerInterface;
/**
* Provides a common interface for config mapper managers.
*/
interface ConfigMapperManagerInterface extends PluginManagerInterface {
/**
* Returns an array of all mappers.
*
* @return \Drupal\config_translation\ConfigMapperInterface[]
* An array of all mappers.
*/
public function getMappers();
/**
* Returns TRUE if the configuration data has translatable items.
*
* @param string $name
* Configuration key.
*
* @return bool
* A boolean indicating if the configuration data has translatable items.
*/
public function hasTranslatable($name);
}
<?php
/**
* @file
* Contains \Drupal\config_translation\ConfigNamesMapper.
*/
namespace Drupal\config_translation;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Language\Language;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\locale\LocaleConfigManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Configuration mapper base implementation.
*/
class ConfigNamesMapper extends PluginBase implements ConfigMapperInterface, ContainerFactoryPluginInterface {
/**
* The configuration factory.
*
* @var \Drupal\Core\Config\ConfigFactory
*/
protected $configFactory;
/**
* The typed configuration manager.
*
* @var \Drupal\locale\LocaleConfigManager
*/
protected $localeConfigManager;
/**
* The mapper plugin discovery service.
*
* @var \Drupal\config_translation\ConfigMapperManagerInterface
*/
protected $configMapperManager;
/**
* The base route object that the mapper is attached to.
*
* @return \Symfony\Component\Routing\Route
*/
protected $baseRoute;
/**
* The language code of the language this mapper, if any.
*
* @var string|null
*/
protected $langcode = NULL;
/**
* Constructs a ConfigNamesMapper.
*
* @param $plugin_id
* The config mapper plugin ID.
* @param array $plugin_definition
* An array of plugin information with the following keys:
* - title: The title of the mapper, used for generating page titles.
* - base_route_name: The route name of the base route this mapper is
* attached to.
* - names: (optional) An array of configuration names.
* - weight: (optional) The weight of this mapper, used in mapper listings.
* Defaults to 20.
* - list_controller: (optional) Class name for list controller used to
* generate lists of this type of configuration.
* @param \Drupal\Core\Config\ConfigFactory $config_factory
* The configuration factory.
* @param \Drupal\locale\LocaleConfigManager $locale_config_manager
* The locale configuration manager.
* @param \Drupal\config_translation\ConfigMapperManagerInterface $config_mapper_manager
* The mapper plugin discovery service.
* @param \Drupal\Core\Routing\RouteProviderInterface
* The route provider.
* @param \Drupal\Core\StringTranslation\TranslationInterface $translation_manager
* The string translation manager.
*
* @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, array $plugin_definition, ConfigFactory $config_factory, LocaleConfigManager $locale_config_manager, ConfigMapperManagerInterface $config_mapper_manager, RouteProviderInterface $route_provider, TranslationInterface $translation_manager) {
$this->pluginId = $plugin_id;
$this->pluginDefinition = $plugin_definition;
$this->configFactory = $config_factory;
$this->localeConfigManager = $locale_config_manager;
$this->configMapperManager = $config_mapper_manager;
$this->setTranslationManager($translation_manager);
$this->baseRoute = $route_provider->getRouteByName($this->getBaseRouteName());
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
// Note that we ignore the plugin $configuration because mappers have
// nothing to configure in themselves.
return new static (
$plugin_id,
$plugin_definition,
$container->get('config.factory'),
$container->get('locale.config.typed'),
$container->get('plugin.manager.config_translation.mapper'),
$container->get('router.route_provider'),
$container->get('string_translation')
);
}
/**
* {@inheritdoc}
*/
public function getTitle() {
// A title from a *.config_translation.yml. Should be translated for
// display in the current page language.
return $this->t($this->pluginDefinition['title']);
}
/**
* {@inheritdoc}
*/
public function getBaseRouteName() {
return $this->pluginDefinition['base_route_name'];
}
/**
* {@inheritdoc}
*/
public function getBaseRouteParameters() {
return array();
}
/**
* {@inheritdoc}
*/
public function getBaseRoute() {
return $this->baseRoute;
}
/**
* {@inheritdoc}
*/
public function getBasePath() {
return $this->getPathFromRoute($this->getBaseRoute(), $this->getBaseRouteParameters());
}
/**
* {@inheritdoc}
*/
public function getOverviewRouteName() {
return 'config_translation.item.overview.' . $this->getBaseRouteName();
}
/**
* {@inheritdoc}
*/
public function getOverviewRouteParameters() {
return $this->getBaseRouteParameters();
}
/**
* {@inheritdoc}
*/
public function getOverviewRoute() {
return new Route(
$this->getBaseRoute()->getPath() . '/translate',
array(
'_controller' => '\Drupal\config_translation\Controller\ConfigTranslationController::itemPage',
'plugin_id' => $this->getPluginId(),
),
array('_config_translation_overview_access' => 'TRUE')
);
}
/**
* {@inheritdoc}
*/
public function getOverviewPath() {
return $this->getPathFromRoute($this->getOverviewRoute(), $this->getOverviewRouteParameters());
}
/**
* {@inheritdoc}
*/
public function getAddRouteName() {
return 'config_translation.item.add.' . $this->getBaseRouteName();
}
/**
* {@inheritdoc}
*/
public function getAddRouteParameters() {
// If sub-classes provide route parameters in getBaseRouteParameters(), they
// probably also want to provide those for the add, edit, and delete forms.
$parameters = $this->getBaseRouteParameters();
$parameters['langcode'] = $this->langcode;
return $parameters;
}
/**
* {@inheritdoc}
*/
public function getAddRoute() {
return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/add',
array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationAddForm',
'plugin_id' => $this->getPluginId(),
),
array('_config_translation_form_access' => 'TRUE')
);
}
/**
* {@inheritdoc}
*/
public function getEditRouteName() {
return 'config_translation.item.edit.' . $this->getBaseRouteName();
}
/**
* {@inheritdoc}
*/
public function getEditRouteParameters() {
return $this->getAddRouteParameters();
}
/**
* {@inheritdoc}
*/
public function getEditRoute() {
return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/edit',
array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationEditForm',
'plugin_id' => $this->getPluginId(),
),
array('_config_translation_form_access' => 'TRUE')
);
}
/**
* {@inheritdoc}
*/
public function getDeleteRouteName() {
return 'config_translation.item.delete.' . $this->getBaseRouteName();
}
/**
* {@inheritdoc}
*/
public function getDeleteRouteParameters() {
return $this->getAddRouteParameters();
}
/**
* {@inheritdoc}
*/
public function getDeleteRoute() {
return new Route(
$this->getBaseRoute()->getPath() . '/translate/{langcode}/delete',
array(
'_form' => '\Drupal\config_translation\Form\ConfigTranslationDeleteForm',
'plugin_id' => $this->getPluginId(),
),
array('_config_translation_form_access' => 'TRUE')
);
}
/**
* Gets the path for a certain route, given a set of route parameters.
*
* @param \Symfony\Component\Routing\Route $route
* The route object.
* @param array $parameters
* An array of route parameters.
*
* @return string
* Processed path with placeholders replaced.
*/
public function getPathFromRoute(Route $route, array $parameters) {
$path = $route->getPath();
foreach ($parameters as $key => $value) {
$path = str_replace('{' . $key . '}', $value, $path);
}
return $path;
}
/**
* {@inheritdoc}
*/
public function getConfigNames() {
return $this->pluginDefinition['names'];
}
/**
* {@inheritdoc}
*/
public function addConfigName($name) {
$this->pluginDefinition['names'][] = $name;
}
/**
* {@inheritdoc}
*/
public function getWeight() {
return $this->pluginDefinition['weight'];
}
/**
* {@inheritdoc}
*/
public function populateFromRequest(Request $request) {
if ($request->attributes->has('langcode')) {
$this->langcode = $request->attributes->get('langcode');
}
else {
$this->langcode = NULL;
}
}
/**
* {@inheritdoc}
*/
public function getTypeLabel() {
return $this->getTitle();
}
/**
* {@inheritdoc}
*/
public function getLangcode() {
$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 \RuntimeException('A config mapper can only contain configuration for a single language.');
}
return reset($langcodes);
}
/**
* {@inheritdoc}
*/
public function getLanguageWithFallback() {
$langcode = $this->getLangcode();
$language = language_load($langcode);
// If the language of the file is English but English is not a configured
// language on the site, create a mock language object to represent this
// language run-time. In this case, the title of the language is
// 'Built-in English' because we assume such configuration is shipped with
// core and the modules and not custom created. (In the later case an
// English language configured on the site is assumed.)
if (empty($language) && $langcode == 'en') {
$language = new Language(array('id' => 'en', 'name' => $this->t('Built-in English')));
}
return $language;
}
/**
* {@inheritdoc}
*/
public function getConfigData() {
$config_data = array();
foreach ($this->getConfigNames() as $name) {
$config_data[$name] = $this->configFactory->get($name)->get();
}
return $config_data;
}
/**
* {@inheritdoc}
*/
public function hasSchema() {
foreach ($this->getConfigNames() as $name) {
if (!$this->localeConfigManager->hasConfigSchema($name)) {
return FALSE;
}
}
return TRUE;
}
/**
* {@inheritdoc}
*/
public function hasTranslatable() {
foreach ($this->getConfigNames() as $name) {
if (!$this->configMapperManager->hasTranslatable($name)) {
return FALSE;
}
}
return TRUE;
}
/**
* {@inheritdoc}
*/
public function hasTranslation(Language $language) {
foreach ($this->getConfigNames() as $name) {
if ($this->localeConfigManager->hasTranslation($name, $language)) {
return TRUE;
}
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function getTypeName() {
return $this->t('Settings');
}
/**
* {@inheritdoc}
*/
public function getOperations() {
return array(
'translate' => array(
'title' => $this->t('Translate'),
'href' => $this->getOverviewPath(),
),
);
}
/**
* {@inheritdoc}
*/
public function getContextualLinkGroup() {
return NULL;
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\Controller\ConfigTranslationBlockListController.
*/
namespace Drupal\config_translation\Controller;
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
/**
* Defines the config translation controller for blocks.
*/
class ConfigTranslationBlockListController extends ConfigTranslationEntityListController {
/**
* An array of theme info keyed by theme name.
*
* @var array
*/
protected $themes = array();
/**
* {@inheritdoc}
*/
public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler) {
parent::__construct($entity_type, $entity_info, $storage, $module_handler);
$this->themes = list_themes();
}
/**
* {@inheritdoc}
*/
public function getFilterLabels() {
$info = parent::getFilterLabels();
$info['placeholder'] = $this->t('Enter block, theme or category');
$info['description'] = $this->t('Enter a part of the block, theme or category to filter by.');
return $info;
}
/**
* {@inheritdoc}
*/
public function buildRow(EntityInterface $entity) {
$theme = $entity->get('theme');
$plugin_definition = $entity->getPlugin()->getPluginDefinition();
$row['label'] = array(
'data' => $this->getLabel($entity),
'class' => 'table-filter-text-source',
);
$row['theme'] = array(
'data' => String::checkPlain($this->themes[$theme]->info['name']),
'class' => 'table-filter-text-source',
);
$row['category'] = array(
'data' => String::checkPlain($plugin_definition['category']),
'class' => 'table-filter-text-source',
);
$row['operations']['data'] = $this->buildOperations($entity);
return $row;
}
/**
* {@inheritdoc}
*/
public function buildHeader() {
$header['label'] = $this->t('Block');
$header['theme'] = $this->t('Theme');
$header['category'] = $this->t('Category');
$header['operations'] = $this->t('Operations');
return $header;
}
/**
* {@inheritdoc}
*/
public function sortRows($a, $b) {
return $this->sortRowsMultiple($a, $b, array('theme', 'category', 'label'));
}
}
<?php
/**
* @file
* Contains \Drupal\config_translation\Controller\ConfigTranslationEntityListControllerInterface.
*/
namespace Drupal\config_translation\Controller;
use Drupal\Core\Entity\EntityListControllerInterface;
/**
* Defines an interface for configuration translation entity list controllers.
*/
interface ConfigTranslationEntityListControllerInterface extends EntityListControllerInterface {
/**
* Sorts an array by value.
*
* @param array $a
* First item for comparison.
* @param array $b
* Second item for comparison.
*
* @return int
* The comparison result for uasort().
*/
public function sortRows($a, $b);
}