Skip to content

Commit

Permalink
refactor: move code from array_helper.php to ArrayHelper.php
Browse files Browse the repository at this point in the history
  • Loading branch information
kenjis committed Oct 31, 2023
1 parent 514fe62 commit bc4f308
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 126 deletions.
143 changes: 143 additions & 0 deletions system/Helpers/Array/ArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,149 @@
*/
final class ArrayHelper
{
/**
* Searches an array through dot syntax. Supports
* wildcard searches, like foo.*.bar
*
* @return array|bool|int|object|string|null
*/
public static function dotArraySearch(string $index, array $array)
{
// See https://regex101.com/r/44Ipql/1
$segments = preg_split(
'/(?<!\\\\)\./',
rtrim($index, '* '),
0,
PREG_SPLIT_NO_EMPTY
);

$segments = array_map(static fn ($key) => str_replace('\.', '.', $key), $segments);

return self::arraySearchDot($segments, $array);
}

/**
* Used by `dotArraySearch()` to recursively search the
* array with wildcards.
*
* @return array|bool|float|int|object|string|null
*/
private static function arraySearchDot(array $indexes, array $array)
{
// If index is empty, returns null.
if ($indexes === []) {
return null;
}

// Grab the current index
$currentIndex = array_shift($indexes);

if (! isset($array[$currentIndex]) && $currentIndex !== '*') {
return null;
}

// Handle Wildcard (*)
if ($currentIndex === '*') {
$answer = [];

foreach ($array as $value) {
if (! is_array($value)) {
return null;
}

$answer[] = self::arraySearchDot($indexes, $value);
}

$answer = array_filter($answer, static fn ($value) => $value !== null);

if ($answer !== []) {
if (count($answer) === 1) {
// If array only has one element, we return that element for BC.
return current($answer);
}

return $answer;
}

return null;
}

// If this is the last index, make sure to return it now,
// and not try to recurse through things.
if (empty($indexes)) {

Check failure on line 88 in system/Helpers/Array/ArrayHelper.php

View workflow job for this annotation

GitHub Actions / PHP Static Analysis

Construct empty() is not allowed. Use more strict comparison.
return $array[$currentIndex];
}

// Do we need to recursively search this value?
if (is_array($array[$currentIndex]) && $array[$currentIndex] !== []) {
return self::arraySearchDot($indexes, $array[$currentIndex]);
}

// Otherwise, not found.
return null;
}

/**
* Groups all rows by their index values. Result's depth equals number of indexes
*
* @param array $array Data array (i.e. from query result)
* @param array $indexes Indexes to group by. Dot syntax used. Returns $array if empty
* @param bool $includeEmpty If true, null and '' are also added as valid keys to group
*
* @return array Result array where rows are grouped together by indexes values.
*/
public static function arrayGroupBy(array $array, array $indexes, bool $includeEmpty = false): array
{
if ($indexes === []) {
return $array;
}

$result = [];

foreach ($array as $row) {
$result = self::arrayAttachIndexedValue($result, $row, $indexes, $includeEmpty);
}

return $result;
}

/**
* Used by `arrayGroupBy()` to recursively attach $row to the $indexes path of values found by
* `dot_array_search()`
*
* @internal This should not be used on its own
*/
private static function arrayAttachIndexedValue(array $result, array $row, array $indexes, bool $includeEmpty): array
{
if (($index = array_shift($indexes)) === null) {
$result[] = $row;

return $result;
}

$value = dot_array_search($index, $row);

if (! is_scalar($value)) {
$value = '';
}

if (is_bool($value)) {
$value = (int) $value;
}

if (! $includeEmpty && $value === '') {
return $result;
}

if (! array_key_exists($value, $result)) {
$result[$value] = [];
}

$result[$value] = self::arrayAttachIndexedValue($result[$value], $row, $indexes, $includeEmpty);

return $result;
}

/**
* Compare recursively two associative arrays and return difference as new array.
* Returns keys that exist in `$original` but not in `$compareWith`.
Expand Down
130 changes: 4 additions & 126 deletions system/Helpers/array_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* the LICENSE file that was distributed with this source code.
*/

use CodeIgniter\Helpers\Array\ArrayHelper;

// CodeIgniter Array Helpers

if (! function_exists('dot_array_search')) {
Expand All @@ -20,82 +22,7 @@
*/
function dot_array_search(string $index, array $array)
{
// See https://regex101.com/r/44Ipql/1
$segments = preg_split(
'/(?<!\\\\)\./',
rtrim($index, '* '),
0,
PREG_SPLIT_NO_EMPTY
);

$segments = array_map(static fn ($key) => str_replace('\.', '.', $key), $segments);

return _array_search_dot($segments, $array);
}
}

if (! function_exists('_array_search_dot')) {
/**
* Used by `dot_array_search` to recursively search the
* array with wildcards.
*
* @internal This should not be used on its own.
*
* @return array|bool|float|int|object|string|null
*/
function _array_search_dot(array $indexes, array $array)
{
// If index is empty, returns null.
if ($indexes === []) {
return null;
}

// Grab the current index
$currentIndex = array_shift($indexes);

if (! isset($array[$currentIndex]) && $currentIndex !== '*') {
return null;
}

// Handle Wildcard (*)
if ($currentIndex === '*') {
$answer = [];

foreach ($array as $value) {
if (! is_array($value)) {
return null;
}

$answer[] = _array_search_dot($indexes, $value);
}

$answer = array_filter($answer, static fn ($value) => $value !== null);

if ($answer !== []) {
if (count($answer) === 1) {
// If array only has one element, we return that element for BC.
return current($answer);
}

return $answer;
}

return null;
}

// If this is the last index, make sure to return it now,
// and not try to recurse through things.
if (empty($indexes)) {
return $array[$currentIndex];
}

// Do we need to recursively search this value?
if (is_array($array[$currentIndex]) && $array[$currentIndex] !== []) {
return _array_search_dot($indexes, $array[$currentIndex]);
}

// Otherwise, not found.
return null;
return ArrayHelper::dotArraySearch($index, $array);
}
}

Expand Down Expand Up @@ -231,55 +158,6 @@ function array_flatten_with_dots(iterable $array, string $id = ''): array
*/
function array_group_by(array $array, array $indexes, bool $includeEmpty = false): array
{
if ($indexes === []) {
return $array;
}

$result = [];

foreach ($array as $row) {
$result = _array_attach_indexed_value($result, $row, $indexes, $includeEmpty);
}

return $result;
}
}

if (! function_exists('_array_attach_indexed_value')) {
/**
* Used by `array_group_by` to recursively attach $row to the $indexes path of values found by
* `dot_array_search`
*
* @internal This should not be used on its own
*/
function _array_attach_indexed_value(array $result, array $row, array $indexes, bool $includeEmpty): array
{
if (($index = array_shift($indexes)) === null) {
$result[] = $row;

return $result;
}

$value = dot_array_search($index, $row);

if (! is_scalar($value)) {
$value = '';
}

if (is_bool($value)) {
$value = (int) $value;
}

if (! $includeEmpty && $value === '') {
return $result;
}

if (! array_key_exists($value, $result)) {
$result[$value] = [];
}

$result[$value] = _array_attach_indexed_value($result[$value], $row, $indexes, $includeEmpty);

return $result;
return ArrayHelper::arrayGroupBy($array, $indexes, $includeEmpty);
}
}

0 comments on commit bc4f308

Please sign in to comment.