Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542
This commit is contained in:
parent
3b2511d96d
commit
81ccda77eb
2155 changed files with 54307 additions and 46870 deletions
|
@ -14,7 +14,7 @@ use Drupal\Component\Plugin\PluginManagerInterface;
|
|||
/**
|
||||
* Defines a class which is capable of clearing the cache on plugin managers.
|
||||
*/
|
||||
class CachedDiscoveryClearer {
|
||||
class CachedDiscoveryClearer implements CachedDiscoveryClearerInterface {
|
||||
|
||||
/**
|
||||
* The stored discoveries.
|
||||
|
@ -24,18 +24,14 @@ class CachedDiscoveryClearer {
|
|||
protected $cachedDiscoveries = array();
|
||||
|
||||
/**
|
||||
* Adds a plugin manager to the active list.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $cached_discovery
|
||||
* An object that implements the cached discovery interface, typically a
|
||||
* plugin manager.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCachedDiscovery(CachedDiscoveryInterface $cached_discovery) {
|
||||
$this->cachedDiscoveries[] = $cached_discovery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cache on all cached discoveries.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearCachedDefinitions() {
|
||||
foreach ($this->cachedDiscoveries as $cached_discovery) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Plugin\CachedDiscoveryClearerInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
|
||||
|
||||
/**
|
||||
* Provides a way to clear static caches of all plugin managers.
|
||||
*/
|
||||
interface CachedDiscoveryClearerInterface {
|
||||
|
||||
/**
|
||||
* Adds a plugin manager to the active list.
|
||||
*
|
||||
* @param \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $cached_discovery
|
||||
* An object that implements the cached discovery interface, typically a
|
||||
* plugin manager.
|
||||
*/
|
||||
public function addCachedDiscovery(CachedDiscoveryInterface $cached_discovery);
|
||||
|
||||
/**
|
||||
* Clears the cache on all cached discoveries.
|
||||
*/
|
||||
public function clearCachedDefinitions();
|
||||
|
||||
}
|
|
@ -9,7 +9,8 @@ namespace Drupal\Core\Plugin\Context;
|
|||
|
||||
use Drupal\Component\Plugin\Context\Context as ComponentContext;
|
||||
use Drupal\Component\Plugin\Exception\ContextException;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\TypedDataTrait;
|
||||
|
||||
|
@ -34,6 +35,21 @@ class Context extends ComponentContext implements ContextInterface {
|
|||
*/
|
||||
protected $contextDefinition;
|
||||
|
||||
/**
|
||||
* The cacheability metadata.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheableMetadata
|
||||
*/
|
||||
protected $cacheabilityMetadata;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(ContextDefinitionInterface $context_definition) {
|
||||
parent::__construct($context_definition);
|
||||
$this->cacheabilityMetadata = new CacheableMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -49,17 +65,29 @@ class Context extends ComponentContext implements ContextInterface {
|
|||
}
|
||||
elseif ($definition->isRequired()) {
|
||||
$type = $definition->getDataType();
|
||||
throw new ContextException(SafeMarkup::format("The @type context is required and not present.", array('@type' => $type)));
|
||||
throw new ContextException("The '$type' context is required and not present.");
|
||||
}
|
||||
return $default_value;
|
||||
}
|
||||
return $this->getTypedDataManager()->getCanonicalRepresentation($this->contextData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasContextValue() {
|
||||
return (bool) $this->contextData || parent::hasContextValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setContextValue($value) {
|
||||
// Add the value as a cacheable dependency only if implements the interface
|
||||
// to prevent it from disabling caching with a max-age 0.
|
||||
if ($value instanceof CacheableDependencyInterface) {
|
||||
$this->addCacheableDependency($value);
|
||||
}
|
||||
if ($value instanceof TypedDataInterface) {
|
||||
return $this->setContextData($value);
|
||||
}
|
||||
|
@ -113,4 +141,33 @@ class Context extends ComponentContext implements ContextInterface {
|
|||
return $this->getContextData()->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addCacheableDependency($dependency) {
|
||||
$this->cacheabilityMetadata = $this->cacheabilityMetadata->merge(CacheableMetadata::createFromObject($dependency));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return $this->cacheabilityMetadata->getCacheContexts();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return $this->cacheabilityMetadata->getCacheTags();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return $this->cacheabilityMetadata->getCacheMaxAge();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\TypedData\TypedDataTrait;
|
||||
|
||||
/**
|
||||
|
@ -245,7 +244,7 @@ class ContextDefinition implements ContextDefinitionInterface {
|
|||
}
|
||||
|
||||
if (!$definition) {
|
||||
throw new \Exception(SafeMarkup::format('The data type "@type" is invalid', array('@type' => $this->getDataType())));
|
||||
throw new \Exception("The data type '{$this->getDataType()}' is invalid");
|
||||
}
|
||||
$definition->setLabel($this->getLabel())
|
||||
->setDescription($this->getDescription())
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\ContextException;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
|
||||
/**
|
||||
|
@ -74,19 +74,51 @@ class ContextHandler implements ContextHandlerInterface {
|
|||
public function applyContextMapping(ContextAwarePluginInterface $plugin, $contexts, $mappings = array()) {
|
||||
$mappings += $plugin->getContextMapping();
|
||||
// Loop through each of the expected contexts.
|
||||
foreach (array_keys($plugin->getContextDefinitions()) as $plugin_context_id) {
|
||||
|
||||
$missing_value = [];
|
||||
|
||||
foreach ($plugin->getContextDefinitions() as $plugin_context_id => $plugin_context_definition) {
|
||||
// If this context was given a specific name, use that.
|
||||
$context_id = isset($mappings[$plugin_context_id]) ? $mappings[$plugin_context_id] : $plugin_context_id;
|
||||
if (!empty($contexts[$context_id])) {
|
||||
// This assignment has been used, remove it.
|
||||
unset($mappings[$plugin_context_id]);
|
||||
$plugin->setContextValue($plugin_context_id, $contexts[$context_id]->getContextValue());
|
||||
|
||||
// Plugins have their on context objects, only the value is applied.
|
||||
// They also need to know about the cacheability metadata of where that
|
||||
// value is coming from, so pass them through to those objects.
|
||||
$plugin_context = $plugin->getContext($plugin_context_id);
|
||||
if ($plugin_context instanceof ContextInterface && $contexts[$context_id] instanceof CacheableDependencyInterface) {
|
||||
$plugin_context->addCacheableDependency($contexts[$context_id]);
|
||||
}
|
||||
|
||||
// Pass the value to the plugin if there is one.
|
||||
if ($contexts[$context_id]->hasContextValue()) {
|
||||
$plugin->setContextValue($plugin_context_id, $contexts[$context_id]->getContextValue());
|
||||
}
|
||||
elseif ($plugin_context_definition->isRequired()) {
|
||||
// Collect required contexts that exist but are missing a value.
|
||||
$missing_value[] = $plugin_context_id;
|
||||
}
|
||||
}
|
||||
elseif ($plugin_context_definition->isRequired()) {
|
||||
// Collect required contexts that are missing.
|
||||
$missing_value[] = $plugin_context_id;
|
||||
}
|
||||
else {
|
||||
// Ignore mappings for optional missing context.
|
||||
unset($mappings[$plugin_context_id]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any required contexts without a value, throw an exception.
|
||||
if ($missing_value) {
|
||||
throw new ContextException(sprintf('Required contexts without a value: %s.', implode(', ', $missing_value)));
|
||||
}
|
||||
|
||||
// If there are any mappings that were not satisfied, throw an exception.
|
||||
if (!empty($mappings)) {
|
||||
throw new ContextException(SafeMarkup::format('Assigned contexts were not satisfied: @mappings', ['@mappings' => implode(',', array_keys($mappings))]));
|
||||
throw new ContextException('Assigned contexts were not satisfied: ' . implode(',', array_keys($mappings)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
use Drupal\Component\Plugin\Context\ContextInterface as ComponentContextInterface;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
|
||||
/**
|
||||
* Interface for context.
|
||||
*/
|
||||
interface ContextInterface extends ComponentContextInterface {
|
||||
interface ContextInterface extends ComponentContextInterface, CacheableDependencyInterface {
|
||||
|
||||
/**
|
||||
* Gets the context value as typed data object.
|
||||
|
@ -32,4 +33,22 @@ interface ContextInterface extends ComponentContextInterface {
|
|||
*/
|
||||
public function setContextData(TypedDataInterface $data);
|
||||
|
||||
/**
|
||||
* Adds a dependency on an object: merges its cacheability metadata.
|
||||
*
|
||||
* E.g. when a context depends on some configuration, an entity, or an access
|
||||
* result, we must make sure their cacheability metadata is present on the
|
||||
* response. This method makes doing that simple.
|
||||
*
|
||||
* @param \Drupal\Core\Cache\CacheableDependencyInterface|mixed $dependency
|
||||
* The dependency. If the object implements CacheableDependencyInterface,
|
||||
* then its cacheability metadata will be used. Otherwise, the passed in
|
||||
* object must be assumed to be uncacheable, so max-age 0 is set.
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @see \Drupal\Core\Cache\CacheableMetadata::createFromObject()
|
||||
*/
|
||||
public function addCacheableDependency($dependency);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Plugin\Context\ContextProviderInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
/**
|
||||
* Defines an interface for providing plugin contexts.
|
||||
*
|
||||
* Implementations only need to deal with unqualified context IDs so they only
|
||||
* need to be unique in the context of a given service provider.
|
||||
*
|
||||
* The fully qualified context ID then includes the service ID:
|
||||
* @{service_id}:{unqualified_context_id}.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\Context\ContextRepositoryInterface
|
||||
*/
|
||||
interface ContextProviderInterface {
|
||||
|
||||
/**
|
||||
* Gets runtime context values for the given context IDs.
|
||||
*
|
||||
* For context-aware plugins to function correctly, all of the contexts that
|
||||
* they require must be populated with values. So this method should set a
|
||||
* value for each context that it adds. For example:
|
||||
*
|
||||
* @code
|
||||
* // Determine a specific node to pass as context to a block.
|
||||
* $node = ...
|
||||
*
|
||||
* // Set that specific node as the value of the 'node' context.
|
||||
* $context = new Context(new ContextDefinition('entity:node'));
|
||||
* $context->setContextValue($node);
|
||||
* return ['node' => $context];
|
||||
* @endcode
|
||||
*
|
||||
* On the other hand, there are cases, on which providers no longer are
|
||||
* possible to provide context objects, even without the value, so the caller
|
||||
* should not expect it.
|
||||
*
|
||||
* @param string[] $unqualified_context_ids
|
||||
* The requested context IDs. The context provider must only return contexts
|
||||
* for those IDs.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
* The determined available contexts, keyed by the unqualified context_id.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\Context\ContextProviderInterface:getAvailableContexts()
|
||||
*/
|
||||
public function getRuntimeContexts(array $unqualified_context_ids);
|
||||
|
||||
/**
|
||||
* Gets all available contexts for the purposes of configuration.
|
||||
*
|
||||
* When a context aware plugin is being configured, the configuration UI must
|
||||
* know which named contexts are potentially available, but does not care
|
||||
* about the value, since the value can be different for each request, and
|
||||
* might not be available at all during the configuration UI's request.
|
||||
*
|
||||
* For example:
|
||||
* @code
|
||||
* // During configuration, there is no specific node to pass as context.
|
||||
* // However, inform the system that a context named 'node' is
|
||||
* // available, and provide its definition, so that context aware plugins
|
||||
* // can be configured to use it. When the plugin, for example a block,
|
||||
* // needs to evaluate the context, the value of this context will be
|
||||
* // supplied by getRuntimeContexts().
|
||||
* $context = new Context(new ContextDefinition('entity:node'));
|
||||
* return ['node' => $context];
|
||||
* @endcode
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
* All available contexts keyed by the unqualified context ID.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\Context\ContextProviderInterface::getRuntimeContext()
|
||||
*/
|
||||
public function getAvailableContexts();
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Plugin\Context\ContextRepositoryInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
/**
|
||||
* Offers a global context repository.
|
||||
*
|
||||
* Provides a list of all available contexts, which is mostly useful for
|
||||
* configuration on forms, as well as a method to get the concrete contexts with
|
||||
* their values, given a list of fully qualified context IDs.
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\Context\ContextProviderInterface
|
||||
*/
|
||||
interface ContextRepositoryInterface {
|
||||
|
||||
/**
|
||||
* Gets runtime context values for the given context IDs.
|
||||
*
|
||||
* Given that context providers might not return contexts for the given
|
||||
* context IDs, it is also not guaranteed that the context repository returns
|
||||
* contexts for all specified IDs.
|
||||
*
|
||||
* @param string[] $context_ids
|
||||
* Fully qualified context IDs, which looks like
|
||||
* @{service_id}:{unqualified_context_id}, so for example
|
||||
* node.node_route_context:node.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
* The determined contexts, keyed by the fully qualified context ID.
|
||||
*/
|
||||
public function getRuntimeContexts(array $context_ids);
|
||||
|
||||
/**
|
||||
* Gets all available contexts for the purposes of configuration.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
* All available contexts.
|
||||
*/
|
||||
public function getAvailableContexts();
|
||||
|
||||
}
|
112
core/lib/Drupal/Core/Plugin/Context/LazyContextRepository.php
Normal file
112
core/lib/Drupal/Core/Plugin/Context/LazyContextRepository.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Plugin\Context\LazyContextRepository.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Plugin\Context;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a context repository which uses context provider services.
|
||||
*/
|
||||
class LazyContextRepository implements ContextRepositoryInterface {
|
||||
|
||||
/**
|
||||
* The set of available context providers service IDs.
|
||||
*
|
||||
* @var string[]
|
||||
* Context provider service IDs.
|
||||
*/
|
||||
protected $contextProviderServiceIDs = [];
|
||||
|
||||
/**
|
||||
* The service container.
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* The statically cached contexts.
|
||||
*
|
||||
* @var \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
protected $contexts = [];
|
||||
|
||||
/**
|
||||
* Constructs a LazyContextRepository object.
|
||||
*
|
||||
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
|
||||
* The current service container.
|
||||
* @param string[] $context_provider_service_ids
|
||||
* The set of the available context provider service IDs.
|
||||
*/
|
||||
public function __construct(ContainerInterface $container, array $context_provider_service_ids) {
|
||||
$this->container = $container;
|
||||
$this->contextProviderServiceIDs = $context_provider_service_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRuntimeContexts(array $context_ids) {
|
||||
$contexts = [];
|
||||
|
||||
// Create a map of context providers (service IDs) to unqualified context
|
||||
// IDs.
|
||||
$context_ids_by_service = [];
|
||||
foreach ($context_ids as $id) {
|
||||
if (isset($this->contexts[$id])) {
|
||||
$contexts[$id] = $this->contexts[$id];
|
||||
continue;
|
||||
}
|
||||
// The IDs have been passed in @{service_id}:{unqualified_context_id}
|
||||
// format.
|
||||
// @todo Convert to an assert once https://www.drupal.org/node/2408013 is
|
||||
// in.
|
||||
if ($id[0] === '@' && strpos($id, ':') !== FALSE) {
|
||||
list($service_id, $unqualified_context_id) = explode(':', $id, 2);
|
||||
// Remove the leading '@'.
|
||||
$service_id = substr($service_id, 1);
|
||||
}
|
||||
else {
|
||||
throw new \InvalidArgumentException('You must provide the context IDs in the @{service_id}:{unqualified_context_id} format.');
|
||||
}
|
||||
$context_ids_by_service[$service_id][] = $unqualified_context_id;
|
||||
}
|
||||
|
||||
// Iterate over all missing context providers (services), gather the
|
||||
// runtime contexts and assign them as requested.
|
||||
foreach ($context_ids_by_service as $service_id => $unqualified_context_ids) {
|
||||
$contexts_by_service = $this->container->get($service_id)->getRuntimeContexts($unqualified_context_ids);
|
||||
|
||||
$wanted_contexts = array_intersect_key($contexts_by_service, array_flip($unqualified_context_ids));
|
||||
foreach ($wanted_contexts as $unqualified_context_id => $context) {
|
||||
$context_id = '@' . $service_id . ':' . $unqualified_context_id;
|
||||
$this->contexts[$context_id] = $contexts[$context_id] = $context;
|
||||
}
|
||||
}
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAvailableContexts() {
|
||||
$contexts = [];
|
||||
foreach ($this->contextProviderServiceIDs as $service_id) {
|
||||
$contexts_by_service = $this->container->get($service_id)->getAvailableContexts();
|
||||
foreach ($contexts_by_service as $unqualified_context_id => $context) {
|
||||
$context_id = '@' . $service_id . ':' . $unqualified_context_id;
|
||||
$contexts[$context_id] = $context;
|
||||
}
|
||||
}
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,8 @@ namespace Drupal\Core\Plugin;
|
|||
use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
||||
use Drupal\Component\Plugin\ContextAwarePluginBase as ComponentContextAwarePluginBase;
|
||||
use Drupal\Component\Plugin\Exception\ContextException;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
@ -91,4 +93,53 @@ abstract class ContextAwarePluginBase extends ComponentContextAwarePluginBase im
|
|||
return \Drupal::service('context.handler');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
$cache_contexts = [];
|
||||
// Applied contexts can affect the cache contexts when this plugin is
|
||||
// involved in caching, collect and return them.
|
||||
foreach ($this->getContexts() as $context) {
|
||||
/** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */
|
||||
if ($context instanceof CacheableDependencyInterface) {
|
||||
$cache_contexts = Cache::mergeContexts($cache_contexts, $context->getCacheContexts());
|
||||
}
|
||||
}
|
||||
return $cache_contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
$tags = [];
|
||||
// Applied contexts can affect the cache tags when this plugin is
|
||||
// involved in caching, collect and return them.
|
||||
foreach ($this->getContexts() as $context) {
|
||||
/** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */
|
||||
if ($context instanceof CacheableDependencyInterface) {
|
||||
$tags = Cache::mergeTags($tags, $context->getCacheTags());
|
||||
}
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
$max_age = Cache::PERMANENT;
|
||||
|
||||
// Applied contexts can affect the cache max age when this plugin is
|
||||
// involved in caching, collect and return them.
|
||||
foreach ($this->getContexts() as $context) {
|
||||
/** @var $context \Drupal\Core\Cache\CacheableDependencyInterface */
|
||||
if ($context instanceof CacheableDependencyInterface) {
|
||||
$max_age = Cache::mergeMaxAges($max_age, $context->getCacheMaxAge());
|
||||
}
|
||||
}
|
||||
return $max_age;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -336,7 +336,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
|
|||
/**
|
||||
* Determines if the provider of a definition exists.
|
||||
*
|
||||
* @return boolean
|
||||
* @return bool
|
||||
* TRUE if provider exists, FALSE otherwise.
|
||||
*/
|
||||
protected function providerExists($provider) {
|
||||
|
|
|
@ -10,9 +10,18 @@ namespace Drupal\Core\Plugin\Discovery;
|
|||
use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
|
||||
use Drupal\Component\Discovery\YamlDiscovery as ComponentYamlDiscovery;
|
||||
use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
|
||||
/**
|
||||
* Allows YAML files to define plugin definitions.
|
||||
*
|
||||
* If the value of a key (like title) in the definition is translatable then
|
||||
* the addTranslatableProperty() method can be used to mark it as such and also
|
||||
* to add translation context. Then
|
||||
* \Drupal\Core\StringTranslation\TranslationWrapper will be used to translate
|
||||
* the string and also to mark it safe. Only strings written in the YAML files
|
||||
* should be marked as safe, strings coming from dynamic plugin definitions
|
||||
* potentially containing user input should not.
|
||||
*/
|
||||
class YamlDiscovery implements DiscoveryInterface {
|
||||
|
||||
|
@ -25,6 +34,15 @@ class YamlDiscovery implements DiscoveryInterface {
|
|||
*/
|
||||
protected $discovery;
|
||||
|
||||
/**
|
||||
* Contains an array of translatable properties passed along to t().
|
||||
*
|
||||
* @see \Drupal\Core\Plugin\Discovery\YamlDiscovery::addTranslatableProperty()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $translatableProperties = [];
|
||||
|
||||
/**
|
||||
* Construct a YamlDiscovery object.
|
||||
*
|
||||
|
@ -38,6 +56,23 @@ class YamlDiscovery implements DiscoveryInterface {
|
|||
$this->discovery = new ComponentYamlDiscovery($name, $directories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one of the YAML values as being translatable.
|
||||
*
|
||||
* @param string $value_key
|
||||
* The key corresponding to the value in the YAML that contains a
|
||||
* translatable string.
|
||||
* @param string $context_key
|
||||
* (Optional) the translation context for the value specified by the
|
||||
* $value_key.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTranslatableProperty($value_key, $context_key = '') {
|
||||
$this->translatableProperties[$value_key] = $context_key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -48,6 +83,20 @@ class YamlDiscovery implements DiscoveryInterface {
|
|||
$definitions = array();
|
||||
foreach ($plugins as $provider => $list) {
|
||||
foreach ($list as $id => $definition) {
|
||||
// Add translation wrappers.
|
||||
foreach ($this->translatableProperties as $property => $context_key) {
|
||||
if (isset($definition[$property])) {
|
||||
$options = [];
|
||||
// Move the t() context from the definition to the translation
|
||||
// wrapper.
|
||||
if ($context_key && isset($definition[$context_key])) {
|
||||
$options['context'] = $definition[$context_key];
|
||||
unset($definition[$context_key]);
|
||||
}
|
||||
$definition[$property] = new TranslationWrapper($definition[$property], [], $options);
|
||||
}
|
||||
}
|
||||
// Add ID and provider.
|
||||
$definitions[$id] = $definition + array(
|
||||
'provider' => $provider,
|
||||
'id' => $id,
|
||||
|
|
|
@ -10,18 +10,7 @@ namespace Drupal\Core\Plugin;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for a plugin that contains a form.
|
||||
*
|
||||
* Plugin forms are usually contained in other forms. In order to know where the
|
||||
* plugin form is located in the parent form, #parents and #array_parents must
|
||||
* be known, but these are not available during the initial build phase. In
|
||||
* order to have these properties available when building the plugin form's
|
||||
* elements, let buildConfigurationForm() return a form element that has a
|
||||
* #process callback and build the rest of the form in the callback. By the time
|
||||
* the callback is executed, the element's #parents and #array_parents
|
||||
* properties will have been set by the form API. For more documentation on
|
||||
* #parents and #array_parents, see
|
||||
* https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/8.
|
||||
* Provides an interface for an embeddable plugin form.
|
||||
*
|
||||
* @ingroup plugin_api
|
||||
*/
|
||||
|
@ -30,10 +19,21 @@ interface PluginFormInterface {
|
|||
/**
|
||||
* Form constructor.
|
||||
*
|
||||
* Plugin forms are embedded in other forms. In order to know where the plugin
|
||||
* form is located in the parent form, #parents and #array_parents must be
|
||||
* known, but these are not available during the initial build phase. In order
|
||||
* to have these properties available when building the plugin form's
|
||||
* elements, let this method return a form element that has a #process
|
||||
* callback and build the rest of the form in the callback. By the time the
|
||||
* callback is executed, the element's #parents and #array_parents properties
|
||||
* will have been set by the form API. For more documentation on #parents and
|
||||
* #array_parents, see
|
||||
* https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/8.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* An associative array containing the initial structure of the plugin form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* The current state of the complete form.
|
||||
*
|
||||
* @return array
|
||||
* The form structure.
|
||||
|
@ -44,9 +44,10 @@ interface PluginFormInterface {
|
|||
* Form validation handler.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* An associative array containing the structure of the plugin form as built
|
||||
* by static::buildConfigurationForm().
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* The current state of the complete form.
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state);
|
||||
|
||||
|
@ -54,9 +55,10 @@ interface PluginFormInterface {
|
|||
* Form submission handler.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* An associative array containing the structure of the plugin form as built
|
||||
* by static::buildConfigurationForm().
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* The current state of the complete form.
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state);
|
||||
|
||||
|
|
Reference in a new issue