mustache_templates-8.x-1.0-beta4/src/Plugin/mustache/Magic/Condition.php

src/Plugin/mustache/Magic/Condition.php
<?php

namespace Drupal\mustache\Plugin\mustache\Magic;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\mustache\Plugin\MustacheMagic;

/**
 * Perform simple condition checks within Mustache templates.
 *
 * Usage:
 *
 * You can use the "magical" {{#if.<data>.<condition>}} variable to perform
 * conditions checks on given data. Examples:
 *
 * @code
 * {{#if.node.title.empty}}Title is empty!{{/if.node.title.empty}}
 * {{^if.node.id.numeric}}ID is not numeric...{{/if.node.id.numeric}}
 * {{#if.user.uid.equals.1}}You are the admin.{{/if.user.uid.equals.1}}
 * {{#if.user.uid.greaterthan.1}}You are authenticated.{{/if.user.uid.greaterthan.1}}
 * {{#if.user.uid.lessthan.1}}You are anonymous.{{/if.user.uid.lessthan.1}}
 * {{#if.node.field_mytodolist.atleast.1}}You have work to do.{{/if.node.field_mytodolist.atleast.1}}
 * {{#if.node.field_mylazylist.atmost.0}}No time to be lazy.{{/if.node.field_mylazylist.atmost.1}}
 * @endcode
 *
 * @MustacheMagic(
 *   id = "if",
 *   label = @Translation("Condition"),
 *   description = @Translation("Use the <b>{{#if.&lt;data&gt;.&lt;condition&gt;}}</b> variable to perform condition checks on given data. Examples: <ul><li>{{#if.node.title.empty}}Title is empty!{{/if.node.title.empty}}</li><li>{{^if.node.id.numeric}}ID is not numeric...{{/if.node.id.numeric}}</li><li>{{#if.user.uid.equals.1}}You are the admin.{{/if.user.uid.equals.1}}</li><li>{{#if.user.uid.greaterthan.1}}You are authenticated.{{/if.user.uid.greaterthan.1}}</li><li>{{#if.user.uid.lessthan.1}}You are anonymous.{{/if.user.uid.lessthan.1}}</li><li>{{#if.node.field_mytodolist.atleast.1}}You have work to do.{{/if.node.field_mytodolist.atleast.1}}</li><li>{{#if.node.field_mylazylist.atmost.0}}No time to be lazy.{{/if.node.field_mylazylist.atmost.1}}</li></ul>")
 * )
 */
class Condition extends MustacheMagic {

  /**
   * The condition type.
   *
   * @var string|null
   */
  protected $condition;

  /**
   * The comparison value to evaluate against.
   *
   * @var mixed
   */
  protected $comparisonValue = NULL;

  /**
   * The keys which point to the data value that should be evaluated.
   *
   * @var array
   */
  protected $keys = [];

  /**
   * Whether this object is a clone.
   *
   * @var bool
   */
  protected $cloned = FALSE;

  /**
   * Available condition types.
   *
   * @var array
   */
  protected static $available = [
    'defined' => 0,
    'empty' => 0,
    'numeric' => 0,
    'equals' => 1,
    'greaterthan' => 1,
    'biggerthan' => 1,
    'lessthan' => 1,
    'smallerthan' => 1,
    'atleast' => 1,
    'atmost' => 1,
  ];

  /**
   * The client library for magic conditions.
   *
   * @var string
   */
  public static $library = 'mustache/magic.condition';

  /**
   * Implementation of the magic __isset() method.
   */
  public function __isset($name): bool {
    return !empty($name) || (!is_null($name) && is_scalar($name) && (trim((string) $name) !== ''));
  }

  /**
   * Implementation of the magic __get() method.
   */
  public function __get($name) {
    if (!$this->cloned) {
      // Clone the object, so that multiple usages of {{#if..}} conditions
      // in one template will not interfere with each other.
      $cloned = clone $this;
      $cloned->cloned = TRUE;
      return $cloned->__get($name);
    }
    if (isset($this->condition)) {
      if (static::$available[$this->condition]) {
        if (strtolower(trim($name)) == 'previous') {
          $success = FALSE;
          $scope = $this->switchDataScope($success, array_merge(['previous'], $this->keys));
          if ($success) {
            if (is_scalar($scope)) {
              $this->comparisonValue = $scope;
            }
            elseif (is_object($scope) && method_exists($scope, '__toString')) {
              $this->comparisonValue = (string) $scope;
            }
            elseif (is_array($scope) || is_object($scope) || is_null($scope)) {
              $this->comparisonValue = json_encode($scope);
            }
          }
        }
        else {
          $this->comparisonValue = $name;
        }
      }
      return $this->evaluate();
    }
    elseif (isset(static::$available[$name])) {
      $this->condition = $name;
      if (!static::$available[$this->condition]) {
        return $this->evaluate();
      }
      return $this;
    }
    $this->keys[] = $name;
    return $this;
  }

  /**
   * Evaluates the condition.
   *
   * @return bool
   *   Returns TRUE if condition evaluates to be true, FALSE otherwise.
   */
  protected function evaluate() {
    // Attach the library at the beginning, so that BubbleableMetadata will
    // include that one (and will not forget about it).
    $this->attachLibrary();

    $success = FALSE;
    $scope = $this->switchDataScope($success, $this->keys, $this->withTokens());
    if (!$success || !isset($scope)) {
      return $this->condition === 'empty';
    }
    if (!isset($this->condition)) {
      $this->condition = 'empty';
      return !$this->evaluate();
    }
    if (!isset(static::$available[$this->condition]) || (static::$available[$this->condition] && !isset($this->comparisonValue))) {
      return FALSE;
    }
    switch ($this->condition) {
      case 'defined':
        return TRUE;

      case 'empty':
        return is_countable($scope) ? !count($scope) : empty($scope);

      case 'numeric':
        return is_object($scope) && method_exists($scope, '__toString') ? is_numeric((string) $scope) : is_numeric($scope);

      case 'equals':
        $actual_value = is_scalar($scope) || (is_object($scope) && method_exists($scope, '__toString')) ? (string) $scope : $scope;
        if (is_array($actual_value) || is_object($actual_value) || is_null($actual_value)) {
          $actual_value = json_encode($actual_value);
        }
        return $actual_value === (string) $this->comparisonValue;

      case 'biggerthan':
      case 'greaterthan':
        if (is_object($scope) && method_exists($scope, '__toString')) {
          $string_value = (string) $scope;
        }
        $actual_value = isset($string_value) && is_numeric($string_value) ? $string_value : $scope;
        if (is_countable($actual_value)) {
          if (is_numeric($this->comparisonValue)) {
            return count($actual_value) > $this->comparisonValue;
          }
          if (is_countable($this->comparisonValue)) {
            return count($actual_value) > count($this->comparisonValue);
          }
        }
        $actual_value = is_object($scope) && method_exists($scope, '__toString') ? (string) $scope : $scope;
        if (is_scalar($actual_value)) {
          if (is_numeric($actual_value) && is_numeric($this->comparisonValue)) {
            return $actual_value > $this->comparisonValue;
          }
          return mb_strlen((string) $actual_value) > mb_strlen((string) $this->comparisonValue);
        }
        return FALSE;

      case 'smallerthan':
      case 'lessthan':
        if (is_object($scope) && method_exists($scope, '__toString')) {
          $string_value = (string) $scope;
        }
        $actual_value = isset($string_value) && is_numeric($string_value) ? $string_value : $scope;
        if (is_countable($actual_value)) {
          if (is_numeric($this->comparisonValue)) {
            return count($actual_value) < $this->comparisonValue;
          }
          if (is_countable($this->comparisonValue)) {
            return count($actual_value) < count($this->comparisonValue);
          }
        }
        $actual_value = is_object($scope) && method_exists($scope, '__toString') ? (string) $scope : $scope;
        if (is_scalar($actual_value)) {
          if (is_numeric($actual_value) && is_numeric($this->comparisonValue)) {
            return $actual_value < $this->comparisonValue;
          }
          return mb_strlen((string) $actual_value) < mb_strlen((string) $this->comparisonValue);
        }
        return FALSE;

      case 'atleast':
        if (is_object($scope) && method_exists($scope, '__toString')) {
          $string_value = (string) $scope;
        }
        $actual_value = isset($string_value) && is_numeric($string_value) ? $string_value : $scope;
        if (is_countable($actual_value)) {
          if (is_numeric($this->comparisonValue)) {
            return count($actual_value) >= $this->comparisonValue;
          }
          if (is_countable($this->comparisonValue)) {
            return count($actual_value) >= count($this->comparisonValue);
          }
        }
        $actual_value = is_object($scope) && method_exists($scope, '__toString') ? (string) $scope : $scope;
        if (is_scalar($actual_value)) {
          if (is_numeric($actual_value) && is_numeric($this->comparisonValue)) {
            return $actual_value >= $this->comparisonValue;
          }
          return mb_strlen((string) $actual_value) >= mb_strlen((string) $this->comparisonValue);
        }
        return FALSE;

      case 'atmost':
        if (is_object($scope) && method_exists($scope, '__toString')) {
          $string_value = (string) $scope;
        }
        $actual_value = isset($string_value) && is_numeric($string_value) ? $string_value : $scope;
        if (is_countable($actual_value)) {
          if (is_numeric($this->comparisonValue)) {
            return count($actual_value) <= $this->comparisonValue;
          }
          if (is_countable($this->comparisonValue)) {
            return count($actual_value) <= count($this->comparisonValue);
          }
        }
        $actual_value = is_object($scope) && method_exists($scope, '__toString') ? (string) $scope : $scope;
        if (is_scalar($actual_value)) {
          if (is_numeric($actual_value) && is_numeric($this->comparisonValue)) {
            return $actual_value <= $this->comparisonValue;
          }
          return mb_strlen((string) $actual_value) <= mb_strlen((string) $this->comparisonValue);
        }
        return FALSE;
    }
    return FALSE;
  }

  /**
   * Switches the data scope by using given data keys.
   *
   * @param bool &$success
   *   A flag that indicates whether the switch was completed successfully.
   * @param array $keys
   *   The keys for being used to traverse throughout the data.
   * @param bool $include_tokens
   *   (optional) Whether Token matches should be looked up. Default is FALSE.
   *
   * @return mixed
   *   The switched scope within the data.
   */
  protected function &switchDataScope(&$success, array $keys, $include_tokens = FALSE) {
    $scope = &$this->data;
    foreach ($keys as $i => $key) {
      if ((($scope instanceof \ArrayAccess) || is_array($scope)) && isset($scope[$key])) {
        $scope = &$scope[$key];
        continue;
      }
      if (is_object($scope)) {
        if (method_exists($scope, $key)) {
          $reflection = new \ReflectionMethod($scope, $key);
          if (!$reflection->getNumberOfRequiredParameters()) {
            $scope = &$scope->$key();
            continue;
          }
        }
        if (isset($scope->$key)) {
          $scope = &$scope->$key;
          continue;
        }
      }
      unset($scope);
      if (!$i && $include_tokens) {
        $token_data = isset($this->element['#with_tokens']['data']) ? $this->element['#with_tokens']['data'] : [];
        $token_options = isset($this->element['#with_tokens']['options']) ? $this->element['#with_tokens']['options'] : [];
        $bubbleable_metadata = BubbleableMetadata::createFromRenderArray($this->element);
        if (!$token_data) {
          /** @var \Drupal\mustache\MustacheTokenProcessor $token_processor */
          $token_processor = \Drupal::service('mustache.token_processor');
          $fake_tokens = [];
          NestedArray::setValue($fake_tokens, $keys, '[' . implode(':', $keys) . ']');
          $token_processor->processData($token_data, $fake_tokens, 'view', $bubbleable_metadata);
        }
        $target = static::getTokenIterate()->getIterableTarget($keys, $token_data, $token_options, $bubbleable_metadata);
        $bubbleable_metadata->applyTo($this->element);
        if ($target->exists() && isset($target[$key])) {
          $scope = &$target[$key];
          continue;
        }
      }
      $success = FALSE;
      return $scope;
    }
    $success = TRUE;
    return $scope;
  }

  /**
   * Get the token iterate service.
   *
   * @return \Drupal\mustache\MustacheTokenIterate
   *   The token iterate service.
   */
  protected static function getTokenIterate() {
    return \Drupal::service('mustache.token_iterate');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc