mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Merge pull request #11287 from chinpei215/2.x-hash-backport
[2.x] Backport Hash new features & bug fixes
This commit is contained in:
commit
7e35169652
2 changed files with 151 additions and 27 deletions
|
@ -1356,7 +1356,7 @@ class HashTest extends CakeTestCase {
|
||||||
);
|
);
|
||||||
$this->assertEquals($expected, $result);
|
$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(
|
$expected = array(
|
||||||
array('Item' => array('image' => 'img1.jpg')),
|
array('Item' => array('image' => 'img1.jpg')),
|
||||||
array('Item' => array('image' => 'img2.jpg')),
|
array('Item' => array('image' => 'img2.jpg')),
|
||||||
|
@ -1529,6 +1529,58 @@ class HashTest extends CakeTestCase {
|
||||||
$this->assertEquals($expected, $sorted);
|
$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()
|
* Test insert()
|
||||||
*
|
*
|
||||||
|
@ -1594,6 +1646,17 @@ class HashTest extends CakeTestCase {
|
||||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||||
);
|
);
|
||||||
$this->assertEquals($expected, $result);
|
$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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1686,6 +1749,43 @@ class HashTest extends CakeTestCase {
|
||||||
$this->assertEquals($expected, $result);
|
$this->assertEquals($expected, $result);
|
||||||
$result = Hash::remove($array, '{n}.{n}.part');
|
$result = Hash::remove($array, '{n}.{n}.part');
|
||||||
$this->assertEquals($expected, $result);
|
$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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1721,6 +1821,17 @@ class HashTest extends CakeTestCase {
|
||||||
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
4 => array('Item' => array('id' => 5, 'title' => 'fifth')),
|
||||||
);
|
);
|
||||||
$this->assertEquals($expected, $result);
|
$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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -91,8 +91,8 @@ class Hash {
|
||||||
*
|
*
|
||||||
* - `1.User.name` Get the name of the user at index 1.
|
* - `1.User.name` Get the name of the user at index 1.
|
||||||
* - `{n}.User.name` Get the name of every user in the set of users.
|
* - `{n}.User.name` Get the name of every user in the set of users.
|
||||||
* - `{n}.User[id]` Get the name of every user with an id key.
|
* - `{n}.User[id].name` Get the name of every user with an id key.
|
||||||
* - `{n}.User[id>=2]` Get the name of every user with an id key greater than or equal to 2.
|
* - `{n}.User[id>=2].name` Get the name of every user with an id key greater than or equal to 2.
|
||||||
* - `{n}.User[username=/^paul/]` Get User elements with username matching `^paul`.
|
* - `{n}.User[username=/^paul/]` Get User elements with username matching `^paul`.
|
||||||
*
|
*
|
||||||
* @param array $data The data to extract from.
|
* @param array $data The data to extract from.
|
||||||
|
@ -149,6 +149,7 @@ class Hash {
|
||||||
}
|
}
|
||||||
return $context[$_key];
|
return $context[$_key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split token conditions
|
* Split token conditions
|
||||||
*
|
*
|
||||||
|
@ -274,12 +275,10 @@ class Hash {
|
||||||
|
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
if (static::_matchToken($k, $token)) {
|
if (static::_matchToken($k, $token)) {
|
||||||
if ($conditions && static::_matches($v, $conditions)) {
|
if (!$conditions || static::_matches($v, $conditions)) {
|
||||||
$data[$k] = array_merge($v, $values);
|
$data[$k] = $nextPath
|
||||||
continue;
|
? static::insert($v, $nextPath, $values)
|
||||||
}
|
: array_merge($v, (array)$values);
|
||||||
if (!$conditions) {
|
|
||||||
$data[$k] = static::insert($v, $nextPath, $values);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,9 +300,6 @@ class Hash {
|
||||||
$count = count($path);
|
$count = count($path);
|
||||||
$last = $count - 1;
|
$last = $count - 1;
|
||||||
foreach ($path as $i => $key) {
|
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 ($op === 'insert') {
|
||||||
if ($i === $last) {
|
if ($i === $last) {
|
||||||
$_list[$key] = $values;
|
$_list[$key] = $values;
|
||||||
|
@ -318,7 +314,9 @@ class Hash {
|
||||||
}
|
}
|
||||||
} elseif ($op === 'remove') {
|
} elseif ($op === 'remove') {
|
||||||
if ($i === $last) {
|
if ($i === $last) {
|
||||||
unset($_list[$key]);
|
if (is_array($_list)) {
|
||||||
|
unset($_list[$key]);
|
||||||
|
}
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
if (!isset($_list[$key])) {
|
if (!isset($_list[$key])) {
|
||||||
|
@ -358,15 +356,21 @@ class Hash {
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
$match = static::_matchToken($k, $token);
|
$match = static::_matchToken($k, $token);
|
||||||
if ($match && is_array($v)) {
|
if ($match && is_array($v)) {
|
||||||
if ($conditions && static::_matches($v, $conditions)) {
|
if ($conditions) {
|
||||||
unset($data[$k]);
|
if (static::_matches($v, $conditions)) {
|
||||||
continue;
|
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])) {
|
if (empty($data[$k])) {
|
||||||
unset($data[$k]);
|
unset($data[$k]);
|
||||||
}
|
}
|
||||||
} elseif ($match && empty($nextPath)) {
|
} elseif ($match && $nextPath === '') {
|
||||||
unset($data[$k]);
|
unset($data[$k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,7 +458,7 @@ class Hash {
|
||||||
* The `$format` string can use any format options that `vsprintf()` and `sprintf()` do.
|
* The `$format` string can use any format options that `vsprintf()` and `sprintf()` do.
|
||||||
*
|
*
|
||||||
* @param array $data Source array from which to extract the data
|
* @param array $data Source array from which to extract the data
|
||||||
* @param string $paths An array containing one or more Hash::extract()-style key paths
|
* @param array $paths An array containing one or more Hash::extract()-style key paths
|
||||||
* @param string $format Format string into which values will be inserted, see sprintf()
|
* @param string $format Format string into which values will be inserted, see sprintf()
|
||||||
* @return array An array of strings extracted from `$path` and formatted with `$format`
|
* @return array An array of strings extracted from `$path` and formatted with `$format`
|
||||||
* @link https://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::format
|
* @link https://book.cakephp.org/2.0/en/core-utility-libraries/hash.html#Hash::format
|
||||||
|
@ -729,7 +733,7 @@ class Hash {
|
||||||
* Counts the dimensions of an array.
|
* Counts the dimensions of an array.
|
||||||
* Only considers the dimension of the first element in the array.
|
* Only considers the dimension of the first element in the array.
|
||||||
*
|
*
|
||||||
* If you have an un-even or heterogenous array, consider using Hash::maxDimensions()
|
* If you have an un-even or heterogeneous array, consider using Hash::maxDimensions()
|
||||||
* to get the dimensions of the array.
|
* to get the dimensions of the array.
|
||||||
*
|
*
|
||||||
* @param array $data Array to count dimensions on
|
* @param array $data Array to count dimensions on
|
||||||
|
@ -809,11 +813,15 @@ class Hash {
|
||||||
* You can easily count the results of an extract using apply().
|
* You can easily count the results of an extract using apply().
|
||||||
* For example to count the comments on an Article:
|
* For example to count the comments on an Article:
|
||||||
*
|
*
|
||||||
* `$count = Hash::apply($data, 'Article.Comment.{n}', 'count');`
|
* ```
|
||||||
|
* $count = Hash::apply($data, 'Article.Comment.{n}', 'count');
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
* You could also use a function like `array_sum` to sum the results.
|
* You could also use a function like `array_sum` to sum the results.
|
||||||
*
|
*
|
||||||
* `$total = Hash::apply($data, '{n}.Item.price', 'array_sum');`
|
* ```
|
||||||
|
* $total = Hash::apply($data, '{n}.Item.price', 'array_sum');
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
* @param array $data The data to reduce.
|
* @param array $data The data to reduce.
|
||||||
* @param string $path The path to extract from $data.
|
* @param string $path The path to extract from $data.
|
||||||
|
@ -833,7 +841,7 @@ class Hash {
|
||||||
* - `asc` Sort ascending.
|
* - `asc` Sort ascending.
|
||||||
* - `desc` Sort descending.
|
* - `desc` Sort descending.
|
||||||
*
|
*
|
||||||
* ## Sort types
|
* ### Sort types
|
||||||
*
|
*
|
||||||
* - `regular` For regular sorting (don't change types)
|
* - `regular` For regular sorting (don't change types)
|
||||||
* - `numeric` Compare values numerically
|
* - `numeric` Compare values numerically
|
||||||
|
@ -868,12 +876,18 @@ class Hash {
|
||||||
$data = array_values($data);
|
$data = array_values($data);
|
||||||
}
|
}
|
||||||
$sortValues = static::extract($data, $path);
|
$sortValues = static::extract($data, $path);
|
||||||
$sortCount = count($sortValues);
|
|
||||||
$dataCount = count($data);
|
$dataCount = count($data);
|
||||||
|
|
||||||
// Make sortValues match the data length, as some keys could be missing
|
// Make sortValues match the data length, as some keys could be missing
|
||||||
// the sorted value path.
|
// 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);
|
$sortValues = array_pad($sortValues, $dataCount, null);
|
||||||
}
|
}
|
||||||
$result = static::_squash($sortValues);
|
$result = static::_squash($sortValues);
|
||||||
|
@ -888,9 +902,8 @@ class Hash {
|
||||||
$type += array('ignoreCase' => false, 'type' => 'regular');
|
$type += array('ignoreCase' => false, 'type' => 'regular');
|
||||||
$ignoreCase = $type['ignoreCase'];
|
$ignoreCase = $type['ignoreCase'];
|
||||||
$type = $type['type'];
|
$type = $type['type'];
|
||||||
} else {
|
|
||||||
$type = strtolower($type);
|
|
||||||
}
|
}
|
||||||
|
$type = strtolower($type);
|
||||||
|
|
||||||
if ($type === 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) {
|
if ($type === 'natural' && version_compare(PHP_VERSION, '5.4.0', '<')) {
|
||||||
$type = 'regular';
|
$type = 'regular';
|
||||||
|
|
Loading…
Reference in a new issue