From c8856ecac04d9edb457e92b8956f6e88ae604272 Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Fri, 5 Oct 2018 11:32:12 -0400 Subject: [PATCH] Add some new helper methods, with updated tests --- composer.json | 11 ++-- phpunit.dist.xml | 32 ++++++------ src/Config.php | 15 +++++- src/ConfigInterface.php | 12 ++++- src/Di/Container.php | 4 +- src/Di/ContainerInterface.php | 1 + src/Enum.php | 2 + src/Friend.php | 2 + src/Transformer/AbstractTransformer.php | 27 ++++++++-- src/Type/ArrayType.php | 19 ++++++- src/functions.php | 2 +- tests/ConfigTest.php | 17 +++++- tests/Transformer/AbstractTransformerTest.php | 52 ++++++++++++++++++- tests/Type/ArrayTypeTest.php | 23 ++++++++ tests/mocks.php | 7 +++ 15 files changed, 192 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 00fd335..5e56984 100644 --- a/composer.json +++ b/composer.json @@ -21,9 +21,10 @@ "aura/html": "2.*", "container-interop/container-interop": "1.*", "danielstjules/stringy": "^3.0.0", + "ext-json": "*", "psr/http-message": "~1.0", "psr/log": "~1.0", - "zendframework/zend-diactoros": "^1.4.0" + "zendframework/zend-diactoros": "^2.0.0" }, "require-dev": { "aura/session": "^2.1.0", @@ -33,9 +34,9 @@ "phploc/phploc": "^4.0", "phpmd/phpmd": "^2.4", "phpstan/phpstan": "^0.9.1", - "phpunit/phpunit": "^6.0", - "robmorgan/phinx": "^0.9.2", - "sebastian/phpcpd": "^3.0", + "phpunit/phpunit": "^6.5.13", + "robmorgan/phinx": "^0.10.6", + "sebastian/phpcpd": "^3.0.1", "squizlabs/php_codesniffer": "^3.0.0", "theseer/phpdox": "^0.11.0" }, @@ -44,7 +45,7 @@ "build": "robo build", "docs": "cd build && ../vendor/bin/phpdox && cd ..", "phpstan": "phpstan analyse -l 7 -c phpstan.neon src tests", - "test": "phpunit" + "test": "phpunit -c phpunit.dist.xml" }, "suggest": { "monolog/monolog": "Provides implementation of psr/log" diff --git a/phpunit.dist.xml b/phpunit.dist.xml index d094f27..7cd548d 100644 --- a/phpunit.dist.xml +++ b/phpunit.dist.xml @@ -1,17 +1,19 @@ - - - - src - - - - - tests - - + + + + src + + + + + tests + + \ No newline at end of file diff --git a/src/Config.php b/src/Config.php index 64f9224..a8df6b3 100644 --- a/src/Config.php +++ b/src/Config.php @@ -44,14 +44,25 @@ class Config implements ConfigInterface { $this->map = $this->arr($configArray); } + /** + * Does the config item exist? + * + * @param string|int|array $key + * @return bool + */ + public function has($key): bool + { + return $this->map->hasKey($key); + } + /** * Get a config value * - * @param array|string $key + * @param array|string|null $key * @return mixed * @throws ConfigException */ - public function get($key) + public function get($key = NULL) { if (\is_array($key)) { diff --git a/src/ConfigInterface.php b/src/ConfigInterface.php index 05efabc..bc9879c 100644 --- a/src/ConfigInterface.php +++ b/src/ConfigInterface.php @@ -20,13 +20,21 @@ namespace Aviat\Ion; * Standard interface for retrieving/setting configuration values */ interface ConfigInterface { + /** + * Does the config item exist? + * + * @param string|int|array $key + * @return bool + */ + public function has($key): bool; + /** * Get a config value * - * @param array|string $key + * @param array|string|null $key * @return mixed */ - public function get($key); + public function get($key = NULL); /** * Set a config value diff --git a/src/Di/Container.php b/src/Di/Container.php index 723d892..ca39b6e 100644 --- a/src/Di/Container.php +++ b/src/Di/Container.php @@ -211,8 +211,8 @@ class Container implements ContainerInterface { */ private function applyContainer($obj) { - $trait_name = __NAMESPACE__ . '\\ContainerAware'; - $interface_name = __NAMESPACE__ . '\\ContainerAwareInterface'; + $trait_name = ContainerAware::class; + $interface_name = ContainerAwareInterface::class; $uses_trait = \in_array($trait_name, class_uses($obj), TRUE); $implements_interface = \in_array($interface_name, class_implements($obj), TRUE); diff --git a/src/Di/ContainerInterface.php b/src/Di/ContainerInterface.php index 8b0c9ef..4418243 100644 --- a/src/Di/ContainerInterface.php +++ b/src/Di/ContainerInterface.php @@ -75,6 +75,7 @@ interface ContainerInterface { /** * Determine whether a logger channel is registered + * * @param string $id The logger channel * @return boolean */ diff --git a/src/Enum.php b/src/Enum.php index 8220c63..65832d0 100644 --- a/src/Enum.php +++ b/src/Enum.php @@ -27,6 +27,7 @@ abstract class Enum { * Return the list of constant values for the Enum * * @return array + * @throws \ReflectionException */ public static function getConstList(): array { @@ -47,6 +48,7 @@ abstract class Enum { * * @param mixed $key * @return boolean + * @throws \ReflectionException */ public static function isValid($key): bool { diff --git a/src/Friend.php b/src/Friend.php index 3a19527..50905d9 100644 --- a/src/Friend.php +++ b/src/Friend.php @@ -44,6 +44,7 @@ class Friend { * * @param mixed $obj * @throws InvalidArgumentException + * @throws \ReflectionException */ public function __construct($obj) { @@ -115,6 +116,7 @@ class Friend { * @param array $args * @return mixed * @throws BadMethodCallException + * @throws \ReflectionException */ public function __call(string $method, array $args) { diff --git a/src/Transformer/AbstractTransformer.php b/src/Transformer/AbstractTransformer.php index 4e7e50c..69e04e6 100644 --- a/src/Transformer/AbstractTransformer.php +++ b/src/Transformer/AbstractTransformer.php @@ -18,8 +18,10 @@ namespace Aviat\Ion\Transformer; use Aviat\Ion\StringWrapper; +use BadMethodCallException; + /** - * Base class for data trasformation + * Base class for data transformation */ abstract class AbstractTransformer implements TransformerInterface { @@ -36,13 +38,32 @@ abstract class AbstractTransformer implements TransformerInterface { /** * Transform a set of structures * - * @param array|object $collection + * @param iterable $collection * @return array */ - public function transformCollection($collection): array + public function transformCollection(iterable $collection): array { $list = (array)$collection; return array_map([$this, 'transform'], $list); } + + /** + * Untransform a set of structures + * + * Requires an 'untransform' method in the extending class + * + * @param iterable $collection + * @return array + */ + public function untransformCollection(iterable $collection): array + { + if ( ! method_exists($this, 'untransform')) + { + throw new BadMethodCallException('untransform() method does not exist.'); + } + + $list = (array)$collection; + return array_map([$this, 'untransform'], $list); + } } // End of AbstractTransformer.php \ No newline at end of file diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index d2579e9..69c56e1 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -114,11 +114,28 @@ class ArrayType { /** * Does the passed key exist in the current array? * - * @param int|string $key + * @param int|string|array $key * @return bool */ public function hasKey($key): bool { + if (\is_array($key)) + { + $pos =& $this->arr; + + foreach($key as $level) + { + if ( ! array_key_exists($level, $pos)) + { + return FALSE; + } + + $pos =& $pos[$level]; + } + + return TRUE; + } + return array_key_exists($key, $this->arr); } diff --git a/src/functions.php b/src/functions.php index 403ab0d..fb90a34 100644 --- a/src/functions.php +++ b/src/functions.php @@ -20,7 +20,7 @@ namespace Aviat\Ion; * Joins paths together. Variadic to take an * arbitrary number of arguments * - * @param string[] ...$args + * @param string ...$args * @return string */ function _dir(string ...$args): string diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index ba8a40f..a8260a0 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -25,10 +25,24 @@ class ConfigTest extends Ion_TestCase { $this->config = new Config([ 'foo' => 'bar', 'asset_path' => '/assets', - 'bar' => 'baz' + 'bar' => 'baz', + 'a' => [ + 'b' => [ + 'c' => TRUE, + ], + ], ]); } + public function testConfigHas() + { + $this->assertTrue($this->config->has('foo')); + $this->assertTrue($this->config->has(['a', 'b', 'c'])); + + $this->assertFalse($this->config->has('baz')); + $this->assertFalse($this->config->has(['c', 'b', 'a'])); + } + public function testConfigGet() { $this->assertEquals('bar', $this->config->get('foo')); @@ -48,7 +62,6 @@ class ConfigTest extends Ion_TestCase { $this->assertEquals('great', $apple['sauce']['is'], "Config value not set correctly"); $this->assertEquals('great', $this->config->get(['apple', 'sauce', 'is']), "Array argument get for config failed."); - } public function testConfigBadSet() diff --git a/tests/Transformer/AbstractTransformerTest.php b/tests/Transformer/AbstractTransformerTest.php index 7793a92..0e0571b 100644 --- a/tests/Transformer/AbstractTransformerTest.php +++ b/tests/Transformer/AbstractTransformerTest.php @@ -17,16 +17,18 @@ namespace Aviat\Ion\Tests\Transformer; use Aviat\Ion\Tests\Ion_TestCase; -use Aviat\Ion\Tests\TestTransformer; +use Aviat\Ion\Tests\{TestTransformer, TestTransformerUntransform}; class AbstractTransformerTest extends Ion_TestCase { protected $transformer; + protected $untransformer; public function setUp() { $this->transformer = new TestTransformer(); + $this->untransformer = new TestTransformerUntransform(); } public function dataTransformCollection() @@ -87,6 +89,36 @@ class AbstractTransformerTest extends Ion_TestCase { ]; } + public function dataUnTransformCollection() + { + return [ + 'object' => [ + 'original' => [ + (object)['Comedy', 'Romance', 'School', 'Harem'], + (object)['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'], + (object)['Comedy', 'Sci-Fi'] + ], + 'expected' => [ + ['Comedy', 'Romance', 'School', 'Harem'], + ['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'], + ['Comedy', 'Sci-Fi'] + ] + ], + 'array' => [ + 'original' => [ + ['Comedy', 'Romance', 'School', 'Harem'], + ['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'], + ['Comedy', 'Sci-Fi'] + ], + 'expected' => [ + ['Comedy', 'Romance', 'School', 'Harem'], + ['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo'], + ['Comedy', 'Sci-Fi'] + ] + ] + ]; + } + public function testTransform() { $data = $this->dataTransformCollection(); @@ -105,4 +137,22 @@ class AbstractTransformerTest extends Ion_TestCase { $actual = $this->transformer->transformCollection($original); $this->assertEquals($expected, $actual); } + + /** + * @dataProvider dataUnTransformCollection + */ + public function testUntransformCollection($original, $expected) + { + $actual = $this->untransformer->untransformCollection($original); + $this->assertEquals($expected, $actual); + } + + /** + * @dataProvider dataUnTransformCollection + */ + public function testUntransformCollectionWithException($original, $expected) + { + $this->expectException(\BadMethodCallException::class); + $this->transformer->untransformCollection($original); + } } \ No newline at end of file diff --git a/tests/Type/ArrayTypeTest.php b/tests/Type/ArrayTypeTest.php index 6f687cc..227acb6 100644 --- a/tests/Type/ArrayTypeTest.php +++ b/tests/Type/ArrayTypeTest.php @@ -169,6 +169,29 @@ class ArrayTypeTest extends Ion_TestCase { $this->assertFalse($obj->hasKey('b')); } + public function testHasKeyArray() + { + $obj = $this->arr([ + 'foo' => [ + 'bar' => [ + 'baz' => [ + 'foobar' => NULL, + 'one' => 1, + ], + ], + ], + ]); + + $this->assertTrue($obj->hasKey(['foo'])); + $this->assertTrue($obj->hasKey(['foo', 'bar'])); + $this->assertTrue($obj->hasKey(['foo', 'bar', 'baz'])); + $this->assertTrue($obj->hasKey(['foo', 'bar', 'baz', 'one'])); + $this->assertTrue($obj->hasKey(['foo', 'bar', 'baz', 'foobar'])); + + $this->assertFalse($obj->hasKey(['foo', 'baz'])); + $this->assertFalse($obj->hasKey(['bar', 'baz'])); + } + public function testHas() { $obj = $this->arr([1, 2, 6, 8, 11]); diff --git a/tests/mocks.php b/tests/mocks.php index c789d81..3635f5e 100644 --- a/tests/mocks.php +++ b/tests/mocks.php @@ -81,6 +81,13 @@ class TestTransformer extends AbstractTransformer { } } +class TestTransformerUntransform extends TestTransformer { + public function untransform($item) + { + return (array)$item; + } +} + trait MockViewOutputTrait { /*protected function output() { $reflect = new ReflectionClass($this);