You are here

class Condition in Zircon Profile 8

Same name in this branch
  1. 8 core/lib/Drupal/Core/Condition/Annotation/Condition.php \Drupal\Core\Condition\Annotation\Condition
  2. 8 core/lib/Drupal/Core/Database/Query/Condition.php \Drupal\Core\Database\Query\Condition
  3. 8 core/lib/Drupal/Core/Config/Entity/Query/Condition.php \Drupal\Core\Config\Entity\Query\Condition
  4. 8 core/lib/Drupal/Core/Entity/KeyValueStore/Query/Condition.php \Drupal\Core\Entity\KeyValueStore\Query\Condition
  5. 8 core/lib/Drupal/Core/Entity/Query/Sql/Condition.php \Drupal\Core\Entity\Query\Sql\Condition
  6. 8 core/lib/Drupal/Core/Entity/Query/Null/Condition.php \Drupal\Core\Entity\Query\Null\Condition
  7. 8 core/lib/Drupal/Core/Entity/Query/Sql/pgsql/Condition.php \Drupal\Core\Entity\Query\Sql\pgsql\Condition
Same name and namespace in other branches
  1. 8.0 core/lib/Drupal/Core/Database/Query/Condition.php \Drupal\Core\Database\Query\Condition

Generic class for a series of conditions in a query.

Hierarchy

Expanded class hierarchy of Condition

11 files declare their use of Condition
AliasStorage.php in core/lib/Drupal/Core/Path/AliasStorage.php
Contains \Drupal\Core\Path\AliasStorage.
Condition.php in core/lib/Drupal/Core/Entity/Query/Sql/Condition.php
Contains \Drupal\Core\Entity\Query\Sql\Condition.
ConditionAggregate.php in core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php
Contains \Drupal\Core\Entity\Query\Sql\ConditionAggregate.
ConditionTest.php in core/tests/Drupal/Tests/Core/Database/ConditionTest.php
Contains \Drupal\Tests\Core\Database\ConditionTest.
database.inc in core/includes/database.inc
Core systems for the database layer.

... See full list

3 string references to 'Condition'
ConditionAggregate::compile in core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php
Compiles this conditional clause.
core.data_types.schema.yml in core/config/schema/core.data_types.schema.yml
core/config/schema/core.data_types.schema.yml
QueryBase::conditionGroupFactory in core/lib/Drupal/Core/Entity/Query/QueryBase.php
Creates an object holding a group of conditions.

File

core/lib/Drupal/Core/Database/Query/Condition.php, line 16
Contains \Drupal\Core\Database\Query\Condition.

Namespace

Drupal\Core\Database\Query
View source
class Condition implements ConditionInterface, \Countable {

  /**
   * Array of conditions.
   *
   * @var array
   */
  protected $conditions = array();

  /**
   * Array of arguments.
   *
   * @var array
   */
  protected $arguments = array();

  /**
   * Whether the conditions have been changed.
   *
   * TRUE if the condition has been changed since the last compile.
   * FALSE if the condition has been compiled and not changed.
   *
   * @var bool
   */
  protected $changed = TRUE;

  /**
   * The identifier of the query placeholder this condition has been compiled against.
   */
  protected $queryPlaceholderIdentifier;

  /**
   * Constructs a Condition object.
   *
   * @param string $conjunction
   *   The operator to use to combine conditions: 'AND' or 'OR'.
   */
  public function __construct($conjunction) {
    $this->conditions['#conjunction'] = $conjunction;
  }

  /**
   * Implements Countable::count().
   *
   * Returns the size of this conditional. The size of the conditional is the
   * size of its conditional array minus one, because one element is the
   * conjunction.
   */
  public function count() {
    return count($this->conditions) - 1;
  }

  /**
   * {@inheritdoc}
   */
  public function condition($field, $value = NULL, $operator = '=') {
    if (empty($operator)) {
      $operator = '=';
    }
    if (empty($value) && is_array($value)) {
      throw new InvalidQueryException(sprintf("Query condition '%s %s ()' cannot be empty.", $field, $operator));
    }
    $this->conditions[] = array(
      'field' => $field,
      'value' => $value,
      'operator' => $operator,
    );
    $this->changed = TRUE;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function where($snippet, $args = array()) {
    $this->conditions[] = array(
      'field' => $snippet,
      'value' => $args,
      'operator' => NULL,
    );
    $this->changed = TRUE;
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isNull($field) {
    return $this
      ->condition($field, NULL, 'IS NULL');
  }

  /**
   * {@inheritdoc}
   */
  public function isNotNull($field) {
    return $this
      ->condition($field, NULL, 'IS NOT NULL');
  }

  /**
   * {@inheritdoc}
   */
  public function exists(SelectInterface $select) {
    return $this
      ->condition('', $select, 'EXISTS');
  }

  /**
   * {@inheritdoc}
   */
  public function notExists(SelectInterface $select) {
    return $this
      ->condition('', $select, 'NOT EXISTS');
  }

  /**
   * {@inheritdoc}
   */
  public function &conditions() {
    return $this->conditions;
  }

  /**
   * {@inheritdoc}
   */
  public function arguments() {

    // If the caller forgot to call compile() first, refuse to run.
    if ($this->changed) {
      return NULL;
    }
    return $this->arguments;
  }

  /**
   * {@inheritdoc}
   */
  public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {

    // Re-compile if this condition changed or if we are compiled against a
    // different query placeholder object.
    if ($this->changed || isset($this->queryPlaceholderIdentifier) && $this->queryPlaceholderIdentifier != $queryPlaceholder
      ->uniqueIdentifier()) {
      $this->queryPlaceholderIdentifier = $queryPlaceholder
        ->uniqueIdentifier();
      $condition_fragments = array();
      $arguments = array();
      $conditions = $this->conditions;
      $conjunction = $conditions['#conjunction'];
      unset($conditions['#conjunction']);
      foreach ($conditions as $condition) {
        if (empty($condition['operator'])) {

          // This condition is a literal string, so let it through as is.
          $condition_fragments[] = ' (' . $condition['field'] . ') ';
          $arguments += $condition['value'];
        }
        else {

          // It's a structured condition, so parse it out accordingly.
          // Note that $condition['field'] will only be an object for a dependent
          // DatabaseCondition object, not for a dependent subquery.
          if ($condition['field'] instanceof ConditionInterface) {

            // Compile the sub-condition recursively and add it to the list.
            $condition['field']
              ->compile($connection, $queryPlaceholder);
            $condition_fragments[] = '(' . (string) $condition['field'] . ')';
            $arguments += $condition['field']
              ->arguments();
          }
          else {

            // For simplicity, we treat all operators as the same data structure.
            // In the typical degenerate case, this won't get changed.
            $operator_defaults = array(
              'prefix' => '',
              'postfix' => '',
              'delimiter' => '',
              'operator' => $condition['operator'],
              'use_value' => TRUE,
            );

            // Remove potentially dangerous characters.
            // If something passed in an invalid character stop early, so we
            // don't rely on a broken SQL statement when we would just replace
            // those characters.
            if (stripos($condition['operator'], 'UNION') !== FALSE || strpbrk($condition['operator'], '[-\'"();') !== FALSE) {
              $this->changed = TRUE;
              $this->arguments = [];

              // Provide a string which will result into an empty query result.
              $this->stringVersion = '( AND 1 = 0 )';

              // Conceptually throwing an exception caused by user input is bad
              // as you result into a WSOD, which depending on your webserver
              // configuration can result into the assumption that your site is
              // broken.
              // On top of that the database API relies on __toString() which
              // does not allow to throw exceptions.
              trigger_error('Invalid characters in query operator: ' . $condition['operator'], E_USER_ERROR);
              return;
            }
            $operator = $connection
              ->mapConditionOperator($condition['operator']);
            if (!isset($operator)) {
              $operator = $this
                ->mapConditionOperator($condition['operator']);
            }
            $operator += $operator_defaults;
            $placeholders = array();
            if ($condition['value'] instanceof SelectInterface) {
              $condition['value']
                ->compile($connection, $queryPlaceholder);
              $placeholders[] = (string) $condition['value'];
              $arguments += $condition['value']
                ->arguments();

              // Subqueries are the actual value of the operator, we don't
              // need to add another below.
              $operator['use_value'] = FALSE;
            }
            elseif (!$operator['delimiter'] && !is_array($condition['value'])) {
              $condition['value'] = array(
                $condition['value'],
              );
            }
            if ($operator['use_value']) {
              foreach ($condition['value'] as $value) {
                $placeholder = ':db_condition_placeholder_' . $queryPlaceholder
                  ->nextPlaceholder();
                $arguments[$placeholder] = $value;
                $placeholders[] = $placeholder;
              }
            }
            $condition_fragments[] = ' (' . $connection
              ->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
          }
        }
      }
      $this->changed = FALSE;
      $this->stringVersion = implode($conjunction, $condition_fragments);
      $this->arguments = $arguments;
    }
  }

  /**
   * {@inheritdoc}
   */
  public function compiled() {
    return !$this->changed;
  }

  /**
   * Implements PHP magic __toString method to convert the conditions to string.
   *
   * @return string
   *   A string version of the conditions.
   */
  public function __toString() {

    // If the caller forgot to call compile() first, refuse to run.
    if ($this->changed) {
      return '';
    }
    return $this->stringVersion;
  }

  /**
   * PHP magic __clone() method.
   *
   * Only copies fields that implement Drupal\Core\Database\Query\ConditionInterface. Also sets
   * $this->changed to TRUE.
   */
  function __clone() {
    $this->changed = TRUE;
    foreach ($this->conditions as $key => $condition) {
      if ($key !== '#conjunction') {
        if ($condition['field'] instanceof ConditionInterface) {
          $this->conditions[$key]['field'] = clone $condition['field'];
        }
        if ($condition['value'] instanceof SelectInterface) {
          $this->conditions[$key]['value'] = clone $condition['value'];
        }
      }
    }
  }

  /**
   * Gets any special processing requirements for the condition operator.
   *
   * Some condition types require special processing, such as IN, because
   * the value data they pass in is not a simple value. This is a simple
   * overridable lookup function.
   *
   * @param $operator
   *   The condition operator, such as "IN", "BETWEEN", etc. Case-sensitive.
   *
   * @return array
   *   The extra handling directives for the specified operator or an empty
   *   array if there are no extra handling directives.
   */
  protected function mapConditionOperator($operator) {

    // $specials does not use drupal_static as its value never changes.
    static $specials = array(
      'BETWEEN' => array(
        'delimiter' => ' AND ',
      ),
      'IN' => array(
        'delimiter' => ', ',
        'prefix' => ' (',
        'postfix' => ')',
      ),
      'NOT IN' => array(
        'delimiter' => ', ',
        'prefix' => ' (',
        'postfix' => ')',
      ),
      'EXISTS' => array(
        'prefix' => ' (',
        'postfix' => ')',
      ),
      'NOT EXISTS' => array(
        'prefix' => ' (',
        'postfix' => ')',
      ),
      'IS NULL' => array(
        'use_value' => FALSE,
      ),
      'IS NOT NULL' => array(
        'use_value' => FALSE,
      ),
      // Use backslash for escaping wildcard characters.
      'LIKE' => array(
        'postfix' => " ESCAPE '\\\\'",
      ),
      'NOT LIKE' => array(
        'postfix' => " ESCAPE '\\\\'",
      ),
      // These ones are here for performance reasons.
      '=' => array(),
      '<' => array(),
      '>' => array(),
      '>=' => array(),
      '<=' => array(),
    );
    if (isset($specials[$operator])) {
      $return = $specials[$operator];
    }
    else {

      // We need to upper case because PHP index matches are case sensitive but
      // do not need the more expensive Unicode::strtoupper() because SQL statements are ASCII.
      $operator = strtoupper($operator);
      $return = isset($specials[$operator]) ? $specials[$operator] : array();
    }
    $return += array(
      'operator' => $operator,
    );
    return $return;
  }

  /**
   * {@inheritdoc}
   */
  public function conditionGroupFactory($conjunction = 'AND') {
    return new Condition($conjunction);
  }

  /**
   * {@inheritdoc}
   */
  public function andConditionGroup() {
    return $this
      ->conditionGroupFactory('AND');
  }

  /**
   * {@inheritdoc}
   */
  public function orConditionGroup() {
    return $this
      ->conditionGroupFactory('OR');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Condition::$arguments protected property Array of arguments.
Condition::$changed protected property Whether the conditions have been changed.
Condition::$conditions protected property Array of conditions.
Condition::$queryPlaceholderIdentifier protected property The identifier of the query placeholder this condition has been compiled against.
Condition::andConditionGroup public function Creates a new group of conditions ANDed together. Overrides ConditionInterface::andConditionGroup
Condition::arguments public function Gets a complete list of all values to insert into the prepared statement. Overrides ConditionInterface::arguments
Condition::compile public function Compiles the saved conditions for later retrieval. Overrides ConditionInterface::compile
Condition::compiled public function Check whether a condition has been previously compiled. Overrides ConditionInterface::compiled
Condition::condition public function Helper function: builds the most common conditional clauses. Overrides ConditionInterface::condition
Condition::conditionGroupFactory public function Creates an object holding a group of conditions. Overrides ConditionInterface::conditionGroupFactory
Condition::conditions public function Gets a complete list of all conditions in this conditional clause. Overrides ConditionInterface::conditions
Condition::count public function Implements Countable::count().
Condition::exists public function Sets a condition that the specified subquery returns values. Overrides ConditionInterface::exists
Condition::isNotNull public function Sets a condition that the specified field be NOT NULL. Overrides ConditionInterface::isNotNull
Condition::isNull public function Sets a condition that the specified field be NULL. Overrides ConditionInterface::isNull
Condition::mapConditionOperator protected function Gets any special processing requirements for the condition operator.
Condition::notExists public function Sets a condition that the specified subquery returns no values. Overrides ConditionInterface::notExists
Condition::orConditionGroup public function Creates a new group of conditions ORed together. Overrides ConditionInterface::orConditionGroup
Condition::where public function Adds an arbitrary WHERE clause to the query. Overrides ConditionInterface::where
Condition::__clone function PHP magic __clone() method.
Condition::__construct public function Constructs a Condition object.
Condition::__toString public function Implements PHP magic __toString method to convert the conditions to string.