Skip to content

Commit

Permalink
Making it possible to build queries using an array like in Cake 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Aug 10, 2013
1 parent 70f7219 commit f806e52
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 1 deletion.
1 change: 0 additions & 1 deletion lib/Cake/Database/Expression/FunctionExpression.php
Expand Up @@ -112,7 +112,6 @@ public function add($params, $types = []) {
* @return string
*/
public function sql(ValueBinder $generator) {

$parts = [];
foreach ($this->_conditions as $condition) {
if ($condition instanceof ExpressionInterface) {
Expand Down
59 changes: 59 additions & 0 deletions lib/Cake/ORM/Query.php
Expand Up @@ -459,6 +459,65 @@ public function aliasFields($fields, $defaultAlias = null) {
return $aliased;
}

/**
* Populates or adds parts to current query clauses using an array.
* This is handy for passing all query clauses at once.
*
* ## Example:
*
* {{{
* $query->applyOptions([
* 'fields' => ['id', 'name'],
* 'conditions' => [
* 'created >=' => '2013-01-01'
* ],
* 'limit' => 10
* ]);
* }}}
*
* Is equivalent to:
*
* {{{
* $query
* ->select(['id', 'name'])
* ->where(['created >=' => '2013-01-01'])
* ->limit(10)
* }}}
*
* @param array $options list of query clauses to apply new parts to. Accepts:
* - fields: Maps to the select method
* - conditions: Maps to the where method
* - limit: Maps to the limit method
* - order: Maps to the order method
* - offset: Maps to the offset method
* - group: Maps to the group method
* - having: Maps to the having method
* - contain: Maps to the contain options for eager loading
* - join: Maps to the join method
* @return Query
*/
public function applyOptions(array $options) {
$valid = [
'fields' => 'select',
'conditions' => 'where',
'limit' => 'limit',
'order' => 'order',
'offset' => 'offset',
'group' => 'group',
'having' => 'having',
'contain' => 'contain',
'join' => 'join'
];

foreach ($options as $option => $values) {
if (isset($valid[$option])) {
$this->{$valid[$option]}($values);
}
}

return $this;
}

/**
* Auxiliary function used to wrap the original statement from the driver with
* any registered callbacks. This will also setup the correct statement class
Expand Down
1 change: 1 addition & 0 deletions lib/Cake/ORM/Table.php
Expand Up @@ -509,6 +509,7 @@ public function find($type, $options = []) {
if ($event->isStopped()) {
return $query;
}
$query->applyOptions($options);
return $this->{'find' . ucfirst($type)}($query, $options);
}

Expand Down
48 changes: 48 additions & 0 deletions lib/Cake/Test/TestCase/ORM/QueryTest.php
Expand Up @@ -840,4 +840,52 @@ public function testBufferResults() {
$this->assertInstanceOf('Cake\ORM\BufferedResultSet', $result);
}

/*
* Tests that applying array options to a query will convert them
* to equivalent function calls with the correspondent array values
*
* @return void
*/
public function testApplyOptions() {
$options = [
'fields' => ['field_a', 'field_b'],
'conditions' => ['field_a' => 1, 'field_b' => 'something'],
'limit' => 1,
'order' => ['a' => 'ASC'],
'offset' => 5,
'group' => ['field_a'],
'having' => ['field_a >' => 100],
'contain' => ['table_a' => ['table_b']],
'join' => ['table_a' => ['conditions' => ['a > b']]]
];
$query = new Query($this->connection, $this->table);
$query->applyOptions($options);

$this->assertEquals(['field_a', 'field_b'], $query->clause('select'));

$expected = new QueryExpression($options['conditions']);
$result = $query->clause('where');
$this->assertEquals($expected, $result);

$this->assertEquals(1, $query->clause('limit'));

$expected = new QueryExpression(['a > b']);
$result = $query->clause('join');
$this->assertEquals([
['alias' => 'table_a', 'type' => 'INNER', 'conditions' => $expected]
], $result);

$expected = new OrderByExpression(['a' => 'ASC']);
$this->assertEquals($expected, $query->clause('order'));

$this->assertEquals(5, $query->clause('offset'));
$this->assertEquals(['field_a'], $query->clause('group'));

$expected = new QueryExpression($options['having']);
$this->assertEquals($expected, $query->clause('having'));

$expected = new \ArrayObject(['table_a' => ['table_b' => []]]);
$this->assertEquals($expected, $query->contain());
}

}
18 changes: 18 additions & 0 deletions lib/Cake/Test/TestCase/ORM/TableTest.php
Expand Up @@ -485,4 +485,22 @@ public function testDeleteAllFailure() {
$table->deleteAll(['id >' => 4]);
}

/**
* Tests that array options are passed to the query object using applyOptions
*
* @return void
*/
public function testFindApplyOptions() {
$table = $this->getMock('Cake\ORM\Table', ['_buildQuery'], ['table' => 'users']);
$query = $this->getMock('Cake\ORM\Query', [], [$this->connection, $table]);
$table->expects($this->once())
->method('_buildQuery')
->will($this->returnValue($query));

$options = ['fields' => ['a', 'b'], 'connections' => ['a >' => 1]];
$query->expects($this->once())
->method('applyOptions')
->with($options);
$table->find('all', $options);
}
}

0 comments on commit f806e52

Please sign in to comment.