Skip to content

Commit

Permalink
feat: add ArrayHelper::dotKeyExists()
Browse files Browse the repository at this point in the history
  • Loading branch information
kenjis committed Oct 31, 2023
1 parent 60f2fa0 commit 50a1aaa
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
55 changes: 55 additions & 0 deletions system/Helpers/Array/ArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace CodeIgniter\Helpers\Array;

use InvalidArgumentException;

/**
* @see \CodeIgniter\Helpers\Array\ArrayHelperRecursiveDiffTest
*/
Expand Down Expand Up @@ -107,6 +109,59 @@ private static function arraySearchDot(array $indexes, array $array)
return null;
}

/**
* array_key_exists() with dot array syntax.
*
* If wildcard `*` is used, all items for the key after it must have the key.
*/
public static function dotKeyExists(string $index, array $array): bool
{
if (str_ends_with($index, '*') || str_contains($index, '*.*')) {
throw new InvalidArgumentException(
'You must set key right after "*". Invalid index: "' . $index . '"'
);
}

$indexes = self::convertToArray($index);

// If indexes is empty, returns false.
if ($indexes === []) {
return false;
}

$currentArray = $array;

// Grab the current index
while ($currentIndex = array_shift($indexes)) {
if ($currentIndex === '*') {
$currentIndex = array_shift($indexes);

foreach ($currentArray as $item) {
if (! array_key_exists($currentIndex, $item)) {
return false;
}
}

// If indexes is empty, all elements are checked.
if ($indexes === []) {
return true;
}

$currentArray = self::dotSearch('*.' . $currentIndex, $currentArray);

continue;
}

if (! array_key_exists($currentIndex, $currentArray)) {
return false;
}

$currentArray = $currentArray[$currentIndex];
}

return true;
}

/**
* Groups all rows by their index values. Result's depth equals number of indexes
*
Expand Down
72 changes: 72 additions & 0 deletions tests/system/Helpers/Array/ArrayHelperDotKeyExistsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Helpers\Array;

use CodeIgniter\Test\CIUnitTestCase;
use InvalidArgumentException;

/**
* @group Others
*
* @internal
*/
final class ArrayHelperDotKeyExistsTest extends CIUnitTestCase
{
private array $array = [
'contacts' => [
'friends' => [
['name' => 'Fred Flinstone', 'age' => 20],
['age' => 21], // 'name' key does not exist
],
],
];

public function testDotKeyExists(): void
{
$this->assertFalse(ArrayHelper::dotKeyExists('', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('not', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('not.friends', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends.0.name', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.1.name', $this->array));
}

public function testDotKeyExistsWithEndingWildCard(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('You must set key right after "*". Invalid index: "contacts.*"');

$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*', $this->array));
}

public function testDotKeyExistsWithDoubleWildCard(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('You must set key right after "*". Invalid index: "contacts.*.*.age"');

$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.*.age', $this->array));
}

public function testDotKeyExistsWithWildCard(): void
{
$this->assertTrue(ArrayHelper::dotKeyExists('*.friends', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.friends.*.age', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.friends.*.name', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('*.friends.*.age', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('*.friends.*.name', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.age', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.1.age', $this->array));
$this->assertTrue(ArrayHelper::dotKeyExists('contacts.*.0.name', $this->array));
$this->assertFalse(ArrayHelper::dotKeyExists('contacts.*.1.name', $this->array));
}
}

0 comments on commit 50a1aaa

Please sign in to comment.