You are here

ClosureExpressionVisitor.php in Plug 7

File

lib/doctrine/collections/lib/Doctrine/Common/Collections/Expr/ClosureExpressionVisitor.php
View source
<?php

/*
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the MIT license. For more information, see
 * <http://www.doctrine-project.org>.
 */
namespace Doctrine\Common\Collections\Expr;


/**
 * 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
 */
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;
    };
  }

}

Classes

Namesort descending Description
ClosureExpressionVisitor Walks an expression graph and turns it into a PHP closure.