Refactoring find types in Model::find()

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6481 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
nate 2008-02-28 01:50:38 +00:00
parent 8b8b268c08
commit 3a11fe2340
4 changed files with 150 additions and 114 deletions

View file

@ -303,7 +303,7 @@ class AclShell extends Shell {
} else { } else {
$conditions = null; $conditions = null;
} }
$nodes = $this->Acl->{$class}->findAll($conditions, null, 'lft ASC'); $nodes = $this->Acl->{$class}->find('all', array('conditions' => $conditions, 'order' => 'lft ASC'));
if (empty($nodes)) { if (empty($nodes)) {
if (isset($this->args[1])) { if (isset($this->args[1])) {
$this->error(sprintf(__("%s not found", true), $this->args[1]), __("No tree returned.", true)); $this->error(sprintf(__("%s not found", true), $this->args[1]), __("No tree returned.", true));
@ -447,7 +447,7 @@ class AclShell extends Shell {
extract($this->__dataVars($this->args[0])); extract($this->__dataVars($this->args[0]));
$key = (ife(is_numeric($this->args[1]), $secondary_id, 'alias')); $key = (ife(is_numeric($this->args[1]), $secondary_id, 'alias'));
$conditions = array($class . '.' . $key => $this->args[1]); $conditions = array($class . '.' . $key => $this->args[1]);
$possibility = $this->Acl->{$class}->findAll($conditions); $possibility = $this->Acl->{$class}->find('all', compact('conditions'));
if (empty($possibility)) { if (empty($possibility)) {
$this->error(sprintf(__("%s not found", true), $this->args[1]), __("No tree returned.", true)); $this->error(sprintf(__("%s not found", true), $this->args[1]), __("No tree returned.", true));
} }

View file

@ -102,7 +102,7 @@ class ConsoleShell extends Shell {
$this->out(''); $this->out('');
$this->out('Model testing:'); $this->out('Model testing:');
$this->out('To test model results, use the name of your model without a leading $'); $this->out('To test model results, use the name of your model without a leading $');
$this->out('e.g. Foo->findAll()'); $this->out('e.g. Foo->find("all")');
$this->out(''); $this->out('');
$this->out('To dynamically set associations, you can do the following:'); $this->out('To dynamically set associations, you can do the following:');
$this->out("\tModelA bind <association> ModelB"); $this->out("\tModelA bind <association> ModelB");

View file

@ -1518,7 +1518,7 @@ class Model extends Overloadable {
if (isset($data['exclusive']) && $data['exclusive']) { if (isset($data['exclusive']) && $data['exclusive']) {
$model->deleteAll(array($field => $id)); $model->deleteAll(array($field => $id));
} else { } else {
$records = $model->findAll(array($field => $id), $model->primaryKey); $records = $model->find('all', array('conditions' => array($field => $id), 'fields' => $model->primaryKey));
if (!empty($records)) { if (!empty($records)) {
foreach ($records as $record) { foreach ($records as $record) {
@ -1543,12 +1543,14 @@ class Model extends Overloadable {
foreach ($this->hasAndBelongsToMany as $assoc => $data) { foreach ($this->hasAndBelongsToMany as $assoc => $data) {
if (isset($data['with'])) { if (isset($data['with'])) {
$model =& $this->{$data['with']}; $records = $this->{$data['with']}->find('all', array(
$records = $model->findAll(array($data['foreignKey'] => $id), $model->primaryKey, null, null, null, -1); 'conditions' => array($data['foreignKey'] => $id),
'fields' => $this->{$data['with']}->primaryKey,
'recursive' => -1
));
if (!empty($records)) { if (!empty($records)) {
foreach ($records as $record) { foreach ($records as $record) {
$model->delete($record[$model->alias][$model->primaryKey]); $this->{$data['with']}->delete($record[$this->{$data['with']}->alias][$this->{$data['with']}->primaryKey]);
} }
} }
} else { } else {
@ -1632,7 +1634,9 @@ class Model extends Overloadable {
if ($this->__exists !== null && $reset !== true) { if ($this->__exists !== null && $reset !== true) {
return $this->__exists; return $this->__exists;
} }
return $this->__exists = ($this->findCount(array($this->alias . '.' . $this->primaryKey => $this->getID()), -1) > 0); return $this->__exists = ($this->find('count', array(
'conditions' => array($this->alias . '.' . $this->primaryKey => $this->getID()), 'recursive' => -1
)) > 0);
} }
/** /**
* Returns true if a record that meets given conditions exists * Returns true if a record that meets given conditions exists
@ -1679,12 +1683,11 @@ class Model extends Overloadable {
$type = 'first'; $type = 'first';
$query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1)); $query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1));
} else { } else {
$type = $conditions; list($type, $query) = array($conditions, $fields);
$query = $fields;
} }
$this->findQueryType = $type;
$db =& ConnectionManager::getDataSource($this->useDbConfig); $db =& ConnectionManager::getDataSource($this->useDbConfig);
$this->findQueryType = $type;
$this->id = $this->getID(); $this->id = $this->getID();
$query = array_merge( $query = array_merge(
@ -1695,76 +1698,33 @@ class Model extends Overloadable {
$query $query
); );
switch ($type) { if ($type != 'all') {
case 'count' : if ($this->__findMethods[$type] === true) {
if (empty($query['fields'])) { $query = $this->{'_find' . ucfirst($type)}('before', $query);
$query['fields'] = 'COUNT(*) AS ' . $db->name('count');
} }
$query['order'] = false;
break;
case 'first' :
$query['limit'] = 1;
if (empty($query['conditions']) && !empty($this->id)) {
$query['conditions'] = array($this->escapeField() => $this->id);
}
break;
case 'list' :
if (empty($query['fields'])) {
$query['fields'] = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}");
$keyPath = "{n}.{$this->alias}.{$this->primaryKey}";
$valuePath = "{n}.{$this->alias}.{$this->displayField}";
$groupPath = null;
} else {
if (!is_array($query['fields'])) {
$query['fields'] = String::tokenize($query['fields']);
}
if (count($query['fields']) == 1) {
$keyPath = "{n}.{$this->alias}.{$this->primaryKey}";
$valuePath = '{n}.' . $query['fields'][0];
$groupPath = null;
$query['fields'] = array("{$this->alias}.{$this->primaryKey}", $query['fields'][0]);
} elseif (count($query['fields']) == 3) {
$keyPath = '{n}.' . $query['fields'][0];
$valuePath = '{n}.' . $query['fields'][1];
$groupPath = '{n}.' . $query['fields'][2];
} else {
$keyPath = '{n}.' . $query['fields'][0];
$valuePath = '{n}.' . $query['fields'][1];
$groupPath = null;
}
}
if (!isset($query['recursive']) || $query['recursive'] === null) {
$query['recursive'] = -1;
}
break;
} }
if (!is_numeric($query['page']) || intval($query['page']) < 1) { if (!is_numeric($query['page']) || intval($query['page']) < 1) {
$query['page'] = 1; $query['page'] = 1;
} }
if ($query['page'] > 1 && !empty($query['limit'])) {
if ($query['page'] > 1 && $query['limit'] != null) {
$query['offset'] = ($query['page'] - 1) * $query['limit']; $query['offset'] = ($query['page'] - 1) * $query['limit'];
} }
if ($query['order'] === null && $this->order !== null) {
if ($query['order'] == null && $query['order'] !== false) { $query['order'] = $this->order;
if ($this->order == null) {
$query['order'] = array();
} else {
$query['order'] = array($this->order);
} }
} else {
$query['order'] = array($query['order']); $query['order'] = array($query['order']);
}
$return = $this->Behaviors->trigger('beforeFind', array($query), array('break' => true, 'breakOn' => false, 'modParams' => true)); $return = $this->Behaviors->trigger('beforeFind', array($query), array('break' => true, 'breakOn' => false, 'modParams' => true));
$query = ife(is_array($return), $return, $query); $query = ife(is_array($return), $return, $query);
if ($return === false) { if ($return === false) {
return null; return null;
} }
$return = $this->beforeFind($query); $return = $this->beforeFind($query);
$query = ife(is_array($return), $return, $query); $query = ife(is_array($return), $return, $query);
if ($return === false) { if ($return === false) {
return null; return null;
} }
@ -1773,49 +1733,114 @@ class Model extends Overloadable {
$this->__resetAssociations(); $this->__resetAssociations();
$this->findQueryType = null; $this->findQueryType = null;
switch ($type) { if ($type === 'all') {
case 'all':
return $this->__filterResults($results); return $this->__filterResults($results);
break; } else {
case 'first': if ($this->__findMethods[$type] === true) {
return $this->{'_find' . ucfirst($type)}('after', $query, $results);
}
}
}
/**
* Handles the before/after filter logic for find('first') operations. Only called by Model::find().
*
* @param string $state Either "before" or "after"
* @param array $query
* @param array $data
* @return array
* @access protected
*/
function _findFirst($state, $query, $results = array()) {
if ($state == 'before') {
$query['limit'] = 1;
if (empty($query['conditions']) && !empty($this->id)) {
$query['conditions'] = array($this->escapeField() => $this->id);
}
return $query;
} elseif ($state == 'after') {
$results = $this->__filterResults($results); $results = $this->__filterResults($results);
if (empty($results[0])) { if (empty($results[0])) {
return false; return false;
} }
return $results[0]; return $results[0];
break; }
case 'count': }
/**
* Handles the before/after filter logic for find('count') operations. Only called by Model::find().
*
* @param string $state Either "before" or "after"
* @param array $query
* @param array $data
* @return int The number of records found, or false
* @access protected
*/
function _findCount($state, $query, $results = array()) {
if ($state == 'before') {
if (empty($query['fields'])) {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
$query['fields'] = 'COUNT(*) AS ' . $db->name('count');
}
$query['order'] = false;
return $query;
} elseif ($state == 'after') {
if (isset($results[0][0]['count'])) { if (isset($results[0][0]['count'])) {
return intval($results[0][0]['count']); return intval($results[0][0]['count']);
} elseif (isset($results[0][$this->alias]['count'])) { } elseif (isset($results[0][$this->alias]['count'])) {
return intval($results[0][$this->alias]['count']); return intval($results[0][$this->alias]['count']);
} }
return false; return false;
break;
case 'list':
if (empty($results)) {
return array();
}
return Set::combine($this->__filterResults($results), $keyPath, $valuePath, $groupPath);
break;
} }
} }
/** /**
* Returns a resultset array with specified fields from database matching given conditions. * Handles the before/after filter logic for find('list') operations. Only called by Model::find().
* By using the $recursive parameter, the call can access further "levels of association" than
* the ones this model is directly associated to.
* *
* @param mixed $conditions SQL conditions as a string or as an array('field' =>'value',...) * @param string $state Either "before" or "after"
* @param mixed $fields Either a single string of a field name, or an array of field names * @param array $query
* @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC") * @param array $data
* @param integer $limit SQL LIMIT clause, for calculating items per page. * @return array Key/value pairs of primary keys/display field values of all records found
* @param integer $page Page number, for accessing paged data * @access protected
* @param integer $recursive The number of levels deep to fetch associated records */
* @return array Array of records function _findList($state, $query, $results = array()) {
* @access public if ($state == 'before') {
* @see Model::find() if (empty($query['fields'])) {
$query['fields'] = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}");
$list = array("{n}.{$this->alias}.{$this->primaryKey}", "{n}.{$this->alias}.{$this->displayField}", null);
} else {
if (!is_array($query['fields'])) {
$query['fields'] = String::tokenize($query['fields']);
}
if (count($query['fields']) == 1) {
$list = array("{n}.{$this->alias}.{$this->primaryKey}", '{n}.' . $query['fields'][0], null);
$query['fields'] = array("{$this->alias}.{$this->primaryKey}", $query['fields'][0]);
} elseif (count($query['fields']) == 3) {
$list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], '{n}.' . $query['fields'][2]);
} else {
$list = array('{n}.' . $query['fields'][0], '{n}.' . $query['fields'][1], null);
}
}
if (!isset($query['recursive']) || $query['recursive'] === null) {
$query['recursive'] = -1;
}
list($query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']) = $list;
return $query;
} elseif ($state == 'after') {
if (empty($results)) {
return array();
}
return Set::combine(
$this->__filterResults($results),
$query['list']['keyPath'],
$query['list']['valuePath'],
$query['list']['groupPath']
);
}
}
/**
* @deprecated
* @see Model::find('all')
*/ */
function findAll($conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) { function findAll($conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
//trigger_error(__('(Model::findAll) Deprecated, use Model::find("all")', true), E_USER_WARNING);
return $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive')); return $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'));
} }
/** /**
@ -1886,15 +1911,11 @@ class Model extends Overloadable {
return $data; return $data;
} }
/** /**
* Returns number of rows matching given SQL condition. * @deprecated
* * @see Model::find('count')
* @param array $conditions SQL conditions array for findAll
* @param integer $recursive The number of levels deep to fetch associated records
* @return integer Number of matching rows
* @access public
* @see Model::find()
*/ */
function findCount($conditions = null, $recursive = 0) { function findCount($conditions = null, $recursive = 0) {
//trigger_error(__('(Model::findCount) Deprecated, use Model::find("count")', true), E_USER_WARNING);
return $this->find('count', compact('conditions', 'recursive')); return $this->find('count', compact('conditions', 'recursive'));
} }
/** /**
@ -1987,7 +2008,7 @@ class Model extends Overloadable {
* which is useful when creating paged lists. * which is useful when creating paged lists.
* *
* @param string $conditions SQL conditions for matching rows * @param string $conditions SQL conditions for matching rows
* @param string $field Field name (parameter for findAll) * @param string $field Field name (parameter for find())
* @param integer $value Value from where to find neighbours * @param integer $value Value from where to find neighbours
* @return array Array with keys "prev" and "next" that holds the id's * @return array Array with keys "prev" and "next" that holds the id's
* @access public * @access public
@ -2006,7 +2027,6 @@ class Model extends Overloadable {
@list($prev) = $this->findAll(array_filter(array_merge($conditions, array($field => '< ' . $value))), $fields, $field . ' DESC', 1, null, 0); @list($prev) = $this->findAll(array_filter(array_merge($conditions, array($field => '< ' . $value))), $fields, $field . ' DESC', 1, null, 0);
@list($next) = $this->findAll(array_filter(array_merge($conditions, array($field => '> ' . $value))), $fields, $field . ' ASC', 1, null, 0); @list($next) = $this->findAll(array_filter(array_merge($conditions, array($field => '> ' . $value))), $fields, $field . ' ASC', 1, null, 0);
return compact('prev', 'next'); return compact('prev', 'next');
} }
/** /**
@ -2258,7 +2278,11 @@ class Model extends Overloadable {
return false; return false;
} }
/**
* Top secret
*
* @access public
*/
function normalizeFindParams($type, $data, $altType = null, $r = array(), $_this = null) { function normalizeFindParams($type, $data, $altType = null, $r = array(), $_this = null) {
if ($_this == null) { if ($_this == null) {
$_this = $this; $_this = $this;
@ -2303,7 +2327,6 @@ class Model extends Overloadable {
if (isset($root)) { if (isset($root)) {
return array($this->name => $r); return array($this->name => $r);
} }
return $r; return $r;
} }
/** /**
@ -2452,7 +2475,7 @@ class Model extends Overloadable {
return true; return true;
} }
/** /**
* After find callback. Can be used to modify any results returned by find and findAll. * After find callback. Can be used to modify any results returned by find().
* *
* @param mixed $results The results of the find operation * @param mixed $results The results of the find operation
* @param boolean $primary Whether this model is being queried directly (vs. being queried as an association) * @param boolean $primary Whether this model is being queried directly (vs. being queried as an association)

View file

@ -675,6 +675,19 @@ class ModelTest extends CakeTestCase {
$this->assertEqual($result, $expected); $this->assertEqual($result, $expected);
} }
function testRecordExists() {
$this->loadFixtures('User');
$this->model =& new User();
$this->assertFalse($this->model->exists());
$this->model->read(null, 1);
$this->assertTrue($this->model->exists());
$this->model->create();
$this->assertFalse($this->model->exists());
$this->model->id = 4;
$this->assertTrue($this->model->exists());
}
function testFindField() { function testFindField() {
$this->loadFixtures('User'); $this->loadFixtures('User');
$this->model =& new User(); $this->model =& new User();