diff --git a/lib/Cake/Model/Datasource/Database/Expression/QueryExpression.php b/lib/Cake/Model/Datasource/Database/Expression/QueryExpression.php index c179501e970..711558bc031 100644 --- a/lib/Cake/Model/Datasource/Database/Expression/QueryExpression.php +++ b/lib/Cake/Model/Datasource/Database/Expression/QueryExpression.php @@ -5,7 +5,7 @@ class QueryExpression implements Countable { - protected $_conjuction; + protected $_conjunction; protected $_conditions = []; @@ -33,9 +33,12 @@ public function type($conjunction = null) { public function add($conditions, $types = []) { if (is_string($conditions)) { $this->_conditions[] = $conditions; + return $this; } - if ($conditions instanceof self && count($conditions) > 0) { + + if ($conditions instanceof QueryExpression && count($conditions) > 0) { $this->_conditions[] = $conditions; + return $this; } $this->_addConditions($conditions, $types); diff --git a/lib/Cake/Model/Datasource/Database/Query.php b/lib/Cake/Model/Datasource/Database/Query.php index 4f42e2a7447..e7887a6a984 100644 --- a/lib/Cake/Model/Datasource/Database/Query.php +++ b/lib/Cake/Model/Datasource/Database/Query.php @@ -247,7 +247,11 @@ public function where($conditions = null, $types = [], $overwrite = false) { } public function andWhere($conditions, $types = []) { - $where = $this->_parts['where'] ?: new QueryExpression(); + $where = $this->_parts['where'] ?: new QueryExpression; + + if (is_callable($conditions)) { + $conditions = $conditions(new QueryExpression, $this); + } if ($where->type() === 'AND') { $where->add($conditions, $types); diff --git a/lib/Cake/Test/TestCase/Model/Datasource/Database/QueryTest.php b/lib/Cake/Test/TestCase/Model/Datasource/Database/QueryTest.php index df6faafff55..1a9d03096aa 100644 --- a/lib/Cake/Test/TestCase/Model/Datasource/Database/QueryTest.php +++ b/lib/Cake/Test/TestCase/Model/Datasource/Database/QueryTest.php @@ -485,7 +485,13 @@ public function testSelectAndWhereNoPreviousCondition() { $this->assertEquals(['id' => 1], $result->fetch('assoc')); } - public function testSelectAndWhereUsingClosure() { +/** + * Tests that it is possible to pass a closure to where() to build a set of + * conditions and return the expression to be used + * + * @return void + **/ + public function testSelectWhereUsingClosure() { $this->_insertDateRecords(); $query = new Query($this->connection); $result = $query @@ -523,4 +529,37 @@ public function testSelectAndWhereUsingClosure() { ->execute(); $this->assertCount(0, $result); } + +/** + * Tests that it is possible to pass a closure to andWhere() to build a set of + * conditions and return the expression to be used + * + * @return void + **/ + public function testSelectAndWhereUsingClosure() { + $this->_insertDateRecords(); + $query = new Query($this->connection); + $result = $query + ->select(['id']) + ->from('dates') + ->where(['id' => '1']) + ->andWhere(function($exp) { + return $exp->equals('posted', new \DateTime('2012-12-21 12:00'), 'datetime'); + }) + ->execute(); + $this->assertCount(1, $result); + $this->assertEquals(['id' => 1], $result->fetch('assoc')); + + $query = new Query($this->connection); + $result = $query + ->select(['id']) + ->from('dates') + ->where(['id' => '1']) + ->andWhere(function($exp) { + return $exp->equals('posted', new \DateTime('2022-12-21 12:00'), 'datetime'); + }) + ->execute(); + $this->assertCount(0, $result); + } + }