Example #1
0
 /**
  * De inhoud van de WHERE or HAVING samenstellen.
  *
  * @param array $restrictions
  * @param bool  $addBraces
  *
  * @return string
  */
 private function composeRestrictions($restrictions, $addBraces = false)
 {
     // [string]
     if (is_string($restrictions)) {
         // Is the restrictionsTree already parsed?
         if ($addBraces) {
             return '(' . $restrictions . ')';
         }
         return $restrictions;
     }
     $logicalOperator = \Sledgehammer\extract_logical_operator($restrictions);
     if ($logicalOperator === false) {
         if (count($restrictions) !== 1) {
             throw new InfoException('where[] statements require an logical operator, Example: array("AND", "x = 1", "y = 2")', $restrictions);
         }
     } else {
         unset($restrictions[0]);
         // Remove the operator from the array.
     }
     if (count($restrictions) === 1) {
         reset($restrictions);
         return $this->composeRestrictions(current($restrictions));
     }
     switch ($logicalOperator) {
         case 'AND':
         case 'OR':
             break;
         default:
             throw new Exception('Unknown logical operator: "' . $logicalOperator . '"');
     }
     $expressions = [];
     foreach ($restrictions as $restriction) {
         if (is_array($restriction)) {
             // Is het geen sql maar nog een 'restriction'?
             $operatorSwitch = \Sledgehammer\extract_logical_operator($restriction) !== $logicalOperator;
             // If the subnode has the same logical operator, don't add braces. "x = 1 AND (y = 5 AND z = 8)" has same meaning as "x = 1 AND y = 5 AND z = 8"
             $restriction = $this->composeRestrictions($restriction, $operatorSwitch);
         }
         if ($restriction != '') {
             // ignore empty statements.
             $expressions[] = $restriction;
         }
     }
     if (count($expressions) == 0) {
         // No statements (a restriction with just the operator "array(AND')" but no restrictions).
         return '';
     }
     $sql = implode(' ' . $logicalOperator . ' ', $expressions);
     // Join the sql statements with the logical operator.
     if ($addBraces) {
         // moeten er haakjes omheen?
         return '(' . $sql . ')';
     }
     return $sql;
 }
Example #2
0
 /**
  * Return a subsection of the collection based on the conditions.
  *
  * Convert the $conditions to SQL object when appropriate.
  *
  * auto converts
  *   ['x_id' => null]  to "x_id IS NULL"
  * 	 ['x_id !=' => null]  to "x_id IS NOT NULL"
  *  'hits' => 0]  to "hits = '0'"  (Because in mysql '' = 0 evaluates to true, '' = '0' to false)
  *
  * @param array $conditions
  *
  * @return Collection
  */
 public function where($conditions)
 {
     if ($this->data !== null || is_string($this->sql) || is_object($conditions) && is_callable($conditions) || $this->sql->limit !== false || $this->sql->offset != 0) {
         return parent::where($conditions);
     }
     $db = Connection::instance($this->dbLink);
     $sql = $this->sql;
     $logicalOperator = \Sledgehammer\extract_logical_operator($conditions);
     if ($logicalOperator === false) {
         if (count($conditions) > 1) {
             \Sledgehammer\notice('Conditions with multiple conditions require a logical operator.', "Example: array('AND', 'x' => 1, 'y' => 5)");
         }
         $logicalOperator = 'AND';
     } else {
         unset($conditions[0]);
     }
     if ($logicalOperator === 'AND') {
         $method = 'andWhere';
     } elseif ($logicalOperator === 'OR') {
         $method = 'orWhere';
     } else {
         throw new Exception('Unsupported logical operator "' . $logicalOperator . '", expecting "AND" or "OR"');
     }
     // The result are rows(fetch_assoc arrays), all conditions must be columnnames (or invalid)
     foreach ($conditions as $path => $value) {
         if (preg_match('/^(.*) (' . \Sledgehammer\COMPARE_OPERATORS . ')$/', $path, $matches)) {
             $column = $this->convertPathToColumn($matches[1]);
             $operator = $matches[2];
         } else {
             $column = $this->convertPathToColumn($path);
             $operator = '==';
         }
         if ($column === false) {
             // Converting to path failed?
             \Sledgehammer\array_key_unshift($conditions, 0, $logicalOperator);
             return parent::where($conditions);
         }
         if ($value === null) {
             switch ($operator) {
                 case '==':
                     $operator = 'IS';
                     $expectation = 'NULL';
                     break;
                 case '!=':
                     $operator = 'IS NOT ';
                     $expectation = 'NULL';
                     break;
                 case '>':
                 case '<':
                 case '>=':
                 case '<=':
                     $expectation = "''";
                     break;
                 default:
                     \Sledgehammer\warning('Unknown behavior for NULL values with operator "' . $operator . '"');
                     $expectation = $db->quote($expectation);
                     break;
             }
             $sql = $sql->{$method}($column . ' ' . $operator . ' ' . $expectation);
         } else {
             if ($operator === '!=') {
                 $sql = $sql->{$method}('(' . $column . ' != ' . $db->quote($value, PDO::PARAM_STR) . ' OR ' . $column . ' IS NULL)');
             } elseif ($operator === 'IN') {
                 if ((is_array($value) || $value instanceof Traversable) === false) {
                     \Sledgehammer\notice('Operator IN expects an array or Traversable', $value);
                     $value = explode(',', $value);
                 }
                 $quoted = [];
                 foreach ($value as $val) {
                     $quoted[] = $this->quote($db, $column, $val);
                 }
                 $sql = $sql->{$method}($column . ' ' . $operator . ' (' . implode(', ', $quoted) . ')');
             } else {
                 if ($operator === '==') {
                     $operator = '=';
                 }
                 $sql = $sql->{$method}($column . ' ' . $operator . ' ' . $this->quote($db, $column, $value));
             }
         }
     }
     return new self($sql, $this->dbLink);
 }
 public function where($conditions)
 {
     if ($this->isConverted) {
         return parent::where($conditions);
     }
     if ($this->data instanceof Collection && is_array($conditions)) {
         $logicalOperator = \Sledgehammer\extract_logical_operator($conditions);
         $convertedConditions = [];
         if ($logicalOperator === false) {
             if (count($conditions) > 1) {
                 notice('Conditions with multiple conditions require a logical operator.', "Example: array('AND', 'x' => 1, 'y' => 5)");
             }
             $minimum = 0;
         } else {
             $minimum = 1;
             $convertedConditions[0] = $logicalOperator;
         }
         foreach ($conditions as $path => $value) {
             if (preg_match('/^(.*) (' . \Sledgehammer\COMPARE_OPERATORS . ')$/', $path, $match)) {
                 $column = $match[1];
                 $columnOperator = ' ' . $match[2];
             } else {
                 $column = $path;
                 $columnOperator = '';
             }
             if (($path !== 0 || $logicalOperator === false) && isset($this->options['mapping'][$column])) {
                 $convertCondition = true;
                 if (isset($this->options['writeFilters'][$column])) {
                     if (in_array($columnOperator, array('', '==', '!='))) {
                         $value = filter($value, $this->options['writeFilters'][$column]);
                     } else {
                         $convertCondition = false;
                         // operation can't work reliably with filters
                     }
                 }
                 if ($convertCondition) {
                     $convertedConditions[$this->options['mapping'][$column] . $columnOperator] = $value;
                     unset($conditions[$path]);
                 }
             }
         }
         if (count($convertedConditions) > $minimum) {
             // There are conditions the low-level collection can handle?
             $collection = new self($this->data->where($convertedConditions), $this->model, $this->repository, $this->options);
             if (count($conditions) === $minimum) {
                 return $collection;
             }
             return $collection->where($conditions);
             // Apply the remaining conditions
         } elseif (count($conditions) === $minimum) {
             // An empty array was given as $conditions?
             return new self(clone $this->data, $this->model, $this->repository, $this->options);
         }
     }
     return parent::where($conditions);
 }
Example #4
0
 /**
  * Build a closure which validates an item with the gives $conditions.
  *
  * @param mixed $conditions array|Closure|expression  See Collection::where() for condition options
  *
  * @return callable
  */
 protected function buildFilter($conditions)
 {
     if (\Sledgehammer\is_closure($conditions)) {
         return $conditions;
     }
     if (is_array($conditions)) {
         // Create filter that checks all conditions
         $logicalOperator = \Sledgehammer\extract_logical_operator($conditions);
         if ($logicalOperator === false) {
             if (count($conditions) > 1) {
                 \Sledgehammer\notice('Conditions with multiple conditions require a logical operator.', "Example: array('AND', 'x' => 1, 'y' => 5)");
             }
             $logicalOperator = 'AND';
         } else {
             unset($conditions[0]);
         }
         $operators = [];
         foreach ($conditions as $path => $expectation) {
             if (preg_match('/^(.*) (' . \Sledgehammer\COMPARE_OPERATORS . ')$/', $path, $matches)) {
                 unset($conditions[$path]);
                 $conditions[$matches[1]] = $expectation;
                 $operators[$matches[1]] = $matches[2];
             } else {
                 $operators[$path] = false;
             }
         }
         // @todo Build an optimized closure for when a single conditions is given.
         if ($logicalOperator === 'AND') {
             return function ($item) use($conditions, $operators) {
                 foreach ($conditions as $path => $expectation) {
                     $actual = PropertyPath::get($path, $item);
                     $operator = $operators[$path];
                     if ($operator) {
                         if (\Sledgehammer\compare($actual, $operator, $expectation) === false) {
                             return false;
                         }
                     } elseif (\Sledgehammer\equals($actual, $expectation) === false) {
                         return false;
                     }
                 }
                 return true;
                 // All conditions are met.
             };
         } elseif ($logicalOperator === 'OR') {
             return function ($item) use($conditions, $operators) {
                 foreach ($conditions as $path => $expectation) {
                     $actual = PropertyPath::get($path, $item);
                     $operator = $operators[$path];
                     if ($operator) {
                         if (\Sledgehammer\compare($actual, $operator, $expectation) !== false) {
                             return true;
                         }
                     } elseif (\Sledgehammer\equals($actual, $expectation) !== false) {
                         return true;
                     }
                 }
                 return false;
                 // None of conditions are met.
             };
         } else {
             throw new Exception('Unsupported logical operator "' . $logicalOperator . '", expecting "AND" or "OR"');
         }
     }
     //'<= 5' or '10'
     // Compare the item directly with value given as $condition.
     if (is_string($conditions) && preg_match('/^(' . \Sledgehammer\COMPARE_OPERATORS . ') (.*)$/', $conditions, $matches)) {
         $operator = $matches[1];
         $expectation = $matches[2];
     } else {
         $expectation = $conditions;
         $operator = '==';
     }
     return function ($value) use($expectation, $operator) {
         return \Sledgehammer\compare($value, $operator, $expectation);
     };
 }