Fixing HABTM associations on non-standard keys, fixes #4219, refactoring DboSource::calculate()

git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@6565 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
nate 2008-03-13 03:11:29 +00:00
parent 3ff5bfa829
commit 360b91eea7
9 changed files with 132 additions and 36 deletions

View file

@ -783,7 +783,7 @@ class TreeBehavior extends ModelBehavior {
*/
function __getMax($model, $scope, $right) {
$db =& ConnectionManager::getDataSource($model->useDbConfig);
list($edge) = array_values($model->find('first', array('conditions' => $scope, 'fields' => $db->calculate('max', array($right)), 'recursive' => -1)));
list($edge) = array_values($model->find('first', array('conditions' => $scope, 'fields' => $db->calculate($model, 'max', array($right)), 'recursive' => -1)));
return ife(empty ($edge[$right]), 0, $edge[$right]);
}
/**

View file

@ -697,7 +697,6 @@ class DboSource extends DataSource {
if (!empty($fetch) && is_array($fetch)) {
if ($recursive > 0) {
foreach ($linkModel->__associations as $type1) {
foreach ($linkModel->{$type1} as $assoc1 => $assocData1) {
$deepModel =& $linkModel->{$assoc1};
@ -733,8 +732,8 @@ class DboSource extends DataSource {
$joinKeys = array($foreignKey, $model->hasAndBelongsToMany[$association]['associationForeignKey']);
list($with, $habtmFields) = $model->joinModel($model->hasAndBelongsToMany[$association]['with'], $joinKeys);
$habtmFieldsCount = count($habtmFields);
$q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack);
if ($q != false) {
$fetch = $this->fetchAll($q, $model->cacheQueries, $model->alias);
} else {
@ -775,14 +774,19 @@ class DboSource extends DataSource {
}
}
if ($type == 'hasAndBelongsToMany') {
$merge = array();
$uniqueIds = $merge = array();
foreach($fetch as $j => $data) {
if (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey]) {
if ($habtmFieldsCount > 2) {
$merge[] = $data;
} else {
$merge[] = Set::diff($data, array($with => $data[$with]));
if (
(isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey]) &&
(!in_array($data[$with][$joinKeys[1]], $uniqueIds))
) {
$uniqueIds[] = $data[$with][$joinKeys[1]];
if ($habtmFieldsCount <= 2) {
unset($data[$with]);
}
$merge[] = $data;
}
}
if (empty($merge) && !isset($row[$association])) {
@ -1358,12 +1362,13 @@ class DboSource extends DataSource {
/**
* Returns the an SQL calculation, i.e. COUNT() or MAX()
*
* @param model $model
* @param string $func Lowercase name of SQL function, i.e. 'count' or 'max'
* @param array $params Function parameters (any values must be quoted manually)
* @return string An SQL calculation function
* @access public
*/
function calculate($func, $params = array()) {
function calculate(&$model, $func, $params = array()) {
switch (strtolower($func)) {
case 'count':

View file

@ -1331,11 +1331,11 @@ class Model extends Overloadable {
break;
default:
if ($options['atomic']) {
if ($validates) {
return ($db->commit($this) !== false);
} else {
$db->rollback($this);
if ($validates && ($db->commit($this) !== false)) {
return true;
}
$db->rollback($this);
return false;
}
return $validates;
break;
@ -1779,7 +1779,7 @@ class Model extends Overloadable {
if ($state == 'before') {
if (empty($query['fields'])) {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
$query['fields'] = $db->calculate('count');
$query['fields'] = $db->calculate($this, 'count');
}
$query['order'] = false;
return $query;

View file

@ -2139,25 +2139,25 @@ class DboSourceTest extends CakeTestCase {
}
function testCalculations() {
$result = $this->db->calculate('count');
$result = $this->db->calculate($this->Model, 'count');
$this->assertEqual($result, 'COUNT(*) AS `count`');
$result = $this->db->calculate('count', array('id'));
$result = $this->db->calculate($this->Model, 'count', array('id'));
$this->assertEqual($result, 'COUNT(`id`) AS `count`');
$result = $this->db->calculate('count', array('id', 'id_count'));
$result = $this->db->calculate($this->Model, 'count', array('id', 'id_count'));
$this->assertEqual($result, 'COUNT(`id`) AS `id_count`');
$result = $this->db->calculate('count', array('Model.id', 'id_count'));
$result = $this->db->calculate($this->Model, 'count', array('Model.id', 'id_count'));
$this->assertEqual($result, 'COUNT(`Model`.`id`) AS `id_count`');
$result = $this->db->calculate('max', array('id'));
$result = $this->db->calculate($this->Model, 'max', array('id'));
$this->assertEqual($result, 'MAX(`id`) AS `id`');
$result = $this->db->calculate('max', array('Model.id', 'id'));
$result = $this->db->calculate($this->Model, 'max', array('Model.id', 'id'));
$this->assertEqual($result, 'MAX(`Model`.`id`) AS `id`');
$result = $this->db->calculate('max', array('`Model`.`id`', 'id'));
$result = $this->db->calculate($this->Model, 'max', array('`Model`.`id`', 'id'));
$this->assertEqual($result, 'MAX(`Model`.`id`) AS `id`');
}
}

View file

@ -48,7 +48,7 @@ class ModelTest extends CakeTestCase {
'core.syfile', 'core.image', 'core.device_type', 'core.device_type_category', 'core.feature_set', 'core.exterior_type_category',
'core.document', 'core.device', 'core.document_directory', 'core.primary_model', 'core.secondary_model', 'core.something',
'core.something_else', 'core.join_thing', 'core.join_a', 'core.join_b', 'core.join_c', 'core.join_a_b', 'core.join_a_c',
'core.uuid'
'core.uuid', 'core.data_test', 'core.posts_tag'
);
function start() {
@ -2980,12 +2980,46 @@ class ModelTest extends CakeTestCase {
}
function testZeroDefaultFieldValue() {
$this->loadFixtures('Uuid');
$this->model =& new Uuid();
$this->loadFixtures('DataTest');
$this->model =& new DataTest();
$this->model->create() && $this->model->save();
$this->model->create(array('float' => '')) && $this->model->save();
$result = $this->model->findById($this->model->id);
$this->assertIdentical($result['Uuid']['count'], '0');
$this->assertIdentical($result['DataTest']['count'], '0');
$this->assertIdentical($result['DataTest']['float'], '0');
}
function testNonNumericHabtmJoinKey() {
$this->loadFixtures('Post', 'Tag', 'PostsTag');
$this->Post =& new Post();
$this->Post->bind('Tag', array('type' => 'hasAndBelongsToMany'));
$this->Post->Tag->primaryKey = 'tag';
$result = $this->Post->find('all');
$expected = array(
array(
'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post', 'body' => 'First Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'),
'Author' => array('id' => null, 'user' => null, 'password' => null, 'created' => null, 'updated' => null, 'test' => 'working'),
'Tag' => array(
array('id' => '1', 'tag' => 'tag1', 'created' => '2007-03-18 12:22:23', 'updated' => '2007-03-18 12:24:31'),
array('id' => '2', 'tag' => 'tag2', 'created' => '2007-03-18 12:24:23', 'updated' => '2007-03-18 12:26:31'),
)
),
array(
'Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Second Post', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'),
'Author' => array('id' => null, 'user' => null, 'password' => null, 'created' => null, 'updated' => null, 'test' => 'working'),
'Tag' => array(
array('id' => '1', 'tag' => 'tag1', 'created' => '2007-03-18 12:22:23', 'updated' => '2007-03-18 12:24:31'),
array('id' => '3', 'tag' => 'tag3', 'created' => '2007-03-18 12:26:23', 'updated' => '2007-03-18 12:28:31')
)
),
array(
'Post' => array('id' => '3', 'author_id' => '1', 'title' => 'Third Post', 'body' => 'Third Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
'Author' => array('id' => null, 'user' => null, 'password' => null, 'created' => null, 'updated' => null, 'test' => 'working'),
'Tag' => array()
)
);
$this->assertEqual($result, $expected);
}
function testAfterFindAssociation() {

View file

@ -503,6 +503,15 @@ class Callback extends CakeTestModel {
class Uuid extends CakeTestModel {
var $name = 'Uuid';
}
/**
* Short description for class.
*
* @package cake.tests
* @subpackage cake.tests.cases.libs.model
*/
class DataTest extends CakeTestModel {
var $name = 'DataTest';
}
/**
* Short description for class.
*

View file

@ -97,8 +97,8 @@ class TestAppSchema extends CakeSchema {
var $posts_tags = array(
'post_id' => array('type' => 'integer', 'null' => false, 'key' => 'primary'),
'tag_id' => array('type' => 'integer', 'null' => false, 'key' => 'primary'),
'indexes' => array('UNIQUE_TAG' => array('column'=> array('post_id', 'tag_id'), 'unique'=>1))
'tag_id' => array('type' => 'string', 'null' => false),
'indexes' => array()
);
var $tags = array(

View file

@ -0,0 +1,48 @@
<?php
/* SVN FILE: $Id: data_test_fixture.php 6354 2008-01-10 07:02:33Z nate $ */
/**
* Short description for file.
*
* Long description for file
*
* PHP versions 4 and 5
*
* CakePHP(tm) Tests <https://trac.cakephp.org/wiki/Developement/TestSuite>
* Copyright 2005-2008, Cake Software Foundation, Inc.
* 1785 E. Sahara Avenue, Suite 490-204
* Las Vegas, Nevada 89104
*
* Licensed under The Open Group Test Suite License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc.
* @link https://trac.cakephp.org/wiki/Developement/TestSuite CakePHP(tm) Tests
* @package cake.tests
* @subpackage cake.tests.fixtures
* @since CakePHP(tm) v 1.2.0.6700
* @version $Revision: 6354 $
* @modifiedby $LastChangedBy: nate $
* @lastmodified $Date: 2008-01-10 02:02:33 -0500 (Thu, 10 Jan 2008) $
* @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
*/
/**
* Short description for class.
*
* @package cake.tests
* @subpackage cake.tests.fixtures
*/
class DataTestFixture extends CakeTestFixture {
var $name = 'DataTest';
var $fields = array(
'id' => array('type' => 'integer', 'key' => 'primary'),
'count' => array('type' => 'integer', 'default' => 0),
'float' => array('type' => 'float', 'default' => 0),
//'timestamp' => array('type' => 'timestamp', 'default' => null, 'null' => true),
'created' => array('type' => 'datetime', 'default' => null),
'updated' => array('type' => 'datetime', 'default' => null)
);
var $records = array();
}
?>

View file

@ -36,14 +36,14 @@ class PostsTagFixture extends CakeTestFixture {
var $name = 'PostsTag';
var $fields = array(
'post_id' => array('type' => 'integer', 'null' => false),
'tag_id' => array('type' => 'integer', 'null' => false),
'indexes' => array('UNIQUE_TAG' => array('column'=> array('post_id', 'tag_id'), 'unique'=> 1))
'tag_id' => array('type' => 'string', 'null' => false),
);
var $records = array(
array('post_id' => 1, 'tag_id' => 1),
array('post_id' => 1, 'tag_id' => 2),
array('post_id' => 2, 'tag_id' => 1),
array('post_id' => 2, 'tag_id' => 3)
array('post_id' => 1, 'tag_id' => 'tag1'),
array('post_id' => 1, 'tag_id' => 'tag2'),
array('post_id' => 2, 'tag_id' => 'tag1'),
array('post_id' => 2, 'tag_id' => 'tag3')
);
}