You are here

class ClosureExpressionVisitor in Plug 7

Walks an expression graph and turns it into a PHP closure.

This closure can be used with {@Collection#filter()} and is used internally by {@ArrayCollection#select()}.

@author Benjamin Eberlei <kontakt@beberlei.de> @since 2.3

Hierarchy

Expanded class hierarchy of ClosureExpressionVisitor

2 files declare their use of ClosureExpressionVisitor
ArrayCollection.php in lib/doctrine/collections/lib/Doctrine/Common/Collections/ArrayCollection.php
ClosureExpressionVisitorTest.php in lib/doctrine/collections/tests/Doctrine/Tests/Common/Collections/ClosureExpressionVisitorTest.php

File

lib/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php, line 31

Namespace

Doctrine\Common\Collections\Expr
View source
class ClosureExpressionVisitor extends ExpressionVisitor {

  /**
   * Accesses the field of a given object. This field has to be public
   * directly or indirectly (through an accessor get*, is*, or a magic
   * method, __get, __call).
   *
   * @param object $object
   * @param string $field
   *
   * @return mixed
   */
  public static function getObjectFieldValue($object, $field) {
    if (is_array($object)) {
      return $object[$field];
    }
    $accessors = array(
      'get',
      'is',
    );
    foreach ($accessors as $accessor) {
      $accessor .= $field;
      if (!method_exists($object, $accessor)) {
        continue;
      }
      return $object
        ->{$accessor}();
    }

    // __call should be triggered for get.
    $accessor = $accessors[0] . $field;
    if (method_exists($object, '__call')) {
      return $object
        ->{$accessor}();
    }
    if ($object instanceof \ArrayAccess) {
      return $object[$field];
    }
    return $object->{$field};
  }

  /**
   * Helper for sorting arrays of objects based on multiple fields + orientations.
   *
   * @param string   $name
   * @param int      $orientation
   * @param \Closure $next
   *
   * @return \Closure
   */
  public static function sortByField($name, $orientation = 1, \Closure $next = null) {
    if (!$next) {
      $next = function () {
        return 0;
      };
    }
    return function ($a, $b) use ($name, $next, $orientation) {
      $aValue = ClosureExpressionVisitor::getObjectFieldValue($a, $name);
      $bValue = ClosureExpressionVisitor::getObjectFieldValue($b, $name);
      if ($aValue === $bValue) {
        return $next($a, $b);
      }
      return ($aValue > $bValue ? 1 : -1) * $orientation;
    };
  }

  /**
   * {@inheritDoc}
   */
  public function walkComparison(Comparison $comparison) {
    $field = $comparison
      ->getField();
    $value = $comparison
      ->getValue()
      ->getValue();

    // shortcut for walkValue()
    switch ($comparison
      ->getOperator()) {
      case Comparison::EQ:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
        };
      case Comparison::NEQ:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
        };
      case Comparison::LT:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
        };
      case Comparison::LTE:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
        };
      case Comparison::GT:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
        };
      case Comparison::GTE:
        return function ($object) use ($field, $value) {
          return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
        };
      case Comparison::IN:
        return function ($object) use ($field, $value) {
          return in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
        };
      case Comparison::NIN:
        return function ($object) use ($field, $value) {
          return !in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
        };
      case Comparison::CONTAINS:
        return function ($object) use ($field, $value) {
          return false !== strpos(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
        };
      default:
        throw new \RuntimeException("Unknown comparison operator: " . $comparison
          ->getOperator());
    }
  }

  /**
   * {@inheritDoc}
   */
  public function walkValue(Value $value) {
    return $value
      ->getValue();
  }

  /**
   * {@inheritDoc}
   */
  public function walkCompositeExpression(CompositeExpression $expr) {
    $expressionList = array();
    foreach ($expr
      ->getExpressionList() as $child) {
      $expressionList[] = $this
        ->dispatch($child);
    }
    switch ($expr
      ->getType()) {
      case CompositeExpression::TYPE_AND:
        return $this
          ->andExpressions($expressionList);
      case CompositeExpression::TYPE_OR:
        return $this
          ->orExpressions($expressionList);
      default:
        throw new \RuntimeException("Unknown composite " . $expr
          ->getType());
    }
  }

  /**
   * @param array $expressions
   *
   * @return callable
   */
  private function andExpressions($expressions) {
    return function ($object) use ($expressions) {
      foreach ($expressions as $expression) {
        if (!$expression($object)) {
          return false;
        }
      }
      return true;
    };
  }

  /**
   * @param array $expressions
   *
   * @return callable
   */
  private function orExpressions($expressions) {
    return function ($object) use ($expressions) {
      foreach ($expressions as $expression) {
        if ($expression($object)) {
          return true;
        }
      }
      return false;
    };
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ClosureExpressionVisitor::andExpressions private function
ClosureExpressionVisitor::getObjectFieldValue public static function Accesses the field of a given object. This field has to be public directly or indirectly (through an accessor get*, is*, or a magic method, __get, __call).
ClosureExpressionVisitor::orExpressions private function
ClosureExpressionVisitor::sortByField public static function Helper for sorting arrays of objects based on multiple fields + orientations.
ClosureExpressionVisitor::walkComparison public function Converts a comparison expression into the target query language output. Overrides ExpressionVisitor::walkComparison
ClosureExpressionVisitor::walkCompositeExpression public function Converts a composite expression into the target query language output. Overrides ExpressionVisitor::walkCompositeExpression
ClosureExpressionVisitor::walkValue public function Converts a value expression into the target query language part. Overrides ExpressionVisitor::walkValue
ExpressionVisitor::dispatch public function Dispatches walking an expression to the appropriate handler.