Skip to content

Commit

Permalink
Add the ability to add automatic fields.
Browse files Browse the repository at this point in the history
When selecting specific fields (such as computed fields) it is often
really helpful to also select all the fields in the model. Instead of
having to type out all the columns in the schema, the autoFields()
method can be used to tell an ORM\Query to also include the automatic
fields. This new method also works in contain() builders.

Refs #4360
  • Loading branch information
markstory committed Aug 24, 2014
1 parent f11629f commit 44fee92
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/ORM/Association.php
Expand Up @@ -596,13 +596,18 @@ protected function _dispatchBeforeFind($query) {
protected function _appendFields($query, $surrogate, $options) {
$options['fields'] = $surrogate->clause('select') ?: $options['fields'];
$target = $this->_targetTable;
if (empty($options['fields'])) {
$autoFields = $surrogate->autoFields();
if (empty($options['fields']) && !$autoFields) {
$f = isset($options['fields']) ? $options['fields'] : null;
if ($options['includeFields'] && ($f === null || $f !== false)) {
$options['fields'] = $target->schema()->columns();
}
}

if ($autoFields === true) {
$options['fields'] = array_merge((array)$options['fields'], $target->schema()->columns());
}

if (!empty($options['fields'])) {
$query->select($query->aliasFields($options['fields'], $target->alias()));
}
Expand Down
27 changes: 26 additions & 1 deletion src/ORM/Query.php
Expand Up @@ -66,6 +66,14 @@ class Query extends DatabaseQuery implements JsonSerializable {
*/
protected $_hasFields;

/**
* Tracks whether or not the original query should include
* fields from the top level model.
*
* @var bool
*/
protected $_autoFields;

/**
* Boolean for tracking whether or not buffered results
* are enabled.
Expand Down Expand Up @@ -625,7 +633,7 @@ protected function _addDefaultFields() {
$select = $this->clause('select');
$this->_hasFields = true;

if (!count($select)) {
if (!count($select) || $this->_autoFields === true) {
$this->_hasFields = false;
$this->select($this->repository()->schema()->columns());
$select = $this->clause('select');
Expand Down Expand Up @@ -756,4 +764,21 @@ public function jsonSerialize() {
return $this->all();
}

/**
* Get/Set whether or not the ORM should automatically append fields.
*
* By default calling select() will disable auto-fields. You can re-enable
* auto-fields with this method.
*
* @param bool $value The value to set or null to read the current value.
* @return bool|$this Either the current value or the query object.
*/
public function autoFields($value = null) {
if ($value === null) {
return $this->_autoFields;
}
$this->_autoFields = (bool)$value;
return $this;
}

}
69 changes: 68 additions & 1 deletion tests/TestCase/ORM/QueryTest.php
Expand Up @@ -27,7 +27,6 @@

/**
* Tests Query class
*
*/
class QueryTest extends TestCase {

Expand Down Expand Up @@ -2006,4 +2005,72 @@ public function testJsonSerialize() {
);
}

/**
* Test that addFields() works in the basic case.
*
* @return void
*/
public function testAutoFields() {
$table = TableRegistry::get('Articles');
$result = $table->find('all')
->select(['myField' => 'id + 20'])
->autoFields(true)
->hydrate(false)
->first();

$this->assertArrayHasKey('myField', $result);
$this->assertArrayHasKey('id', $result);
$this->assertArrayHasKey('title', $result);
}

/**
* Test autoFields with auto fields.
*
* @return void
*/
public function testAutoFieldsWithAssociations() {
$table = TableRegistry::get('Articles');
$table->belongsTo('Authors');

$result = $table->find()
->select(['myField' => '(SELECT RAND())'])
->autoFields(true)
->hydrate(false)
->contain('Authors')
->first();

$this->assertArrayHasKey('myField', $result);
$this->assertArrayHasKey('title', $result);
$this->assertArrayHasKey('author', $result);
$this->assertNotNull($result['author']);
$this->assertArrayHasKey('name', $result['author']);
}

/**
* Test autoFields in contain query builder
*
* @return void
*/
public function testAutoFieldsWithContainQueryBuilder() {
$table = TableRegistry::get('Articles');
$table->belongsTo('Authors');

$result = $table->find()
->select(['myField' => '(SELECT RAND())'])
->autoFields(true)
->hydrate(false)
->contain(['Authors' => function($q) {
return $q->select(['compute' => '2 + 20'])
->autoFields(true);
}])
->first();

$this->assertArrayHasKey('myField', $result);
$this->assertArrayHasKey('title', $result);
$this->assertArrayHasKey('author', $result);
$this->assertNotNull($result['author']);
$this->assertArrayHasKey('name', $result['author']);
$this->assertArrayHasKey('compute', $result);
}

}

0 comments on commit 44fee92

Please sign in to comment.