Applying patch from 'Justas Butkus' to fix CakeSchema::compare()

Fixes issues with comparing null == '' and adds a new protected method to handle null aware array difference generation.
Tests added.
Fixes #1206
This commit is contained in:
mark_story 2010-10-27 23:03:31 -04:00
parent 16387f1961
commit f5fd069583
2 changed files with 75 additions and 6 deletions

View file

@ -468,11 +468,11 @@ class CakeSchema extends Object {
if (!array_key_exists($table, $old)) { if (!array_key_exists($table, $old)) {
$tables[$table]['add'] = $fields; $tables[$table]['add'] = $fields;
} else { } else {
$diff = array_diff_assoc($fields, $old[$table]); $diff = $this->_arrayDiffAssoc($fields, $old[$table]);
if (!empty($diff)) { if (!empty($diff)) {
$tables[$table]['add'] = $diff; $tables[$table]['add'] = $diff;
} }
$diff = array_diff_assoc($old[$table], $fields); $diff = $this->_arrayDiffAssoc($old[$table], $fields);
if (!empty($diff)) { if (!empty($diff)) {
$tables[$table]['drop'] = $diff; $tables[$table]['drop'] = $diff;
} }
@ -480,7 +480,7 @@ class CakeSchema extends Object {
foreach ($fields as $field => $value) { foreach ($fields as $field => $value) {
if (isset($old[$table][$field])) { if (isset($old[$table][$field])) {
$diff = array_diff_assoc($value, $old[$table][$field]); $diff = $this->_arrayDiffAssoc($value, $old[$table][$field]);
if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') { if (!empty($diff) && $field !== 'indexes' && $field !== 'tableParameters') {
$tables[$table]['change'][$field] = array_merge($old[$table][$field], $diff); $tables[$table]['change'][$field] = array_merge($old[$table][$field], $diff);
} }
@ -520,6 +520,46 @@ class CakeSchema extends Object {
return $tables; return $tables;
} }
/**
* Extended array_diff_assoc noticing change from/to NULL values
*
* It behaves almost the same way as array_diff_assoc except for NULL values: if
* one of the values is not NULL - change is detected. It is useful in situation
* where one value is strval('') ant other is strval(null) - in string comparing
* methods this results as EQUAL, while it is not.
*
* @param array $array1 Base array
* @param array $array2 Corresponding array checked for equality
* @return array Difference as array with array(keys => values) from input array
* where match was not found.
* @access protected
*/
function _arrayDiffAssoc($array1, $array2) {
$difference = array();
foreach ($array1 as $key => $value) {
if (!array_key_exists($key, $array2)) {
$difference[$key] = $value;
continue;
}
$correspondingValue = $array2[$key];
if (is_null($value) !== is_null($correspondingValue)) {
$difference[$key] = $value;
continue;
}
if (is_bool($value) !== is_bool($correspondingValue)) {
$difference[$key] = $value;
continue;
}
$value = strval($value);
$correspondingValue = strval($correspondingValue);
if ($value === $correspondingValue) {
continue;
}
$difference[$key] = $value;
}
return $difference;
}
/** /**
* Formats Schema columns from Model Object * Formats Schema columns from Model Object
* *
@ -596,7 +636,7 @@ class CakeSchema extends Object {
if (!is_array($new) || !is_array($old)) { if (!is_array($new) || !is_array($old)) {
return false; return false;
} }
$change = array_diff_assoc($new, $old); $change = $this->_arrayDiffAssoc($new, $old);
return $change; return $change;
} }
@ -614,12 +654,12 @@ class CakeSchema extends Object {
$add = $drop = array(); $add = $drop = array();
$diff = array_diff_assoc($new, $old); $diff = $this->_arrayDiffAssoc($new, $old);
if (!empty($diff)) { if (!empty($diff)) {
$add = $diff; $add = $diff;
} }
$diff = array_diff_assoc($old, $new); $diff = $this->_arrayDiffAssoc($old, $new);
if (!empty($diff)) { if (!empty($diff)) {
$drop = $diff; $drop = $diff;
} }

View file

@ -798,6 +798,35 @@ class CakeSchemaTest extends CakeTestCase {
$this->assertEqual($expected, $compare); $this->assertEqual($expected, $compare);
} }
/**
* test comparing '' and null and making sure they are different.
*
* @return void
*/
function testCompareEmptyStringAndNull() {
$One =& new CakeSchema(array(
'posts' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'name' => array('type' => 'string', 'null' => false, 'default' => '')
)
));
$Two =& new CakeSchema(array(
'posts' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'name' => array('type' => 'string', 'null' => false, 'default' => null)
)
));
$compare = $One->compare($Two);
$expected = array(
'posts' => array(
'change' => array(
'name' => array('type' => 'string', 'null' => false, 'default' => null)
)
)
);
$this->assertEqual($expected, $compare);
}
/** /**
* Test comparing tableParameters and indexes. * Test comparing tableParameters and indexes.
* *