Skip to content

Commit

Permalink
Backport #7080, #8233 and #11060
Browse files Browse the repository at this point in the history
  • Loading branch information
chinpei215 committed Oct 6, 2017
1 parent ccf634e commit deac8f9
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 20 deletions.
113 changes: 112 additions & 1 deletion lib/Cake/Test/Case/Utility/HashTest.php
Expand Up @@ -1356,7 +1356,7 @@ public function testSortNaturalIgnoreCase() {
);
$this->assertEquals($expected, $result);

$result = Hash::sort($items, '{n}.Item.image', 'asc', array('type' => 'natural', 'ignoreCase' => true));
$result = Hash::sort($items, '{n}.Item.image', 'asc', array('type' => 'NATURAL', 'ignoreCase' => true));
$expected = array(
array('Item' => array('image' => 'img1.jpg')),
array('Item' => array('image' => 'img2.jpg')),
Expand Down Expand Up @@ -1529,6 +1529,58 @@ public function testSortRegularIgnoreCase() {
$this->assertEquals($expected, $sorted);
}

/**
* Test sorting on a nested key that is sometimes undefined.
*
* @return void
*/
public function testSortSparse() {
$data = array(
array(
'id' => 1,
'title' => 'element 1',
'extra' => 1,
),
array(
'id' => 2,
'title' => 'element 2',
'extra' => 2,
),
array(
'id' => 3,
'title' => 'element 3',
),
array(
'id' => 4,
'title' => 'element 4',
'extra' => 4,
)
);
$result = Hash::sort($data, '{n}.extra', 'desc', 'natural');
$expected = array(
array(
'id' => 4,
'title' => 'element 4',
'extra' => 4,
),
array(
'id' => 2,
'title' => 'element 2',
'extra' => 2,
),
array(
'id' => 1,
'title' => 'element 1',
'extra' => 1,
),
array(
'id' => 3,
'title' => 'element 3',
),
);
$this->assertSame($expected, $result);
}

/**
* Test insert()
*
Expand Down Expand Up @@ -1594,6 +1646,17 @@ public function testInsertMulti() {
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
);
$this->assertEquals($expected, $result);

$data[3]['testable'] = true;
$result = Hash::insert($data, '{n}[testable].Item[id=/\b2|\b4/].test', 2);
$expected = array(
0 => array('Item' => array('id' => 1, 'title' => 'first')),
1 => array('Item' => array('id' => 2, 'title' => 'second')),
2 => array('Item' => array('id' => 3, 'title' => 'third')),
3 => array('Item' => array('id' => 4, 'title' => 'fourth', 'test' => 2), 'testable' => true),
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
);
$this->assertEquals($expected, $result);
}

/**
Expand Down Expand Up @@ -1686,6 +1749,43 @@ public function testRemove() {
$this->assertEquals($expected, $result);
$result = Hash::remove($array, '{n}.{n}.part');
$this->assertEquals($expected, $result);

$array = array(
'foo' => 'string',
);
$expected = $array;
$result = Hash::remove($array, 'foo.bar');
$this->assertEquals($expected, $result);

$array = array(
'foo' => 'string',
'bar' => array(
0 => 'a',
1 => 'b',
),
);
$expected = array(
'foo' => 'string',
'bar' => array(
1 => 'b',
),
);
$result = Hash::remove($array, '{s}.0');
$this->assertEquals($expected, $result);

$array = array(
'foo' => array(
0 => 'a',
1 => 'b',
),
);
$expected = array(
'foo' => array(
1 => 'b',
),
);
$result = Hash::remove($array, 'foo[1=b].0');
$this->assertEquals($expected, $result);
}

/**
Expand Down Expand Up @@ -1721,6 +1821,17 @@ public function testRemoveMulti() {
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
);
$this->assertEquals($expected, $result);

$data[3]['testable'] = true;
$result = Hash::remove($data, '{n}[testable].Item[id=/\b2|\b4/].title');
$expected = array(
0 => array('Item' => array('id' => 1, 'title' => 'first')),
1 => array('Item' => array('id' => 2, 'title' => 'second')),
2 => array('Item' => array('id' => 3, 'title' => 'third')),
3 => array('Item' => array('id' => 4), 'testable' => true),
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
);
$this->assertEquals($expected, $result);
}

/**
Expand Down
46 changes: 27 additions & 19 deletions lib/Cake/Utility/Hash.php
Expand Up @@ -275,12 +275,10 @@ public static function insert(array $data, $path, $values = null) {

foreach ($data as $k => $v) {
if (static::_matchToken($k, $token)) {
if ($conditions && static::_matches($v, $conditions)) {
$data[$k] = array_merge($v, $values);
continue;
}
if (!$conditions) {
$data[$k] = static::insert($v, $nextPath, $values);
if (!$conditions || static::_matches($v, $conditions)) {
$data[$k] = $nextPath
? static::insert($v, $nextPath, $values)
: array_merge($v, (array)$values);
}
}
}
Expand All @@ -302,9 +300,6 @@ protected static function _simpleOp($op, $data, $path, $values = null) {
$count = count($path);
$last = $count - 1;
foreach ($path as $i => $key) {
if ((is_numeric($key) && intval($key) > 0 || $key === '0') && strpos($key, '0') !== 0) {
$key = (int)$key;
}
if ($op === 'insert') {
if ($i === $last) {
$_list[$key] = $values;
Expand All @@ -319,7 +314,9 @@ protected static function _simpleOp($op, $data, $path, $values = null) {
}
} elseif ($op === 'remove') {
if ($i === $last) {
unset($_list[$key]);
if (is_array($_list)) {
unset($_list[$key]);
}
return $data;
}
if (!isset($_list[$key])) {
Expand Down Expand Up @@ -359,15 +356,21 @@ public static function remove(array $data, $path) {
foreach ($data as $k => $v) {
$match = static::_matchToken($k, $token);
if ($match && is_array($v)) {
if ($conditions && static::_matches($v, $conditions)) {
unset($data[$k]);
continue;
if ($conditions) {
if (static::_matches($v, $conditions)) {
if ($nextPath !== '') {
$data[$k] = static::remove($v, $nextPath);
} else {
unset($data[$k]);
}
}
} else {
$data[$k] = static::remove($v, $nextPath);
}
$data[$k] = static::remove($v, $nextPath);
if (empty($data[$k])) {
unset($data[$k]);
}
} elseif ($match && empty($nextPath)) {
} elseif ($match && $nextPath === '') {
unset($data[$k]);
}
}
Expand Down Expand Up @@ -873,12 +876,18 @@ public static function sort(array $data, $path, $dir = 'asc', $type = 'regular')
$data = array_values($data);
}
$sortValues = static::extract($data, $path);
$sortCount = count($sortValues);
$dataCount = count($data);

// Make sortValues match the data length, as some keys could be missing
// the sorted value path.
if ($sortCount < $dataCount) {
$missingData = count($sortValues) < $dataCount;
if ($missingData && $numeric) {
// Get the path without the leading '{n}.'
$itemPath = substr($path, 4);
foreach ($data as $key => $value) {
$sortValues[$key] = static::get($value, $itemPath);
}
} elseif ($missingData) {
$sortValues = array_pad($sortValues, $dataCount, null);
}
$result = static::_squash($sortValues);
Expand All @@ -893,9 +902,8 @@ public static function sort(array $data, $path, $dir = 'asc', $type = 'regular')
$type += array('ignoreCase' => false, 'type' => 'regular');
$ignoreCase = $type['ignoreCase'];
$type = $type['type'];
} else {
$type = strtolower($type);
}
$type = strtolower($type);

if ($type === 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) {
$type = 'regular';
Expand Down

0 comments on commit deac8f9

Please sign in to comment.