|
|
@@ -18,6 +18,13 @@ namespace Cake\Utility;
|
|
|
use ArrayAccess;
|
|
|
use InvalidArgumentException;
|
|
|
use RuntimeException;
|
|
|
+use const SORT_ASC;
|
|
|
+use const SORT_DESC;
|
|
|
+use const SORT_LOCALE_STRING;
|
|
|
+use const SORT_NATURAL;
|
|
|
+use const SORT_NUMERIC;
|
|
|
+use const SORT_REGULAR;
|
|
|
+use const SORT_STRING;
|
|
|
|
|
|
/**
|
|
|
* Library of array functions for manipulating and extracting data
|
|
|
@@ -46,28 +53,15 @@ class Hash
|
|
|
* @return mixed The value fetched from the array, or null.
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::get
|
|
|
*/
|
|
|
- public static function get($data, $path, $default = null)
|
|
|
+ public static function get(ArrayAccess|array $data, array|string|int|null $path, mixed $default = null): mixed
|
|
|
{
|
|
|
- if (!(is_array($data) || $data instanceof ArrayAccess)) {
|
|
|
- throw new InvalidArgumentException(
|
|
|
- 'Invalid data type, must be an array or \ArrayAccess instance.'
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
if (empty($data) || $path === null) {
|
|
|
return $default;
|
|
|
}
|
|
|
|
|
|
- if (is_string($path) || is_numeric($path)) {
|
|
|
+ if (is_string($path) || is_int($path)) {
|
|
|
$parts = explode('.', (string)$path);
|
|
|
} else {
|
|
|
- if (!is_array($path)) {
|
|
|
- throw new InvalidArgumentException(sprintf(
|
|
|
- 'Invalid Parameter %s, should be dot separated path or array.',
|
|
|
- $path
|
|
|
- ));
|
|
|
- }
|
|
|
-
|
|
|
$parts = $path;
|
|
|
}
|
|
|
|
|
|
@@ -122,14 +116,8 @@ class Hash
|
|
|
* if there are no matches.
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::extract
|
|
|
*/
|
|
|
- public static function extract($data, string $path)
|
|
|
+ public static function extract(ArrayAccess|array $data, string $path): ArrayAccess|array
|
|
|
{
|
|
|
- if (!(is_array($data) || $data instanceof ArrayAccess)) {
|
|
|
- throw new InvalidArgumentException(
|
|
|
- 'Invalid data type, must be an array or \ArrayAccess instance.'
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
if (empty($path)) {
|
|
|
return $data;
|
|
|
}
|
|
|
@@ -218,7 +206,7 @@ class Hash
|
|
|
* @param string $token The token being matched.
|
|
|
* @return bool
|
|
|
*/
|
|
|
- protected static function _matchToken($key, string $token): bool
|
|
|
+ protected static function _matchToken(mixed $key, string $token): bool
|
|
|
{
|
|
|
switch ($token) {
|
|
|
case '{n}':
|
|
|
@@ -239,7 +227,7 @@ class Hash
|
|
|
* @param string $selector The patterns to match.
|
|
|
* @return bool Fitness of expression.
|
|
|
*/
|
|
|
- protected static function _matches($data, string $selector): bool
|
|
|
+ protected static function _matches(ArrayAccess|array $data, string $selector): bool
|
|
|
{
|
|
|
preg_match_all(
|
|
|
'/(\[ (?P<attr>[^=><!]+?) (\s* (?P<op>[><!]?[=]|[><]) \s* (?P<val>(?:\/.*?\/ | [^\]]+)) )? \])/x',
|
|
|
@@ -310,7 +298,7 @@ class Hash
|
|
|
* @return array The data with $values inserted.
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::insert
|
|
|
*/
|
|
|
- public static function insert(array $data, string $path, $values = null): array
|
|
|
+ public static function insert(array $data, string $path, mixed $values = null): array
|
|
|
{
|
|
|
$noTokens = strpos($path, '[') === false;
|
|
|
if ($noTokens && strpos($path, '.') === false) {
|
|
|
@@ -356,7 +344,7 @@ class Hash
|
|
|
* @param mixed $values The values to insert when doing inserts.
|
|
|
* @return array data.
|
|
|
*/
|
|
|
- protected static function _simpleOp(string $op, array $data, array $path, $values = null): array
|
|
|
+ protected static function _simpleOp(string $op, array $data, array $path, mixed $values = null): array
|
|
|
{
|
|
|
$_list = &$data;
|
|
|
|
|
|
@@ -463,8 +451,12 @@ class Hash
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::combine
|
|
|
* @throws \RuntimeException When keys and values count is unequal.
|
|
|
*/
|
|
|
- public static function combine(array $data, $keyPath, $valuePath = null, ?string $groupPath = null): array
|
|
|
- {
|
|
|
+ public static function combine(
|
|
|
+ array $data,
|
|
|
+ array|string|null $keyPath,
|
|
|
+ array|string|null $valuePath = null,
|
|
|
+ ?string $groupPath = null
|
|
|
+ ): array {
|
|
|
if (empty($data)) {
|
|
|
return [];
|
|
|
}
|
|
|
@@ -644,12 +636,12 @@ class Hash
|
|
|
* Recursively filters a data set.
|
|
|
*
|
|
|
* @param array $data Either an array to filter, or value when in callback
|
|
|
- * @param callable|array $callback A function to filter the data with. Defaults to
|
|
|
- * `static::_filter()` Which strips out all non-zero empty values.
|
|
|
+ * @param callable|null $callback A function to filter the data with. Defaults to
|
|
|
+ * all non-empty or zero values.
|
|
|
* @return array Filtered array
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::filter
|
|
|
*/
|
|
|
- public static function filter(array $data, $callback = ['self', '_filter']): array
|
|
|
+ public static function filter(array $data, ?callable $callback = null): array
|
|
|
{
|
|
|
foreach ($data as $k => $v) {
|
|
|
if (is_array($v)) {
|
|
|
@@ -657,7 +649,7 @@ class Hash
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return array_filter($data, $callback);
|
|
|
+ return array_filter($data, $callback ?? 'static::_filter');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -666,7 +658,7 @@ class Hash
|
|
|
* @param mixed $var Array to filter.
|
|
|
* @return bool
|
|
|
*/
|
|
|
- protected static function _filter($var): bool
|
|
|
+ protected static function _filter(mixed $var): bool
|
|
|
{
|
|
|
return $var === 0 || $var === 0.0 || $var === '0' || !empty($var);
|
|
|
}
|
|
|
@@ -762,7 +754,7 @@ class Hash
|
|
|
* @return array Merged array
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::merge
|
|
|
*/
|
|
|
- public static function merge(array $data, $merge): array
|
|
|
+ public static function merge(array $data, mixed $merge): array
|
|
|
{
|
|
|
$args = array_slice(func_get_args(), 1);
|
|
|
$return = $data;
|
|
|
@@ -908,7 +900,7 @@ class Hash
|
|
|
* @return mixed The reduced value.
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::reduce
|
|
|
*/
|
|
|
- public static function reduce(array $data, string $path, callable $function)
|
|
|
+ public static function reduce(array $data, string $path, callable $function): mixed
|
|
|
{
|
|
|
$values = (array)static::extract($data, $path);
|
|
|
|
|
|
@@ -940,7 +932,7 @@ class Hash
|
|
|
* @return mixed The results of the applied method.
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::apply
|
|
|
*/
|
|
|
- public static function apply(array $data, string $path, callable $function)
|
|
|
+ public static function apply(array $data, string $path, callable $function): mixed
|
|
|
{
|
|
|
$values = (array)static::extract($data, $path);
|
|
|
|
|
|
@@ -980,8 +972,12 @@ class Hash
|
|
|
* @return array Sorted array of data
|
|
|
* @link https://book.cakephp.org/4/en/core-libraries/hash.html#Cake\Utility\Hash::sort
|
|
|
*/
|
|
|
- public static function sort(array $data, string $path, $dir = 'asc', $type = 'regular'): array
|
|
|
- {
|
|
|
+ public static function sort(
|
|
|
+ array $data,
|
|
|
+ string $path,
|
|
|
+ string|int $dir = 'asc',
|
|
|
+ array|string $type = 'regular'
|
|
|
+ ): array {
|
|
|
if (empty($data)) {
|
|
|
return [];
|
|
|
}
|
|
|
@@ -1015,8 +1011,8 @@ class Hash
|
|
|
if (is_string($dir)) {
|
|
|
$dir = strtolower($dir);
|
|
|
}
|
|
|
- if (!in_array($dir, [\SORT_ASC, \SORT_DESC], true)) {
|
|
|
- $dir = $dir === 'asc' ? \SORT_ASC : \SORT_DESC;
|
|
|
+ if (!in_array($dir, [SORT_ASC, SORT_DESC], true)) {
|
|
|
+ $dir = $dir === 'asc' ? SORT_ASC : SORT_DESC;
|
|
|
}
|
|
|
|
|
|
$ignoreCase = false;
|
|
|
@@ -1030,15 +1026,15 @@ class Hash
|
|
|
$type = strtolower($type);
|
|
|
|
|
|
if ($type === 'numeric') {
|
|
|
- $type = \SORT_NUMERIC;
|
|
|
+ $type = SORT_NUMERIC;
|
|
|
} elseif ($type === 'string') {
|
|
|
- $type = \SORT_STRING;
|
|
|
+ $type = SORT_STRING;
|
|
|
} elseif ($type === 'natural') {
|
|
|
- $type = \SORT_NATURAL;
|
|
|
+ $type = SORT_NATURAL;
|
|
|
} elseif ($type === 'locale') {
|
|
|
- $type = \SORT_LOCALE_STRING;
|
|
|
+ $type = SORT_LOCALE_STRING;
|
|
|
} else {
|
|
|
- $type = \SORT_REGULAR;
|
|
|
+ $type = SORT_REGULAR;
|
|
|
}
|
|
|
if ($ignoreCase) {
|
|
|
$values = array_map('mb_strtolower', $values);
|
|
|
@@ -1067,10 +1063,10 @@ class Hash
|
|
|
* Squashes an array to a single hash so it can be sorted.
|
|
|
*
|
|
|
* @param array $data The data to squash.
|
|
|
- * @param mixed $key The key for the data.
|
|
|
+ * @param string|int|null $key The key for the data.
|
|
|
* @return array
|
|
|
*/
|
|
|
- protected static function _squash(array $data, $key = null): array
|
|
|
+ protected static function _squash(array $data, string|int|null $key = null): array
|
|
|
{
|
|
|
$stack = [];
|
|
|
foreach ($data as $k => $r) {
|
|
|
@@ -1232,8 +1228,10 @@ class Hash
|
|
|
$parentId = static::get($result, $parentKeys);
|
|
|
|
|
|
if (isset($idMap[$id][$options['children']])) {
|
|
|
+ /** @psalm-suppress PossiblyInvalidArgument psalm thinks $result could be ArrayAccess */
|
|
|
$idMap[$id] = array_merge($result, $idMap[$id]);
|
|
|
} else {
|
|
|
+ /** @psalm-suppress PossiblyInvalidArgument psalm thinks $result could be ArrayAccess */
|
|
|
$idMap[$id] = array_merge($result, [$options['children'] => []]);
|
|
|
}
|
|
|
if (!$parentId || !in_array($parentId, $ids)) {
|