toolshed-8.x-1.x-dev/src/Condition/ConditionEvaluatorTrait.php
src/Condition/ConditionEvaluatorTrait.php
<?php
namespace Drupal\toolshed\Condition;
use Drupal\Component\Plugin\Exception\ContextException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Condition\ConditionManager;
use Drupal\Core\Plugin\Context\ContextHandlerInterface;
use Drupal\Core\Plugin\ContextAwarePluginInterface;
/**
* Trait for common evaluation and handling of a list of condition plugins.
*/
trait ConditionEvaluatorTrait {
/**
* Plugin manager for creation and discovery of condition plugins.
*
* @var \Drupal\Core\Condition\ConditionManager|null
*/
protected ?ConditionManager $conditionManager;
/**
* Static method to fetch the condition plugin manager service.
*
* @return \Drupal\Core\Condition\ConditionManager
* The manager of condition plugins.
*/
protected function getConditionManager(): ConditionManager {
if (!isset($this->conditionManager)) {
$this->conditionManager = \Drupal::service('plugin.manager.condition');
}
return $this->conditionManager;
}
/**
* Get the context handler object.
*
* @return \Drupal\Core\Plugin\Context\ContextHandlerInterface
* Get the Drupal context handler.
*/
protected function getContextHandler(): ContextHandlerInterface {
return \Drupal::service('context.handler');
}
/**
* Build and test a configured set of condition plugins.
*
* @param \Drupal\Core\Plugin\ContextInterface[] $contexts
* The contexts to use when testing conditions. Most condition plugins
* evaluate and often require contexts.
* @param array $conditions
* An array of condition plugin configurations to use to evaluate if
* the conditions will pass.
* @param string $conjunction
* Whether to combine the conditions using 'AND' or 'OR' boolean operaters.
*
* @return bool
* TRUE if the set of conditions passes, FALSE otherwise.
*/
protected function evalConditions(array $contexts = [], array $conditions = [], $conjunction = 'AND'): bool {
if (empty($conditions)) {
return TRUE;
}
$condManager = $this->getConditionManager();
$contextHandler = $this->getContextHandler();
$isAllReq = strtoupper($conjunction) === 'AND';
foreach ($conditions as $def) {
try {
$condition = $condManager->createInstance($def['plugin_id'], $def['configuration']);
if ($condition instanceof ContextAwarePluginInterface) {
$contextHandler->applyContextMapping($condition, $contexts);
}
// Decide if we can shortcircuit the logic.
// For "AND" the first failure results in FALSE.
// For "OR" the first success results in TRUE.
if (($condition->evaluate() xor $condition->isNegated()) xor $isAllReq) {
return !$isAllReq;
}
}
catch (ContextException | PluginNotFoundException $e) {
// A missing condition counts as that condition failing.
if ($isAllReq) {
return FALSE;
}
}
}
// If "AND" then reaching here means none of the conditions have failed,
// and therefore return TRUE. If "OR" then none of the conditions have
// passed at this point (AKA: no SHORTCIRCUIT of logic) return FALSE.
// This just happens to be the same value as $isAllReq.
return $isAllReq;
}
}
