Skip to content

Commit

Permalink
ENH Add functionality to ArrayLib
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Sep 12, 2024
1 parent c627ba8 commit 3d3a3a8
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 0 deletions.
62 changes: 62 additions & 0 deletions src/ORM/ArrayLib.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Generator;
use SilverStripe\Dev\Deprecation;
use InvalidArgumentException;

/**
* Library of static methods for manipulating arrays.
Expand Down Expand Up @@ -354,4 +355,65 @@ public static function shuffleAssociative(array &$array): void

$array = $shuffledArray;
}

/**
* Insert a value into an array before another given value.
* Does not preserve keys.
*
* @param mixed $before The value to check for. If this value isn't in the source array, $insert will be put at the end.
* @param boolean $strict If true then this will perform a strict type comparison to look for the $before value in the source array.
* @param boolean $splatInsertArray If true, $insert must be an array.
* Its values will be splatted into the source array.
*/
public static function insertBefore(array $array, mixed $insert, mixed $before, bool $strict = false, bool $splatInsertArray = false): array
{
if ($splatInsertArray && !is_array($insert)) {
throw new InvalidArgumentException('$insert must be an array when $splatInsertArray is true. Got ' . gettype($insert));
}
$array = array_values($array);
$pos = array_search($before, $array, $strict);
if ($pos === false) {
return static::insertIntoArray($array, $insert, $splatInsertArray);
}
return static::insertAtPosition($array, $insert, $pos, $splatInsertArray);
}

/**
* Insert a value into an array after another given value.
* Does not preserve keys.
*
* @param mixed $after The value to check for. If this value isn't in the source array, $insert will be put at the end.
* @param boolean $strict If true then this will perform a strict type comparison to look for the $before value in the source array.
* @param boolean $splatInsertArray If true, $insert must be an array.
* Its values will be splatted into the source array.
*/
public static function insertAfter(array $array, mixed $insert, mixed $after, bool $strict = false, bool $splatInsertArray = false): array
{
if ($splatInsertArray && !is_array($insert)) {
throw new InvalidArgumentException('$insert must be an array when $splatInsertArray is true. Got ' . gettype($insert));
}
$array = array_values($array);
$pos = array_search($after, $array, $strict);
if ($pos === false) {
return static::insertIntoArray($array, $insert, $splatInsertArray);
}
return static::insertAtPosition($array, $insert, $pos + 1, $splatInsertArray);
}

private static function insertAtPosition(array $array, mixed $insert, int $pos, bool $splatInsertArray): array
{
$result = array_slice($array, 0, $pos);
$result = static::insertIntoArray($result, $insert, $splatInsertArray);
return array_merge($result, array_slice($array, $pos));
}

private static function insertIntoArray(array $array, mixed $insert, bool $splatInsertArray): array
{
if ($splatInsertArray) {
$array = array_merge($array, $insert);
} else {
$array[] = $insert;
}
return $array;
}
}
172 changes: 172 additions & 0 deletions tests/php/ORM/ArrayLibTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,176 @@ public function testShuffleAssociative()
}
}
}

public function provideInsertBefore(): array
{
return [
'simple insertion' => [
'insert' => 'new',
'before' => 'def',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'new', 'def', '0', null, true, 0, 'last']
],
'insert before first' => [
'insert' => 'new',
'before' => 'abc',
'strict' => true,
'splat' => false,
'expected' => ['new', 'abc', '', [1,2,3], 'def', '0', null, true, 0, 'last']
],
'insert before last' => [
'insert' => 'new',
'before' => 'last',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'new', 'last']
],
'insert before missing' => [
'insert' => 'new',
'before' => 'this value isnt there',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
],
'strict' => [
'insert' => 'new',
'before' => 0,
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 'new', 0, 'last']
],
'not strict' => [
'insert' => 'new',
'before' => 0,
'strict' => false,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', 'new', '0', null, true, 0, 'last']
],
'before array' => [
'insert' => 'new',
'before' => [1,2,3],
'strict' => true,
'splat' => false,
'expected' => ['abc', '', 'new', [1,2,3], 'def', '0', null, true, 0, 'last']
],
'before missing array' => [
'insert' => 'new',
'before' => ['a', 'b', 'c'],
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
],
'splat array' => [
'insert' => ['a', 'b', 'c'],
'before' => 'def',
'strict' => true,
'splat' => true,
'expected' => ['abc', '', [1,2,3], 'a', 'b', 'c', 'def', '0', null, true, 0, 'last']
],
'no splat array' => [
'insert' => ['a', 'b', 'c'],
'before' => 'def',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], ['a', 'b', 'c'], 'def', '0', null, true, 0, 'last']
],
];
}

/**
* @dataProvider provideInsertBefore
*/
public function testInsertBefore(mixed $insert, mixed $before, bool $strict, bool $splat, array $expected): void
{
$array = ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last'];
$final = ArrayLib::insertBefore($array, $insert, $before, $strict, $splat);
$this->assertSame($expected, $final);
}

public function provideInsertAfter(): array
{
return [
'simple insertion' => [
'insert' => 'new',
'before' => 'def',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', 'new', '0', null, true, 0, 'last']
],
'insert after first' => [
'insert' => 'new',
'before' => 'abc',
'strict' => true,
'splat' => false,
'expected' => ['abc', 'new', '', [1,2,3], 'def', '0', null, true, 0, 'last']
],
'insert after last' => [
'insert' => 'new',
'before' => 'last',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
],
'insert after missing' => [
'insert' => 'new',
'before' => 'this value isnt there',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
],
'strict' => [
'insert' => 'new',
'before' => 0,
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'new', 'last']
],
'not strict' => [
'insert' => 'new',
'before' => 0,
'strict' => false,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', 'new', null, true, 0, 'last']
],
'after array' => [
'insert' => 'new',
'before' => [1,2,3],
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'new', 'def', '0', null, true, 0, 'last']
],
'after missing array' => [
'insert' => 'new',
'before' => ['a', 'b', 'c'],
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
],
'splat array' => [
'insert' => ['a', 'b', 'c'],
'before' => 'def',
'strict' => true,
'splat' => true,
'expected' => ['abc', '', [1,2,3], 'def', 'a', 'b', 'c', '0', null, true, 0, 'last']
],
'no splat array' => [
'insert' => ['a', 'b', 'c'],
'before' => 'def',
'strict' => true,
'splat' => false,
'expected' => ['abc', '', [1,2,3], 'def', ['a', 'b', 'c'], '0', null, true, 0, 'last']
],
];
}

/**
* @dataProvider provideInsertAfter
*/
public function testInsertAfter(mixed $insert, mixed $after, bool $strict, bool $splat, array $expected): void
{
$array = ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last'];
$final = ArrayLib::insertAfter($array, $insert, $after, $strict, $splat);
$this->assertSame($expected, $final);
}
}

0 comments on commit 3d3a3a8

Please sign in to comment.