diff --git a/src/Api/ActionApi.php b/src/Api/ActionApi.php index 233322e..8896385 100644 --- a/src/Api/ActionApi.php +++ b/src/Api/ActionApi.php @@ -58,6 +58,11 @@ class ActionApi extends Api implements Action */ private $return; + /** + * @var TypeCatalog + */ + private $typeCatalog; + /** * Action constructor. * @param KatanaLogger $logger @@ -72,6 +77,7 @@ class ActionApi extends Api implements Action * @param string $actionName * @param ZeroMQRuntimeCaller $caller * @param Transport $transport + * @param TypeCatalog $typeCatalog * @param Param[] $params */ public function __construct( @@ -87,6 +93,7 @@ public function __construct( string $actionName, ZeroMQRuntimeCaller $caller, Transport $transport, + TypeCatalog $typeCatalog, array $params = [] ) { parent::__construct( @@ -105,27 +112,10 @@ public function __construct( $this->caller = $caller; $this->transport = $transport; $this->transportCopy = clone $transport; + $this->typeCatalog = $typeCatalog; $this->params = $this->prepareParams($params); } - /** - * @param array $value - * @return bool - */ - private function isArrayType(array $value): bool - { - return array_keys($value) === range(0, count($value) -1); - } - - /** - * @param array $value - * @return bool - */ - private function isObjectType(array $value): bool - { - return count(array_filter(array_keys($value), 'is_string')) === count($value); - } - /** * @return Transport */ @@ -247,8 +237,9 @@ public function setDownload(FileInterface $file): Action */ public function setEntity(array $entity): Action { - if (!$this->isObjectType($entity)) { - throw new TransportException('Unexpected collection'); + $type = $this->typeCatalog::TYPE_OBJECT; + if (!$this->typeCatalog->validate($type, $entity)) { + throw new TransportException('Invalid Entity'); } $this->transport->setData($this->name, $this->version, $this->actionName, $entity); @@ -263,8 +254,9 @@ public function setEntity(array $entity): Action */ public function setCollection(array $collection): Action { - if (!$this->isArrayType($collection)) { - throw new TransportException('Unexpected entity'); + $type = $this->typeCatalog::TYPE_ARRAY; + if (!$this->typeCatalog->validate($type, $collection)) { + throw new TransportException('Invalid Collection'); } $this->transport->setCollection($this->name, $this->version, $this->actionName, $collection); @@ -570,7 +562,7 @@ public function setReturn($value): Action )); } - if (!$this->validate($value, $action->getReturnType())) { + if (!$this->typeCatalog->validate($action->getReturnType(), $value)) { throw new InvalidValueException(sprintf( 'Invalid return type given in "%s" (%s) for action: "%s"', $this->name, @@ -614,60 +606,7 @@ public function getReturn() $service = $this->getServiceSchema($this->name, $this->version); $action = $service->getActionSchema($this->actionName); - return $this->getDefaultReturn($action->getReturnType()); - } - } - - /** - * @param string $type - * @return mixed - * @throws InvalidValueException - */ - private function getDefaultReturn(string $type) - { - switch ($type) { - case 'null': - return null; - case 'boolean': - return false; - case 'integer': - case 'float': - return 0; - case 'string': - return ''; - case 'array': - case 'object': - return []; + return $this->typeCatalog->getDefault($action->getReturnType()); } - - throw new InvalidValueException("Invalid value type: $type"); - } - - /** - * @param mixed $value - * @param string $type - * @return bool - * @throws InvalidValueException - */ - private function validate($value, string $type): bool - { - switch ($type) { - case 'null': - return is_null($value); - case 'boolean': - return is_bool($value); - case 'integer': - return is_integer($value); - case 'float': - return is_float($value); - case 'string': - return is_string($value); - case 'array': - return $this->isArrayType($value); - case 'object': - return $this->isObjectType($value); - } - - throw new InvalidValueException("Invalid value type: $type"); } } diff --git a/src/Api/Factory/ServiceApiFactory.php b/src/Api/Factory/ServiceApiFactory.php index 4811b54..6950837 100644 --- a/src/Api/Factory/ServiceApiFactory.php +++ b/src/Api/Factory/ServiceApiFactory.php @@ -16,6 +16,7 @@ namespace Katana\Sdk\Api\Factory; use Katana\Sdk\Api\ActionApi; +use Katana\Sdk\Api\TypeCatalog; use Katana\Sdk\Console\CliInput; use Katana\Sdk\Mapper\CompactTransportMapper; use Katana\Sdk\Messaging\MessagePackSerializer; @@ -68,6 +69,7 @@ public function build( $action, $caller, $this->mapper->getTransport($data), + new TypeCatalog(), $this->mapper->getParams($data) ); } diff --git a/src/Api/TypeCatalog.php b/src/Api/TypeCatalog.php new file mode 100644 index 0000000..c8bce7e --- /dev/null +++ b/src/Api/TypeCatalog.php @@ -0,0 +1,117 @@ +isArrayType($value); + case self::TYPE_OBJECT: + if (!is_array($value)) { + return false; + } + return $this->isObjectType($value); + } + + throw new InvalidValueException("Invalid value type: $type"); + } +} diff --git a/tests/Api/ActionApiTest.php b/tests/Api/ActionApiTest.php index 317772f..ecdc561 100644 --- a/tests/Api/ActionApiTest.php +++ b/tests/Api/ActionApiTest.php @@ -20,6 +20,7 @@ use Katana\Sdk\Api\File; use Katana\Sdk\Api\Transport; use Katana\Sdk\Api\TransportMeta; +use Katana\Sdk\Api\TypeCatalog; use Katana\Sdk\Component\Component; use Katana\Sdk\Exception\InvalidValueException; use Katana\Sdk\Logger\KatanaLogger; @@ -84,7 +85,8 @@ public function setUp() true, 'action', $caller->reveal(), - $this->transport->reveal() + $this->transport->reveal(), + new TypeCatalog() ); } diff --git a/tests/Api/TypeCatalogTest.php b/tests/Api/TypeCatalogTest.php new file mode 100644 index 0000000..32f4e90 --- /dev/null +++ b/tests/Api/TypeCatalogTest.php @@ -0,0 +1,194 @@ +typeCatalog = new TypeCatalog(); + } + + public function testNullDefault() + { + $this->assertNull( + $this->typeCatalog->getDefault(TypeCatalog::TYPE_NULL) + ); + } + + public function testBooleanDefault() + { + $this->assertFalse( + $this->typeCatalog->getDefault(TypeCatalog::TYPE_BOOLEAN) + ); + } + + public function testIntegerDefault() + { + $this->assertEquals( + 0, + $this->typeCatalog->getDefault(TypeCatalog::TYPE_INTEGER) + ); + } + + public function testFloatDefault() + { + $this->assertEquals( + 0, + $this->typeCatalog->getDefault(TypeCatalog::TYPE_FLOAT) + ); + } + + public function testStringDefault() + { + $this->assertEquals( + '', + $this->typeCatalog->getDefault(TypeCatalog::TYPE_STRING) + ); + } + + public function testArrayDefault() + { + $this->assertEquals( + [], + $this->typeCatalog->getDefault(TypeCatalog::TYPE_ARRAY) + ); + } + + public function testObjectDefault() + { + $this->assertEquals( + [], + $this->typeCatalog->getDefault(TypeCatalog::TYPE_OBJECT) + ); + } + + public function validateDataProvider() + { + return [ + // Type Null + [true, TypeCatalog::TYPE_NULL, null], + [false, TypeCatalog::TYPE_NULL, false], + [false, TypeCatalog::TYPE_NULL, true], + [false, TypeCatalog::TYPE_NULL, 0], + [false, TypeCatalog::TYPE_NULL, 42], + [false, TypeCatalog::TYPE_NULL, 0.0], + [false, TypeCatalog::TYPE_NULL, 3.1416], + [false, TypeCatalog::TYPE_NULL, ''], + [false, TypeCatalog::TYPE_NULL, 'foo'], + [false, TypeCatalog::TYPE_NULL, []], + [false, TypeCatalog::TYPE_NULL, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_NULL, ['a' => 1, 'b' => 2]], + // Type Boolean + [false, TypeCatalog::TYPE_BOOLEAN, null], + [true, TypeCatalog::TYPE_BOOLEAN, false], + [true, TypeCatalog::TYPE_BOOLEAN, true], + [false, TypeCatalog::TYPE_BOOLEAN, 0], + [false, TypeCatalog::TYPE_BOOLEAN, 42], + [false, TypeCatalog::TYPE_BOOLEAN, 0.0], + [false, TypeCatalog::TYPE_BOOLEAN, 3.1416], + [false, TypeCatalog::TYPE_BOOLEAN, ''], + [false, TypeCatalog::TYPE_BOOLEAN, 'foo'], + [false, TypeCatalog::TYPE_BOOLEAN, []], + [false, TypeCatalog::TYPE_BOOLEAN, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_BOOLEAN, ['a' => 1, 'b' => 2]], + // Type Integer + [false, TypeCatalog::TYPE_INTEGER, null], + [false, TypeCatalog::TYPE_INTEGER, false], + [false, TypeCatalog::TYPE_INTEGER, true], + [true, TypeCatalog::TYPE_INTEGER, 0], + [true, TypeCatalog::TYPE_INTEGER, 42], + [false, TypeCatalog::TYPE_INTEGER, 0.0], + [false, TypeCatalog::TYPE_INTEGER, 3.1416], + [false, TypeCatalog::TYPE_INTEGER, ''], + [false, TypeCatalog::TYPE_INTEGER, 'foo'], + [false, TypeCatalog::TYPE_INTEGER, []], + [false, TypeCatalog::TYPE_INTEGER, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_INTEGER, ['a' => 1, 'b' => 2]], + // Type Float + [false, TypeCatalog::TYPE_FLOAT, null], + [false, TypeCatalog::TYPE_FLOAT, false], + [false, TypeCatalog::TYPE_FLOAT, true], + [false, TypeCatalog::TYPE_FLOAT, 0], + [false, TypeCatalog::TYPE_FLOAT, 42], + [true, TypeCatalog::TYPE_FLOAT, 0.0], + [true, TypeCatalog::TYPE_FLOAT, 3.1416], + [false, TypeCatalog::TYPE_FLOAT, ''], + [false, TypeCatalog::TYPE_FLOAT, 'foo'], + [false, TypeCatalog::TYPE_FLOAT, []], + [false, TypeCatalog::TYPE_FLOAT, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_FLOAT, ['a' => 1, 'b' => 2]], + // Type String + [false, TypeCatalog::TYPE_STRING, null], + [false, TypeCatalog::TYPE_STRING, false], + [false, TypeCatalog::TYPE_STRING, true], + [false, TypeCatalog::TYPE_STRING, 0], + [false, TypeCatalog::TYPE_STRING, 42], + [false, TypeCatalog::TYPE_STRING, 0.0], + [false, TypeCatalog::TYPE_STRING, 3.1416], + [true, TypeCatalog::TYPE_STRING, ''], + [true, TypeCatalog::TYPE_STRING, 'foo'], + [false, TypeCatalog::TYPE_STRING, []], + [false, TypeCatalog::TYPE_STRING, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_STRING, ['a' => 1, 'b' => 2]], + // Type Array + [false, TypeCatalog::TYPE_ARRAY, null], + [false, TypeCatalog::TYPE_ARRAY, false], + [false, TypeCatalog::TYPE_ARRAY, true], + [false, TypeCatalog::TYPE_ARRAY, 0], + [false, TypeCatalog::TYPE_ARRAY, 42], + [false, TypeCatalog::TYPE_ARRAY, 0.0], + [false, TypeCatalog::TYPE_ARRAY, 3.1416], + [false, TypeCatalog::TYPE_ARRAY, ''], + [false, TypeCatalog::TYPE_ARRAY, 'foo'], + [true, TypeCatalog::TYPE_ARRAY, []], + [true, TypeCatalog::TYPE_ARRAY, ['a', 'b', 'c']], + [false, TypeCatalog::TYPE_ARRAY, ['a' => 1, 'b' => 2]], + // Type Object + [false, TypeCatalog::TYPE_OBJECT, null], + [false, TypeCatalog::TYPE_OBJECT, false], + [false, TypeCatalog::TYPE_OBJECT, true], + [false, TypeCatalog::TYPE_OBJECT, 0], + [false, TypeCatalog::TYPE_OBJECT, 42], + [false, TypeCatalog::TYPE_OBJECT, 0.0], + [false, TypeCatalog::TYPE_OBJECT, 3.1416], + [false, TypeCatalog::TYPE_OBJECT, ''], + [false, TypeCatalog::TYPE_OBJECT, 'foo'], + [true, TypeCatalog::TYPE_OBJECT, []], + [false, TypeCatalog::TYPE_OBJECT, ['a', 'b', 'c']], + [true, TypeCatalog::TYPE_OBJECT, ['a' => 1, 'b' => 2]], + ]; + } + + /** + * @dataProvider validateDataProvider + */ + public function testValidateNullType(bool $expected, string $type, $value) + { + $this->assertEquals( + $expected, + $this->typeCatalog->validate($type, $value) + ); + } +}