Commit 6874a1eb authored by mxh's avatar mxh
Browse files

Issue #3256537 by mxh: Provide a generic "entity" context for current, parent and root Tokens

parent d020ab1b
Loading
Loading
Loading
Loading
+19 −4
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
 */

use Drupal\context_stack\ContextStackRepository;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\BubbleableMetadata;

/**
@@ -67,17 +68,18 @@ function context_stack_tokens($type, $tokens, array $data, array $options, Bubbl
        // Cannot proceeed without further parts.
        continue;
      }
      if ($purpose === 'account' && reset($parts) !== 'user') {
      if ($purpose === 'account' && !in_array(reset($parts), ['user', 'entity'])) {
        $chained_token_type = $entity_type_id = 'user';
      }
      else {
        $chained_token_type = $entity_type_id = array_shift($parts);
        _context_stack_map_token_type($chained_token_type, $entity_type_id);
      }
      if (!is_string($entity_type_id) || !is_string($chained_token_type) || empty($parts)) {
      if (!is_string($chained_token_type) || empty($parts)) {
        continue;
      }
      $context_id = '@' . $service_ids[$type] . ':' . $purpose . '.' . $entity_type_id;
      $id = is_string($entity_type_id) ? $entity_type_id : $chained_token_type;
      $context_id = '@' . $service_ids[$type] . ':' . $purpose . '.' . $id;
      /** @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository */
      $context_repository = \Drupal::service('context.repository');
      $contexts = $context_repository->getRuntimeContexts([$context_id]);
@@ -91,9 +93,22 @@ function context_stack_tokens($type, $tokens, array $data, array $options, Bubbl
        }
        continue;
      }

      $value = $context->getContextValue();
      if (!is_string($entity_type_id)) {
        // Last chance to get the correct token type.
        if ($value instanceof EntityInterface) {
          $chained_token_type = $entity_type_id = $value->getEntityTypeId();
        }
        else {
          $type_parts = explode(':', $context->getContextData()->getDataDefinition()->getDataType());
          $chained_token_type = end($type_parts);
        }
        _context_stack_map_token_type($chained_token_type, $entity_type_id);
      }
      $bubbleable_metadata->addCacheableDependency($context);
      $chained_token = implode(':', $parts);
      $replacements += \Drupal::token()->generate($chained_token_type, [$chained_token => $original], [$chained_token_type => $context->getContextValue()], $options, $bubbleable_metadata);
      $replacements += \Drupal::token()->generate($chained_token_type, [$chained_token => $original], [$chained_token_type => $value], $options, $bubbleable_metadata);
    }
  }

+11 −0
Original line number Diff line number Diff line
@@ -24,4 +24,15 @@ class CurrentContent extends CurrentContentBase {
    return $context_stack->validate(GenericEntityContext::fromEntityType($entity_type), FALSE) ? $context : NULL;
  }

  /**
   * {@inheritdoc}
   */
  protected function getGenericRuntimeContext(ContextStackInterface $context_stack): ?CurrentEntityContext {
    $context = CurrentEntityContext::fromNothing($this->t('@name entity in "@purpose" scope', [
      '@name' => $this->t("Current"),
      '@purpose' => $this->t($context_stack->getPurpose()),
    ]), $context_stack, 'entity');
    return $context_stack->validate(GenericEntityContext::fromNothing(), FALSE) ? $context : NULL;
  }

}
+25 −9
Original line number Diff line number Diff line
@@ -51,26 +51,31 @@ abstract class CurrentContentBase implements ContextProviderInterface {
        }
        $purpose = $context_stack->getPurpose();
        $by_stack[$purpose] = $entity_type_ids;
        $by_stack[$purpose][] = 'entity';
      }
    }
    else {
      foreach ($unqualified_context_ids as $context_id) {
        list($purpose, $entity_type_id) = explode('.', $context_id, 2);
        list($purpose, $key) = explode('.', $context_id, 2);
        if (!($context_stack = $this->getContextStack($purpose))) {
          continue;
        }
        $by_stack[$purpose][] = $entity_type_id;
        $by_stack[$purpose][] = $key;
      }
    }
    foreach ($by_stack as $purpose => $entity_type_ids) {
    foreach ($by_stack as $purpose => $keys) {
      $context_stack = $this->getContextStack($purpose);
      foreach ($entity_type_ids as $entity_type_id) {
        if (!($entity_type = $this->entityTypeManager->getDefinition($entity_type_id, FALSE))) {
          continue;
      foreach ($keys as $key) {
        if ($key === 'entity') {
          if ($context = $this->getGenericRuntimeContext($context_stack)) {
            $result[$purpose . '.' . $key] = $context;
          }
        }
        elseif ($entity_type = $this->entityTypeManager->getDefinition($key, FALSE)) {
          if ($entity_type->entityClassImplements(ContentEntityInterface::class)) {
            if ($context = $this->getRuntimeContext($entity_type, $context_stack)) {
            $result[$purpose . '.' . $entity_type_id] = $context;
              $result[$purpose . '.' . $key] = $context;
            }
          }
        }
      }
@@ -91,6 +96,17 @@ abstract class CurrentContentBase implements ContextProviderInterface {
   */
  abstract protected function getRuntimeContext(EntityTypeInterface $entity_type, ContextStackInterface $context_stack): ?CurrentEntityContext;

  /**
   * Get the runtime context for a generic entity.
   *
   * @param \Drupal\context_stack\ContextStackInterface $context_stack
   *   The context stack to define the context for.
   *
   * @return \Drupal\context_stack\Plugin\Context\CurrentEntityContext|null
   *   An instance of CurrentEntityContext, or NULL if no context is defined.
   */
  abstract protected function getGenericRuntimeContext(ContextStackInterface $context_stack): ?CurrentEntityContext;

  /**
   * {@inheritdoc}
   */
+11 −0
Original line number Diff line number Diff line
@@ -25,4 +25,15 @@ class CurrentParentContent extends CurrentContentBase {
    return $context_stack->validate(GenericEntityContext::fromEntityType($entity_type), FALSE) ? $context : NULL;
  }

  /**
   * {@inheritdoc}
   */
  protected function getGenericRuntimeContext(ContextStackInterface $context_stack): ?CurrentEntityContext {
    $context = CurrentParentEntityContext::fromNothing($this->t('@name entity in "@purpose" scope', [
      '@name' => $this->t("Parent"),
      '@purpose' => $this->t($context_stack->getPurpose()),
    ]), $context_stack, 'entity');
    return $context_stack->validate(GenericEntityContext::fromNothing(), FALSE) ? $context : NULL;
  }

}
+11 −0
Original line number Diff line number Diff line
@@ -25,4 +25,15 @@ class CurrentRootContent extends CurrentContentBase {
    return $context_stack->validate(GenericEntityContext::fromEntityType($entity_type), FALSE) ? $context : NULL;
  }

  /**
   * {@inheritdoc}
   */
  protected function getGenericRuntimeContext(ContextStackInterface $context_stack): ?CurrentEntityContext {
    $context = CurrentRootEntityContext::fromNothing($this->t('@name entity in "@purpose" scope', [
      '@name' => $this->t("Root"),
      '@purpose' => $this->t($context_stack->getPurpose()),
    ]), $context_stack, 'entity');
    return $context_stack->validate(GenericEntityContext::fromNothing(), FALSE) ? $context : NULL;
  }

}
Loading