Skip to content

Commit

Permalink
Implemented support for in and not in
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Jan 1, 2013
1 parent 2d0182f commit 8a44c05
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 3 deletions.
50 changes: 47 additions & 3 deletions lib/Cake/Model/Datasource/Database/Expression/QueryExpression.php
Expand Up @@ -13,6 +13,11 @@ class QueryExpression implements Countable {

protected $_identifier;

protected $_bindingsCount = 0;

protected $_replaceArrayParams = false;


public function __construct($conditions = [], $types = [], $conjunction = 'AND') {
$this->_conjunction = strtoupper($conjunction);
$this->_identifier = substr(spl_object_hash($this), 7, 9);
Expand Down Expand Up @@ -89,6 +94,10 @@ public function in($field, $values, $type = null) {
return $this->add([$field . ' IN' => $values], $type ? [$field => $type] : []);
}

public function notIn($field, $values, $type = null) {
return $this->add([$field . ' NOT IN' => $values], $type ? [$field => $type] : []);
}

/**
* Associates a query placeholder to a value and a type for next execution
*
Expand All @@ -101,15 +110,20 @@ public function in($field, $values, $type = null) {
*/
public function bind($token, $value, $type) {
$param = $token;
$number = count($this->_bindings);
$number = $this->_bindingsCount++;

if (is_numeric($token)) {
$param = '?';
} else if ($param[0] !== ':') {
$param = sprintf(':c%s%s', $this->_identifier, $number);
}

$this->_bindings[$number] = compact('value', 'type') + [
if (strpos($type, '[]') !== false) {
$param = sprintf(':array%d', $number);
$type = str_replace('[]', '', $type);
}

$this->_bindings[$number] = compact('value', 'type', 'token') + [
'placeholder' => substr($param, 1)
];
return $param;
Expand All @@ -134,6 +148,9 @@ public function __toString() {
}

public function sql() {
if ($this->_replaceArrayParams) {
$this->_replaceArrays();
}
$conjunction = $this->_conjunction;
return '(' . implode(" $conjunction ", $this->_conditions) . ')';
}
Expand Down Expand Up @@ -188,7 +205,34 @@ protected function _parseCondition($field, $value, $types) {
}

$type = isset($types[$expression]) ? $types[$expression] : null;
return sprintf('%s %s %s', $expression, $operator, $this->bind($field, $value, $type));
$template = '%s %s %s';

if (in_array(strtolower(trim($operator)), ['in', 'not in'])) {
$type = $type ?: 'string';
$type .= strpos($type, '[]') === false ? '[]' : null;
$template = '%s %s (%s)';
$this->_replaceArrayParams = true;
}

return sprintf($template, $expression, $operator, $this->bind($field, $value, $type));
}

protected function _replaceArrays() {
foreach ($this->_conditions as $k => $condition) {
if (!is_string($condition)) {
continue;
}
$condition = preg_replace_callback('/(:array(\d+))/', function($match) {
$params = [];
$binding = $this->_bindings[$match[2]];
foreach ($this->_bindings[$match[2]]['value'] as $value) {
$params[] = $this->bind($binding['token'], $value, $binding['type']);
}
unset($this->_bindings[$match[2]]);
return implode(', ', $params);
}, $condition);
$this->_conditions[$k] = $condition;
}
}

}
41 changes: 41 additions & 0 deletions lib/Cake/Test/TestCase/Model/Datasource/Database/QueryTest.php
Expand Up @@ -692,6 +692,47 @@ public function testSelectWhereOperatorMethods() {
->where(function($exp) { return $exp->isNotNull('visible'); })
->execute();
$this->assertCount(2, $result);

$query = new Query($this->connection);
$result = $query
->select(['id'])
->from('dates')
->where(function($exp) {
return $exp->in('visible', ['Y', 'N']);
})
->execute();
$this->assertCount(2, $result);

$query = new Query($this->connection);
$result = $query
->select(['id'])
->from('dates')
->where(function($exp) {
return $exp->in(
'posted',
[new \DateTime('2012-12-21 12:00'), new \DateTime('2012-12-22 12:00')],
'datetime'
);
})
->execute();
$this->assertCount(2, $result);
$this->assertEquals(['id' => 1], $result->fetch('assoc'));
$this->assertEquals(['id' => 2], $result->fetch('assoc'));

$query = new Query($this->connection);
$result = $query
->select(['id'])
->from('dates')
->where(function($exp) {
return $exp->notIn(
'posted',
[new \DateTime('2012-12-21 12:00'), new \DateTime('2012-12-22 12:00')],
'datetime'
);
})
->execute();
$this->assertCount(1, $result);
$this->assertEquals(['id' => 3], $result->fetch('assoc'));
}

}

0 comments on commit 8a44c05

Please sign in to comment.