You are here

ContextManager.php in Context 8

Same filename and directory in other branches
  1. 8.4 src/ContextManager.php
  2. 8.0 src/ContextManager.php

Namespace

Drupal\context

File

src/ContextManager.php
View source
<?php

namespace Drupal\context;

use Drupal\context\Entity\Context;
use Drupal\context\Plugin\ContextReaction\Blocks;
use Drupal\Core\Entity\Query\QueryFactory;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityFormBuilderInterface;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
use Drupal\Core\Condition\ConditionPluginCollection;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Core\Condition\ConditionAccessResolverTrait;
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Theme\ThemeManagerInterface;

/**
 * This is the manager service for the context module and should not be
 * confused with the built in contexts in Drupal.
 */
class ContextManager {
  use ConditionAccessResolverTrait;
  use StringTranslationTrait;

  /**
   * @var \Drupal\Core\Entity\Query\QueryFactory
   */
  protected $entityQuery;

  /**
   * @var \Drupal\Core\Entity\EntityManagerInterface
   */
  protected $entityManager;

  /**
   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
   */
  protected $contextRepository;

  /**
   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
   */
  protected $contextHandler;

  /**
   * If the context conditions has been evaluated then this is set to TRUE
   * otherwise FALSE.
   *
   * @var bool
   */
  protected $contextConditionsEvaluated = FALSE;

  /**
   * An array of contexts that have been evaluated and are active.
   *
   * @var array
   */
  protected $activeContexts = [];

  /**
   * @var \Drupal\Core\Entity\EntityFormBuilderInterface
   */
  private $entityFormBuilder;

  /**
   * @var \Drupal\Core\Theme\ThemeManagerInterface;
   */
  protected $themeManager;

  /**
   * Construct.
   *
   * @param QueryFactory $entityQuery
   *   The Drupal entity query service.
   *
   * @param EntityManagerInterface $entityManager
   *   The Drupal entity manager service.
   *
   * @param ContextRepositoryInterface $contextRepository
   *   The drupal context repository service.
   *
   * @param ContextHandlerInterface $contextHandler
   *   The Drupal context handler service.
   *
   * @param ThemeManagerInterface $themeManager
   *   The Drupal theme manager service.
   *
   * @param \Drupal\Core\Entity\EntityFormBuilderInterface $entityFormBuilder
   */
  function __construct(QueryFactory $entityQuery, EntityManagerInterface $entityManager, ContextRepositoryInterface $contextRepository, ContextHandlerInterface $contextHandler, EntityFormBuilderInterface $entityFormBuilder, ThemeManagerInterface $themeManager) {
    $this->entityQuery = $entityQuery;
    $this->entityManager = $entityManager;
    $this->contextRepository = $contextRepository;
    $this->contextHandler = $contextHandler;
    $this->entityFormBuilder = $entityFormBuilder;
    $this->themeManager = $themeManager;
  }

  /**
   * Get all contexts.
   *
   * @return Context[]
   */
  public function getContexts() {
    $contextIds = $this->entityQuery
      ->get('context')
      ->execute();
    $contexts = $this->entityManager
      ->getStorage('context')
      ->loadMultiple($contextIds);

    // Sort the contexts by their weight.
    uasort($contexts, [
      $this,
      'sortContextsByWeight',
    ]);
    return $contexts;
  }

  /**
   * Get all contexts sorted by their group and sorted by their weight inside
   * of each group.
   *
   * @return array
   */
  public function getContextsByGroup() {
    $contexts = $this
      ->getContexts();
    $groups = [];

    // Add each context to their respective groups.
    foreach ($contexts as $context_id => $context) {
      $group = $context
        ->getGroup();
      if ($group === Context::CONTEXT_GROUP_NONE) {
        $group = 'not_grouped';
      }
      $groups[$group][$context_id] = $context;
    }
    return $groups;
  }

  /**
   * Check to validate that the context name does not already exist.
   *
   * @param string $name
   *   The machine name of the context to validate.
   *
   * @return bool
   */
  public function contextExists($name) {
    $entity = $this->entityQuery
      ->get('context')
      ->condition('name', $name)
      ->execute();
    return (bool) $entity;
  }

  /**
   * Check to see if context conditions has been evaluated.
   *
   * @return bool
   */
  public function conditionsHasBeenEvaluated() {
    return $this->contextConditionsEvaluated;
  }

  /**
   * Get the evaluated and active contexts.
   *
   * @return \Drupal\context\ContextInterface[]
   */
  public function getActiveContexts() {
    if ($this
      ->conditionsHasBeenEvaluated()) {
      return $this->activeContexts;
    }
    $this
      ->evaluateContexts();
    return $this->activeContexts;
  }

  /**
   * Evaluate all context conditions.
   */
  public function evaluateContexts() {

    /** @var \Drupal\context\ContextInterface $context */
    foreach ($this
      ->getContexts() as $context) {
      if ($this
        ->evaluateContextConditions($context) && !$context
        ->disabled()) {
        $this->activeContexts[] = $context;
      }
    }
    $this->contextConditionsEvaluated = TRUE;
  }

  /**
   * Get all active reactions or reactions of a certain type.
   *
   * @param string $reactionType
   *   Either the reaction class name or the id of the reaction type to get.
   *
   * @return ContextReactionInterface[]
   */
  public function getActiveReactions($reactionType = NULL) {
    $reactions = [];
    foreach ($this
      ->getActiveContexts() as $context) {

      // If no reaction type has been specified then add all reactions and
      // continue to the next context.
      if (is_null($reactionType)) {
        foreach ($context
          ->getReactions() as $reaction) {

          // Only return block reaction if there is a block applied to the current theme.
          if ($reaction instanceof Blocks) {
            $blocks = $reaction
              ->getBlocks();
            $current_theme = $this
              ->getCurrentTheme();
            foreach ($blocks as $block) {
              if ($block
                ->getConfiguration()['theme'] == $current_theme) {
                $reactions[] = $reaction;
                break;
              }
            }
          }
          else {
            $reactions[] = $reaction;
          }
        }
        continue;
      }
      $contextReactions = $context
        ->getReactions();

      // Filter the reactions based on the reaction type.
      foreach ($contextReactions as $reaction) {
        if (class_exists($reactionType) && $reaction instanceof $reactionType) {
          $reactions[] = $reaction;
          continue;
        }
        if ($reaction
          ->getPluginId() === $reactionType) {
          $reactions[] = $reaction;
          continue;
        }
      }
    }
    return $reactions;
  }

  /**
   * Evaluate a contexts conditions.
   *
   * @param ContextInterface $context
   *   The context to evaluate conditions for.
   *
   * @return bool
   */
  public function evaluateContextConditions(ContextInterface $context) {
    $conditions = $context
      ->getConditions();

    // Apply context to any context aware conditions.
    $this
      ->applyContexts($conditions);

    // Set the logic to use when validating the conditions.
    $logic = $context
      ->requiresAllConditions() ? 'and' : 'or';

    // Of there are no conditions then the context will be
    // applied as a site wide context.
    if (!count($conditions)) {
      $logic = 'and';
    }
    return $this
      ->resolveConditions($conditions, $logic);
  }

  /**
   * Apply context to all the context aware conditions in the collection.
   *
   * @param ConditionPluginCollection $conditions
   *   A collection of conditions to apply context to.
   *
   * @return bool
   */
  protected function applyContexts(ConditionPluginCollection &$conditions) {
    foreach ($conditions as $condition) {
      if ($condition instanceof ContextAwarePluginInterface) {
        try {
          $contexts = $this->contextRepository
            ->getRuntimeContexts(array_values($condition
            ->getContextMapping()));
          $this->contextHandler
            ->applyContextMapping($condition, $contexts);
        } catch (ContextException $e) {
          return FALSE;
        }
      }
    }
    return TRUE;
  }

  /**
   * Get a rendered form for the context.
   * @param \Drupal\context\ContextInterface $context
   * @param string $formType
   * @param array $form_state_additions
   * @return array
   */
  public function getForm(ContextInterface $context, $formType = 'edit', array $form_state_additions = array()) {
    return $this->entityFormBuilder
      ->getForm($context, $formType, $form_state_additions);
  }

  /**
   * Sorts an array of context entities by their weight.
   *
   * Callback for uasort().
   *
   * @param ContextInterface $a
   *   First item for comparison.
   *
   * @param ContextInterface $b
   *   Second item for comparison.
   *
   * @return int
   *   The comparison result for uasort().
   */
  public function sortContextsByWeight(ContextInterface $a, ContextInterface $b) {
    if ($a
      ->getWeight() == $b
      ->getWeight()) {
      return 0;
    }
    return $a
      ->getWeight() < $b
      ->getWeight() ? -1 : 1;
  }

  /**
   * Get current active theme.
   *
   * @return string
   *   Current active theme name.
   */
  private function getCurrentTheme() {
    return $this->themeManager
      ->getActiveTheme()
      ->getName();
  }

}

Classes

Namesort descending Description
ContextManager This is the manager service for the context module and should not be confused with the built in contexts in Drupal.