New DatabaseCondition

  1. class DatabaseCondition implements QueryConditionInterface, Countable {
  2.  
  3.   protected $conditions = array();
  4.   protected $arguments = array();
  5.  
  6.   protected $updated = TRUE;
  7.  
  8.   public function __construct($conjunction) {
  9.     $this->conditions['#conjunction'] = $conjunction;
  10.   }
  11.  
  12.   /**
  13.    * Return the size of this conditional.  This is part of the Countable interface.
  14.    *
  15.    * The size of the conditional is the size of its conditional array minus
  16.    * one, because one element is the the conjunction.
  17.    */
  18.   public function count() {
  19.     return count($this->conditions) - 1;
  20.   }
  21.  
  22.   public function condition($field, $value = NULL, $operator = '=') {
  23.     $this->conditions[] = array(
  24.       'field' => $field,
  25.       'value' => $value,
  26.       'operator' => $operator,
  27.     );
  28.    
  29.     $this->updated = TRUE;
  30.    
  31.     return $this;
  32.   }
  33.  
  34.   public function where($snippet, $args = array()) {
  35.     $this->conditions[] = array(
  36.       'field' => $field,
  37.       'value' => $args,
  38.       'operator' => NULL,
  39.     );
  40.  
  41.     $this->updated = TRUE;
  42.    
  43.     return $this;
  44.   }
  45.  
  46.   public function conditions() {
  47.     // If there's only one entry, it's just the default #type, which means
  48.     // we don't really have any conditions to speak of.
  49.     return (count($this->conditions) > 1) ? $this->conditions : array();
  50.   }
  51.  
  52.   public function arguments() {
  53.     return $this->arguments;
  54.   }
  55.  
  56.   public function compile(DatabaseConnection $connection) {
  57.     // This value is static, so it will increment across the entire request
  58.     // rather than just this query.  That is OK, because we only need definitive
  59.     // placeholder names if we're going to use them for _alter hooks, which we
  60.     // are not.  The alter hook would intervene before compilation.
  61.     static $next_placeholder = 1;
  62.    
  63.     $condition_fragments = array();
  64.     $arguments = array();
  65.    
  66.     $conditions = $this->conditions;
  67.     $conjunction = $conditions['#conjunction'];
  68.     unset($conditions['#conjunction']);
  69.     foreach ($conditions as $condition) {
  70.       if (!empty($condition['operator'])) {
  71.         // It's a structured condition, so parse it out accordingly.
  72.         if ($condition['field'] instanceof QueryConditionInterface) {
  73.           // Compile the sub-condition recursively and add it to the list.
  74.           $return = $condition['field']->compile($connection);
  75.           $condition_fragments[] = $return['fragment'];
  76.           $arguments += $return['arguments'];
  77.         }
  78.         else {
  79.           // For simplicity, we treat all operators as the same data structure.
  80.           // In the typical degenerate case, this won't get changed.
  81.           $operator_defaults = array(
  82.             'prefix' => '',
  83.             'postfix' => '',
  84.             'delimiter' => '',
  85.             'operator' => $condition['operator'],
  86.           );
  87.           $operator = $connection->mapConditionOperator($condition['operator']);
  88.           if (!isset($operator)) {
  89.             $operator = $this->mapConditionOperator($condition['operator']);
  90.           }
  91.           $operator += $operator_defaults;
  92.          
  93.           if ($condition['value'] instanceof SelectQuery) {
  94.             $placeholders[] = (string)$condition['value'];
  95.             $arguments += $condition['value']->arguments();
  96.           }
  97.           // We assume that if there is a delimiter, then the value is an
  98.           // array.  If not, it is a scalar.  For simplicity, we first convert
  99.           // up to an array so that we can build the placeholders in the same way.
  100.           elseif (!$operator['delimiter']) {
  101.             $condition['value'] = array($condition['value']);
  102.           }
  103.           foreach ($condition['value'] as $value) {
  104.             $placeholder = ':db_condition_placeholder_'. $next_placeholder++;
  105.             $arguments[$placeholder] = $value;
  106.             $placeholders[] = $placeholder;
  107.           }
  108.          
  109.           $condition_fragments[] = '(' . $condition['field'] . $operator['operator'] . $operator['prefix'] . implode($condition['delimiter'], $placeholders) . $operator['postfix'] . ')';
  110.          
  111.         }
  112.       }
  113.       else {
  114.         // This condition is a literal string, so let it through as is.
  115.         $condition_fragments[] = '(' . $condition['field'] . ')';
  116.         $arguments += $condition['value'];
  117.        
  118.       }
  119.     }
  120.    
  121.     $this->updated = FALSE;
  122.    
  123.     //$this->stringVersion = implode($conjunction, $condition_fragments);
  124.     //$this->arguments = $arguments;
  125.    
  126.    
  127.      return array(
  128.       'fragment' => implode($conjunction, $condition_fragments),
  129.       'arguments' => $arguments,
  130.     );
  131.    
  132.   }
  133.  
  134.   /**
  135.    * Gets any special processing requirements for the condition operator.
  136.    *
  137.    * Some condition types require special processing, such as IN, because
  138.    * the value data they pass in is not a simple value.  This is a simple
  139.    * overridable lookup function.
  140.    *
  141.    * @param $operator
  142.    *   The condition operator, such as "IN", "BETWEEN", etc.  Case-sensitive.
  143.    * @return
  144.    *   The extra handling directives for the specified operator, or NULL.
  145.    */
  146.   protected function mapConditionOperator($operator) {
  147.     static $specials = array(
  148.       'BETWEEN' => array('delimiter' => ' AND '),
  149.       'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
  150.       'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
  151.       'LIKE' => array('operator' => 'LIKE'),
  152.     );
  153.  
  154.     $return = isset($specials[$operator]) ? $specials[$operator] : array();
  155.     $return += array('operator' => $operator);
  156.  
  157.     return $return;
  158.   }
  159.  
  160. }