Skip to content

Commit

Permalink
Refactoring methods, adding self join association detection.
Browse files Browse the repository at this point in the history
Test cases updated.
  • Loading branch information
markstory committed May 10, 2009
1 parent 4b4875e commit 5c48603
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 53 deletions.
103 changes: 60 additions & 43 deletions cake/console/libs/tasks/model.php
Expand Up @@ -78,6 +78,15 @@ class ModelTask extends Shell {
**/
var $__validations = array();

/**
* startup method
*
* @return void
**/
function startup() {
App::import('Core', 'Model');
}

/**
* Execution method always used for tasks
*
Expand Down Expand Up @@ -127,13 +136,8 @@ function all() {
* @param string $className Name of class you want model to be.
* @return object Model instance
**/
function _getModelObject($className) {
if (App::import('Model', $className)) {
$object = new $className();
} else {
App::import('Model');
$object = new Model(array('name' => $className, 'ds' => $this->connection));
}
function &_getModelObject($className) {
$object = new Model(array('name' => $className, 'ds' => $this->connection));
return $object;
}
/**
Expand All @@ -159,7 +163,6 @@ function __interactive() {
$fullTableName = $db->fullTableName($useTable);

if (in_array($useTable, $this->__tables)) {
App::import('Model');
$tempModel = new Model(array('name' => $currentModelName, 'table' => $useTable, 'ds' => $this->connection));
$fields = $tempModel->schema();
if (!array_key_exists('id', $fields)) {
Expand Down Expand Up @@ -387,7 +390,6 @@ function doAssociations(&$model) {
if (!is_object($model)) {
return false;
}
App::import('Model');
$this->out(__('One moment while the associations are detected.', true));

$fields = $model->schema();
Expand Down Expand Up @@ -415,38 +417,7 @@ function doAssociations(&$model) {
} else {
$this->out(__('Please confirm the following associations:', true));
$this->hr();
foreach ($associations as $type => $settings) {
if (!empty($associations[$type])) {
$count = count($associations[$type]);
$response = 'y';
for ($i = 0; $i < $count; $i++) {
$prompt = "{$model->name} {$type} {$associations[$type][$i]['alias']}";
$response = $this->in("{$prompt}?", array('y','n'), 'y');

if ('n' == low($response) || 'no' == low($response)) {
unset($associations[$type][$i]);
} else {
if ($model->name === $associations[$type][$i]['alias']) {
if ($type === 'belongsTo') {
$alias = 'Parent' . $associations[$type][$i]['alias'];
}
if ($type === 'hasOne' || $type === 'hasMany') {
$alias = 'Child' . $associations[$type][$i]['alias'];
}

$alternateAlias = $this->in(sprintf(__('This is a self join. Use %s as the alias', true), $alias), array('y', 'n'), 'y');

if ('n' == low($alternateAlias) || 'no' == low($alternateAlias)) {
$associations[$type][$i]['alias'] = $this->in(__('Specify an alternate alias.', true));
} else {
$associations[$type][$i]['alias'] = $alias;
}
}
}
}
$associations[$type] = array_merge($associations[$type]);
}
}
$associations = $this->confirmAssociations($model, $associations);
}

$wannaDoMoreAssoc = $this->in(__('Would you like to define some additional model associations?', true), array('y','n'), 'n');
Expand Down Expand Up @@ -534,13 +505,19 @@ function findBelongsTo(&$model, $associations) {
$fields = $model->schema();
foreach ($fields as $fieldName => $field) {
$offset = strpos($fieldName, '_id');
if ($fieldName != $model->primaryKey && $offset !== false) {
if ($fieldName != $model->primaryKey && $fieldName != 'parent_id' && $offset !== false) {
$tmpModelName = $this->_modelNameFromKey($fieldName);
$associations['belongsTo'][] = array(
'alias' => $tmpModelName,
'className' => $tmpModelName,
'foreignKey' => $fieldName,
);
} elseif ($fieldName == 'parent_id') {
$associations['belongsTo'][] = array(
'alias' => 'Parent' . $model->name,
'className' => $model->name,
'foreignKey' => $fieldName,
);
}
}
return $associations;
Expand All @@ -561,16 +538,29 @@ function findHasOneAndMany(&$model, $associations) {

$pattern = '/_' . preg_quote($model->table, '/') . '|' . preg_quote($model->table, '/') . '_/';
$possibleJoinTable = preg_match($pattern , $otherTable);
if ($possibleJoinTable == true) {
continue;
}
foreach ($modelFieldsTemp as $fieldName => $field) {
if ($fieldName != $model->primaryKey && $fieldName == $foreignKey && $possibleJoinTable == false) {
$assoc = false;
if ($fieldName != $model->primaryKey && $fieldName == $foreignKey) {
$assoc = array(
'alias' => $tempOtherModel->name,
'className' => $tempOtherModel->name,
'foreignKey' => $fieldName
);
} elseif ($otherTable == $model->table && $fieldName == 'parent_id') {
$assoc = array(
'alias' => 'Child' . $model->name,
'className' => $model->name,
'foreignKey' => $fieldName
);
}
if ($assoc) {
$associations['hasOne'][] = $assoc;
$associations['hasMany'][] = $assoc;
}

}
}
return $associations;
Expand Down Expand Up @@ -615,6 +605,33 @@ function findHasAndBelongsToMany(&$model, $associations) {
}
return $associations;
}
/**
* Interact with the user and confirm associations.
*
* @param array $model Temporary Model instance.
* @param array $associations Array of associations to be confirmed.
* @return array Array of confirmed associations
**/
function confirmAssociations(&$model, $associations) {
foreach ($associations as $type => $settings) {
if (!empty($associations[$type])) {
$count = count($associations[$type]);
$response = 'y';
for ($i = 0; $i < $count; $i++) {
$prompt = "{$model->name} {$type} {$associations[$type][$i]['alias']}";
$response = $this->in("{$prompt}?", array('y','n'), 'y');

if ('n' == low($response)) {
unset($associations[$type][$i]);
} elseif ($type == 'hasMany') {
unset($associations['hasOne'][$i]);
}
}
$associations[$type] = array_merge($associations[$type]);
}
}
return $associations;
}

/**
* Assembles and writes a Model file.
Expand Down
74 changes: 64 additions & 10 deletions cake/tests/cases/console/libs/tasks/model.test.php
Expand Up @@ -39,6 +39,7 @@

if (!class_exists('ModelTask')) {
require CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'model.php';
require CAKE . 'console' . DS . 'libs' . DS . 'tasks' . DS . 'fixture.php';
}

Mock::generatePartial(
Expand All @@ -54,6 +55,10 @@
Mock::generate(
'Model', 'MockModelTaskModel'
);

Mock::generate(
'FixtureTask', 'MockModelTaskFixtureTask'
);
/**
* ModelTaskTest class
*
Expand All @@ -66,7 +71,7 @@ class ModelTaskTest extends CakeTestCase {
*
* @var array
**/
var $fixtures = array('core.article', 'core.comment', 'core.articles_tag', 'core.tag');
var $fixtures = array('core.article', 'core.comment', 'core.articles_tag', 'core.tag', 'core.category_thread');

/**
* setUp method
Expand Down Expand Up @@ -99,20 +104,22 @@ function endTest() {
function testListAll() {
$this->Task->expectAt(1, 'out', array('1. Article'));
$this->Task->expectAt(2, 'out', array('2. ArticlesTag'));
$this->Task->expectAt(3, 'out', array('3. Comment'));
$this->Task->expectAt(4, 'out', array('4. Tag'));
$this->Task->expectAt(3, 'out', array('3. CategoryThread'));
$this->Task->expectAt(4, 'out', array('4. Comment'));
$this->Task->expectAt(5, 'out', array('5. Tag'));
$result = $this->Task->listAll('test_suite');
$expected = array('articles', 'articles_tags', 'comments', 'tags');
$expected = array('articles', 'articles_tags', 'category_threads', 'comments', 'tags');
$this->assertEqual($result, $expected);

$this->Task->expectAt(6, 'out', array('1. Article'));
$this->Task->expectAt(7, 'out', array('2. ArticlesTag'));
$this->Task->expectAt(8, 'out', array('3. Comment'));
$this->Task->expectAt(9, 'out', array('4. Tag'));
$this->Task->expectAt(7, 'out', array('1. Article'));
$this->Task->expectAt(8, 'out', array('2. ArticlesTag'));
$this->Task->expectAt(9, 'out', array('3. CategoryThread'));
$this->Task->expectAt(10, 'out', array('4. Comment'));
$this->Task->expectAt(11, 'out', array('5. Tag'));

$this->Task->connection = 'test_suite';
$result = $this->Task->listAll();
$expected = array('articles', 'articles_tags', 'comments', 'tags');
$expected = array('articles', 'articles_tags', 'category_threads', 'comments', 'tags');
$this->assertEqual($result, $expected);
}

Expand All @@ -133,7 +140,7 @@ function testGetName() {
$expected = 'Article';
$this->assertEqual($result, $expected);

$this->Task->setReturnValueAt(2, 'in', 3);
$this->Task->setReturnValueAt(2, 'in', 4);
$result = $this->Task->getName('test_suite');
$expected = 'Comment';
$this->assertEqual($result, $expected);
Expand Down Expand Up @@ -319,6 +326,20 @@ function testBelongsToGeneration() {
)
);
$this->assertEqual($result, $expected);


$model = new Model(array('ds' => 'test_suite', 'name' => 'CategoryThread'));
$result = $this->Task->findBelongsTo($model, array());
$expected = array(
'belongsTo' => array(
array(
'alias' => 'ParentCategoryThread',
'className' => 'CategoryThread',
'foreignKey' => 'parent_id',
),
)
);
$this->assertEqual($result, $expected);
}

/**
Expand Down Expand Up @@ -348,6 +369,27 @@ function testHasManyHasOneGeneration() {
),
);
$this->assertEqual($result, $expected);


$model = new Model(array('ds' => 'test_suite', 'name' => 'CategoryThread'));
$result = $this->Task->findHasOneAndMany($model, array());
$expected = array(
'hasOne' => array(
array(
'alias' => 'ChildCategoryThread',
'className' => 'CategoryThread',
'foreignKey' => 'parent_id',
),
),
'hasMany' => array(
array(
'alias' => 'ChildCategoryThread',
'className' => 'CategoryThread',
'foreignKey' => 'parent_id',
),
)
);
$this->assertEqual($result, $expected);
}

/**
Expand All @@ -373,5 +415,17 @@ function testHasAndBelongsToManyGeneration() {
);
$this->assertEqual($result, $expected);
}

/**
* Ensure that the fixutre object is correctly called.
*
* @return void
**/
function testFixture() {
$this->Task->Fixture =& new MockModelTaskFixtureTask();
$this->Task->Fixture->expectAt(0, 'bake', array('Article', 'articles'));
$this->Task->fixture('Article', 'articles');
}

}
?>

0 comments on commit 5c48603

Please sign in to comment.