From 5c6170a1ab48b5334f7d8b5a1a9a5747a2438ce3 Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 25 Mar 2024 15:39:12 +0100 Subject: [PATCH 1/4] add static util --- src/StaticUtil/AbstractStaticUtil.php | 14 ++++ src/StaticUtil/SUtil.php | 32 ++++++++ src/StaticUtil/StaticArrayUtil.php | 101 ++++++++++++++++++++++++++ src/StaticUtil/StaticClassUtil.php | 24 ++++++ src/Util/ArrayUtil.php | 73 +++++-------------- src/Util/ClassUtil.php | 13 ++-- 6 files changed, 195 insertions(+), 62 deletions(-) create mode 100644 src/StaticUtil/AbstractStaticUtil.php create mode 100644 src/StaticUtil/SUtil.php create mode 100644 src/StaticUtil/StaticArrayUtil.php create mode 100644 src/StaticUtil/StaticClassUtil.php diff --git a/src/StaticUtil/AbstractStaticUtil.php b/src/StaticUtil/AbstractStaticUtil.php new file mode 100644 index 00000000..7323d2b5 --- /dev/null +++ b/src/StaticUtil/AbstractStaticUtil.php @@ -0,0 +1,14 @@ + $class + * @return T The instance of the given class. + */ + protected static function getInstance(string $class): object + { + if (!isset(static::$instances[$class])) { + static::$instances[$class] = new $class; + } + + return static::$instances[$class]; + } +} \ No newline at end of file diff --git a/src/StaticUtil/StaticArrayUtil.php b/src/StaticUtil/StaticArrayUtil.php new file mode 100644 index 00000000..16264dc6 --- /dev/null +++ b/src/StaticUtil/StaticArrayUtil.php @@ -0,0 +1,101 @@ + $value) { + if (\in_array($k, $keys)) { + $new[$newKey] = $newValue; + } + $new[$k] = $value; + } + $array = $new; + } else { + $array[$newKey] = $newValue; + } + } + + + /** + * Insert a value into an existing array by key name. + * + * Additional options: + * - (bool) strict: Strict behavior for array search. Default false + * - (bool) attachMissingKey: Attach value to the end of the array if the key does not exist. Default: true + * - (int) offset: Add additional offset. + * + * @param array $array The target array + * @param string $key the existing target key in the array + * @param mixed $value the new value to be inserted + * @param array{ + * strict?: bool, + * attachMissingKey?: bool, + * offset?: int + * } $options Additional options + */ + public static function insertAfterKey(array &$array, string $key, mixed $value, string $newKey = null, array $options = []): void + { + $options = array_merge([ + 'strict' => false, + 'attachMissingKey' => true, + 'offset' => 0, + ], $options); + + $keys = array_keys($array); + $index = array_search($key, $keys, $options['strict']); + + if (false === $index && false === $options['attachIfKeyNotExist']) { + return; + } + $pos = false === $index ? \count($array) : $index + 1; + $pos = $pos + $options['offset']; + + if ($newKey) { + $value = [$newKey => $value]; + } else { + $value = [$value]; + } + + $array = array_combine( + array_merge(array_slice($keys, 0, $pos), array_keys($value), array_slice($keys, $pos)), + array_merge(array_slice($array, 0, $pos), $value, array_slice($array, $pos)) + ); + } + + /** + * Removes a value from an array. + * + * @return bool Returns true if the value has been found and removed, false in other cases + */ + public static function removeValue(mixed $value, array &$array): bool + { + $position = array_search($value, $array); + + if (false !== $position) { + unset($array[$position]); + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/StaticUtil/StaticClassUtil.php b/src/StaticUtil/StaticClassUtil.php new file mode 100644 index 00000000..d7cf1fd0 --- /dev/null +++ b/src/StaticUtil/StaticClassUtil.php @@ -0,0 +1,24 @@ +insertBeforeKey(...)} instead. */ public static function insertBeforeKey(array &$array, array|string $keys, string $newKey, mixed $newValue): void { - if (!\is_array($keys)) { - $keys = [$keys]; - } - - if (array_intersect($keys, array_keys($array))) { - $new = []; - - foreach ($array as $k => $value) { - if (\in_array($k, $keys)) { - $new[$newKey] = $newValue; - } - $new[$k] = $value; - } - $array = $new; - } else { - $array[$newKey] = $newValue; - } + StaticArrayUtil::insertBeforeKey($array, $keys, $newKey, $newValue); } /** @@ -47,59 +35,36 @@ public static function insertBeforeKey(array &$array, array|string $keys, string * Additional options: * - (bool) strict: Strict behavior for array search. Default false * - (bool) attachIfKeyNotExist: Attach value at the end of the array if key not exist. Default: true - * - (int) offset: Add an additional offset + * - (int) offset: Add additional offset * * @param array $array The target array * @param string $key the existing target key in the array * @param mixed $value the new value to be inserted * @param array{ - * strict?: bool, - * attachIfKeyNotExist?: bool, - * offset?: int + * strict?: bool, + * attachIfKeyNotExist?: bool, + * offset?: int * } $options Additional options + * + * @deprecated Use {@see StaticArrayUtil::insertAfterKey() SUtil::array()->insertAfterKey(...)} instead. + * Beware: The option keys have changed! */ public function insertAfterKey(array &$array, string $key, mixed $value, string $newKey = null, array $options = []): void { - $options = array_merge([ - 'strict' => false, - 'attachIfKeyNotExist' => true, - 'offset' => 0, - ], $options); - - $keys = array_keys($array); - $index = array_search($key, $keys, $options['strict']); + $options['attachMissingKey'] ??= $options['attachIfKeyNotExist'] ?? true; - if (false === $index && false === $options['attachIfKeyNotExist']) { - return; - } - $pos = false === $index ? \count($array) : $index + 1; - $pos = $pos + $options['offset']; - - if ($newKey) { - $value = [$newKey => $value]; - } else { - $value = [$value]; - } - - $array = array_combine( - array_merge(\array_slice($keys, 0, $pos), array_keys($value), \array_slice($keys, $pos)), - array_merge(\array_slice($array, 0, $pos), $value, \array_slice($array, $pos)) - ); + StaticArrayUtil::insertAfterKey($array, $key, $value, $newKey, $options); } /** - * Removes a value in an array. + * Removes a value from an array. + * + * @return bool True if the value was found and removed, false otherwise. * - * @return bool Returns true if the value has been found and removed, false in other cases + * @deprecated Use {@see StaticArrayUtil::removeValue() SUtil::array()->removeValue(...)} instead. */ public function removeValue(mixed $value, array &$array): bool { - if (false !== ($intPosition = array_search($value, $array))) { - unset($array[$intPosition]); - - return true; - } - - return false; + return StaticArrayUtil::removeValue($value, $array); } } diff --git a/src/Util/ClassUtil.php b/src/Util/ClassUtil.php index 98193398..70347af4 100644 --- a/src/Util/ClassUtil.php +++ b/src/Util/ClassUtil.php @@ -2,20 +2,17 @@ namespace HeimrichHannot\UtilsBundle\Util; +use HeimrichHannot\UtilsBundle\StaticUtil\StaticClassUtil; + class ClassUtil { /** * Return true if the given class or a parent class implements the given trait + * + * @deprecated Use {@see StaticClassUtil::hasTrait() SUtil::class()->hasTrait(...)} instead. */ public function classImplementsTrait(object|string $class, string $trait): bool { - do { - if (in_array($trait, class_uses($class))) { - return true; - } - - } while($class = get_parent_class($class)); - - return false; + return StaticClassUtil::hasTrait($class, $trait); } } \ No newline at end of file From d4d84b64da641b8f900c27554af7c50a6293991a Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 25 Mar 2024 18:28:33 +0100 Subject: [PATCH 2/4] fix options key --- src/StaticUtil/StaticArrayUtil.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StaticUtil/StaticArrayUtil.php b/src/StaticUtil/StaticArrayUtil.php index 16264dc6..ade02c30 100644 --- a/src/StaticUtil/StaticArrayUtil.php +++ b/src/StaticUtil/StaticArrayUtil.php @@ -64,7 +64,7 @@ public static function insertAfterKey(array &$array, string $key, mixed $value, $keys = array_keys($array); $index = array_search($key, $keys, $options['strict']); - if (false === $index && false === $options['attachIfKeyNotExist']) { + if (false === $index && false === $options['attachMissingKey']) { return; } $pos = false === $index ? \count($array) : $index + 1; From 1fcefc6d3cfe742b8a800703c5ffe6fc76b73d25 Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Mon, 25 Mar 2024 18:33:41 +0100 Subject: [PATCH 3/4] add SUtilsTest --- src/StaticUtil/AbstractStaticUtil.php | 1 + src/StaticUtil/{SUtil.php => SUtils.php} | 2 +- tests/StaticUtil/SUtilsTest.php | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) rename src/StaticUtil/{SUtil.php => SUtils.php} (98%) create mode 100644 tests/StaticUtil/SUtilsTest.php diff --git a/src/StaticUtil/AbstractStaticUtil.php b/src/StaticUtil/AbstractStaticUtil.php index 7323d2b5..72639ee9 100644 --- a/src/StaticUtil/AbstractStaticUtil.php +++ b/src/StaticUtil/AbstractStaticUtil.php @@ -4,6 +4,7 @@ /** * @internal + * @codeCoverageIgnore */ abstract class AbstractStaticUtil { diff --git a/src/StaticUtil/SUtil.php b/src/StaticUtil/SUtils.php similarity index 98% rename from src/StaticUtil/SUtil.php rename to src/StaticUtil/SUtils.php index f045102e..762d9426 100644 --- a/src/StaticUtil/SUtil.php +++ b/src/StaticUtil/SUtils.php @@ -2,7 +2,7 @@ namespace HeimrichHannot\UtilsBundle\StaticUtil; -class SUtil +class SUtils { protected static array $instances = []; diff --git a/tests/StaticUtil/SUtilsTest.php b/tests/StaticUtil/SUtilsTest.php new file mode 100644 index 00000000..7edea4db --- /dev/null +++ b/tests/StaticUtil/SUtilsTest.php @@ -0,0 +1,17 @@ +assertInstanceOf(StaticArrayUtil::class, SUtils::array()); + $this->assertInstanceOf(StaticClassUtil::class, SUtils::class()); + } +} \ No newline at end of file From bec2a5e0d288df676033bdb9dbfee41f2a6cbbfc Mon Sep 17 00:00:00 2001 From: Eric Gesemann Date: Tue, 26 Mar 2024 09:09:07 +0100 Subject: [PATCH 4/4] add StaticArrayUtilTest --- src/StaticUtil/StaticArrayUtil.php | 3 +- tests/StaticUtil/SUtilsTest.php | 2 +- tests/StaticUtil/StaticArrayUtilTest.php | 77 ++++++++++++++++++++++++ tests/Util/Type/ArrayUtilTest.php | 2 +- 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 tests/StaticUtil/StaticArrayUtilTest.php diff --git a/src/StaticUtil/StaticArrayUtil.php b/src/StaticUtil/StaticArrayUtil.php index ade02c30..35527399 100644 --- a/src/StaticUtil/StaticArrayUtil.php +++ b/src/StaticUtil/StaticArrayUtil.php @@ -35,7 +35,6 @@ public static function insertBeforeKey(array &$array, array|string $keys, string } } - /** * Insert a value into an existing array by key name. * @@ -67,7 +66,7 @@ public static function insertAfterKey(array &$array, string $key, mixed $value, if (false === $index && false === $options['attachMissingKey']) { return; } - $pos = false === $index ? \count($array) : $index + 1; + $pos = false === $index ? count($array) : $index + 1; $pos = $pos + $options['offset']; if ($newKey) { diff --git a/tests/StaticUtil/SUtilsTest.php b/tests/StaticUtil/SUtilsTest.php index 7edea4db..bddaba0d 100644 --- a/tests/StaticUtil/SUtilsTest.php +++ b/tests/StaticUtil/SUtilsTest.php @@ -1,6 +1,6 @@ getTestInstance(); + $array = ['a' => 'A', 'b' => 'B', 'c' => 'C']; + + $instance::insertBeforeKey($array, 'e', 'f', 'F'); + $this->assertSame( + ['a' => 'A', 'b' => 'B', 'c' => 'C', 'f' => 'F'], $array); + + $instance::insertBeforeKey($array, ['z'], 'h', 'H'); + $this->assertSame( + ['a' => 'A', 'b' => 'B', 'c' => 'C', 'f' => 'F', 'h' => 'H'], $array); + + $instance::insertBeforeKey($array, ['f', 'h'], 'd', 'D'); + $this->assertSame( + ['a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'f' => 'F', 'h' => 'H'], $array); + } + + public function testInsertAfterKey() + { + $arrayUtil = $this->getTestInstance(); + + $target = ['hello' => 'world']; + $arrayUtil->insertAfterKey($target, 'foo', 'bar'); + $this->assertSame(['hello' => 'world', 0 => 'bar'], $target); + + $target = ['hello' => 'world']; + $arrayUtil->insertAfterKey($target, 'foo', 'bar', 'foobar'); + $this->assertSame(['hello' => 'world', 'foobar' => 'bar'], $target); + + $target = ['hello' => 'world']; + $arrayUtil->insertAfterKey($target, 'foo', 'bar', null, ['attachMissingKey' => false]); + $this->assertSame(['hello' => 'world'], $target); + + $target = ['hello' => 'world', 'foo' => 'bar', 'heimrich' => 'hannot']; + $arrayUtil->insertAfterKey($target, 'hello', 'camp', 'contao', ['offset' => 1]); + $this->assertSame(['hello' => 'world', 'foo' => 'bar', 'contao' => 'camp', 'heimrich' => 'hannot'], $target); + + $target = ['1' => 'world', 'foo' => 'bar', 'heimrich' => 'hannot']; + $arrayUtil->insertAfterKey($target, 1, 'camp', 'contao', ['strict' => false]); + $this->assertSame(['1' => 'world', 'contao' => 'camp', 'foo' => 'bar', 'heimrich' => 'hannot'], $target); + + $target = ['1' => 'world', 'foo' => 'bar', 'heimrich' => 'hannot']; + $arrayUtil->insertAfterKey($target, 1, 'camp', 'contao', ['strict' => true]); + $this->assertSame(['1' => 'world', 'foo' => 'bar', 'heimrich' => 'hannot', 'contao' => 'camp'], $target); + } + + public function testRemoveValue() + { + $arrayUtil = $this->getTestInstance(); + + $array = [0 => 0, 1 => 1, 2 => 2]; + $result = $arrayUtil->removeValue(1, $array); + $this->assertTrue($result); + $this->assertCount(2, $array); + $this->assertArrayHasKey(0, $array); + $this->assertArrayHasKey(2, $array); + + $result = $arrayUtil->removeValue(1, $array); + $this->assertFalse($result); + } +} \ No newline at end of file diff --git a/tests/Util/Type/ArrayUtilTest.php b/tests/Util/Type/ArrayUtilTest.php index da878b00..b6cd3b1b 100644 --- a/tests/Util/Type/ArrayUtilTest.php +++ b/tests/Util/Type/ArrayUtilTest.php @@ -14,7 +14,7 @@ class ArrayUtilTest extends AbstractUtilsTestCase { - public function getTestInstance(array $parameters = [], ?MockBuilder $mockBuilder = null) + public function getTestInstance(array $parameters = [], ?MockBuilder $mockBuilder = null): ArrayUtil { return new ArrayUtil(); }