Context.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace Drupal\Core\Plugin\Context;
  3. use Drupal\Component\Plugin\Context\Context as ComponentContext;
  4. use Drupal\Component\Plugin\Exception\ContextException;
  5. use Drupal\Core\Cache\CacheableDependencyInterface;
  6. use Drupal\Core\Cache\CacheableMetadata;
  7. use Drupal\Core\TypedData\TypedDataInterface;
  8. use Drupal\Core\TypedData\TypedDataTrait;
  9. /**
  10. * A Drupal specific context wrapper class.
  11. */
  12. class Context extends ComponentContext implements ContextInterface {
  13. use TypedDataTrait;
  14. /**
  15. * The data associated with the context.
  16. *
  17. * @var \Drupal\Core\TypedData\TypedDataInterface
  18. */
  19. protected $contextData;
  20. /**
  21. * The definition to which a context must conform.
  22. *
  23. * @var \Drupal\Core\Plugin\Context\ContextDefinitionInterface
  24. */
  25. protected $contextDefinition;
  26. /**
  27. * The cacheability metadata.
  28. *
  29. * @var \Drupal\Core\Cache\CacheableMetadata
  30. */
  31. protected $cacheabilityMetadata;
  32. /**
  33. * Create a context object.
  34. *
  35. * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition
  36. * The context definition.
  37. * @param mixed|null $context_value
  38. * The context value object.
  39. */
  40. public function __construct(ContextDefinitionInterface $context_definition, $context_value = NULL) {
  41. parent::__construct($context_definition, NULL);
  42. $this->cacheabilityMetadata = new CacheableMetadata();
  43. if (!is_null($context_value)) {
  44. $this->setContextValue($context_value);
  45. }
  46. }
  47. /**
  48. * {@inheritdoc}
  49. */
  50. public function getContextValue() {
  51. if (!isset($this->contextData)) {
  52. $definition = $this->getContextDefinition();
  53. $default_value = $definition->getDefaultValue();
  54. if (isset($default_value)) {
  55. // Keep the default value here so that subsequent calls don't have to
  56. // look it up again.
  57. $this->setContextValue($default_value);
  58. }
  59. elseif ($definition->isRequired()) {
  60. $type = $definition->getDataType();
  61. throw new ContextException("The '$type' context is required and not present.");
  62. }
  63. return $default_value;
  64. }
  65. return $this->getTypedDataManager()->getCanonicalRepresentation($this->contextData);
  66. }
  67. /**
  68. * {@inheritdoc}
  69. */
  70. public function hasContextValue() {
  71. return (bool) $this->contextData || parent::hasContextValue();
  72. }
  73. /**
  74. * Sets the context value.
  75. *
  76. * @param mixed $value
  77. * The value of this context, matching the context definition.
  78. */
  79. protected function setContextValue($value) {
  80. // Add the value as a cacheable dependency only if implements the interface
  81. // to prevent it from disabling caching with a max-age 0.
  82. if ($value instanceof CacheableDependencyInterface) {
  83. $this->addCacheableDependency($value);
  84. }
  85. if ($value instanceof TypedDataInterface) {
  86. $this->contextData = $value;
  87. }
  88. else {
  89. $this->contextData = $this->getTypedDataManager()->create($this->contextDefinition->getDataDefinition(), $value);
  90. }
  91. }
  92. /**
  93. * {@inheritdoc}
  94. */
  95. public function getConstraints() {
  96. return $this->contextDefinition->getConstraints();
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function getContextData() {
  102. if (!isset($this->contextData)) {
  103. $definition = $this->getContextDefinition();
  104. $default_value = $definition->getDefaultValue();
  105. // Store the default value so that subsequent calls don't have to look
  106. // it up again.
  107. $this->contextData = $this->getTypedDataManager()->create($definition->getDataDefinition(), $default_value);
  108. }
  109. return $this->contextData;
  110. }
  111. /**
  112. * {@inheritdoc}
  113. */
  114. public function getContextDefinition() {
  115. return $this->contextDefinition;
  116. }
  117. /**
  118. * {@inheritdoc}
  119. */
  120. public function validate() {
  121. return $this->getContextData()->validate();
  122. }
  123. /**
  124. * {@inheritdoc}
  125. */
  126. public function addCacheableDependency($dependency) {
  127. $this->cacheabilityMetadata = $this->cacheabilityMetadata->merge(CacheableMetadata::createFromObject($dependency));
  128. return $this;
  129. }
  130. /**
  131. * {@inheritdoc}
  132. */
  133. public function getCacheContexts() {
  134. return $this->cacheabilityMetadata->getCacheContexts();
  135. }
  136. /**
  137. * {@inheritdoc}
  138. */
  139. public function getCacheTags() {
  140. return $this->cacheabilityMetadata->getCacheTags();
  141. }
  142. /**
  143. * {@inheritdoc}
  144. */
  145. public function getCacheMaxAge() {
  146. return $this->cacheabilityMetadata->getCacheMaxAge();
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public static function createFromContext(ContextInterface $old_context, $value) {
  152. $context = new static($old_context->getContextDefinition(), $value);
  153. $context->addCacheableDependency($old_context);
  154. if (method_exists($old_context, 'getTypedDataManager')) {
  155. $context->setTypedDataManager($old_context->getTypedDataManager());
  156. }
  157. return $context;
  158. }
  159. }