diff --git a/src/Configuration/Extractor.php b/src/Configuration/Extractor.php index 1366d28..e095c4d 100644 --- a/src/Configuration/Extractor.php +++ b/src/Configuration/Extractor.php @@ -4,7 +4,9 @@ namespace Kiboko\Plugin\Sylius\Configuration; +use Kiboko\Plugin\Sylius\Validator\ApiType; use Kiboko\Plugin\Sylius\Validator\ExtractorConfigurationValidator; +use Kiboko\Plugin\Sylius\Validator\LoaderConfigurationValidator; use Symfony\Component\Config; use function Kiboko\Component\SatelliteToolbox\Configuration\asExpression; @@ -13,7 +15,6 @@ final class Extractor implements Config\Definition\ConfigurationInterface { - public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder { $filters = new Search(); @@ -23,19 +24,35 @@ public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Bui /* @phpstan-ignore-next-line */ $builder->getRootNode() ->validate() - ->ifArray() - ->then(fn(array $item) => ExtractorConfigurationValidator::validate($item)) + ->always(fn(array $item) => ExtractorConfigurationValidator::validate($item)) //store the item value ->end() ->children() ->scalarNode('api_type') ->isRequired() ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => ExtractorConfigurationValidator::validateApiType($item)) //check index of the item value + ->end() ->end() ->scalarNode('type') ->isRequired() + ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => ExtractorConfigurationValidator::validateType($item)) //check index of the item value + ->end() + ->end() + ->scalarNode('method') + ->isRequired() + ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => ExtractorConfigurationValidator::validateMethod($item)) //check index of the item value + ->end() ->end() - ->scalarNode('method')->end() ->scalarNode('code') + ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => ExtractorConfigurationValidator::validateCode($item)) //check index of the item value + ->end() ->validate() ->ifTrue(isExpression()) ->then(asExpression()) diff --git a/src/Configuration/Loader.php b/src/Configuration/Loader.php index 112c6c2..9911868 100644 --- a/src/Configuration/Loader.php +++ b/src/Configuration/Loader.php @@ -4,6 +4,7 @@ namespace Kiboko\Plugin\Sylius\Configuration; +use Kiboko\Plugin\Sylius\Validator\ApiType; use Kiboko\Plugin\Sylius\Validator\LoaderConfigurationValidator; use Symfony\Component\Config; @@ -16,22 +17,27 @@ public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Bui /* @phpstan-ignore-next-line */ $builder->getRootNode() - ->validate() - ->ifArray() - ->then(fn(array $item) => LoaderConfigurationValidator::validate($item)) - ->end() ->children() ->scalarNode('api_type') ->isRequired() ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => LoaderConfigurationValidator::validateApiType($item)) + ->end() ->end() ->scalarNode('type') ->isRequired() ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => LoaderConfigurationValidator::validateType($item)) + ->end() ->end() ->scalarNode('method') ->isRequired() ->cannotBeEmpty() + ->validate() + ->always(fn(string $item) => LoaderConfigurationValidator::validateMethod($item)) + ->end() ->end() ->end() ; diff --git a/src/Validator/ApiType.php b/src/Validator/ApiType.php index d963847..dfefb7e 100644 --- a/src/Validator/ApiType.php +++ b/src/Validator/ApiType.php @@ -9,4 +9,14 @@ enum ApiType: string case ADMIN = 'admin'; case SHOP = 'shop'; case LEGACY = 'legacy'; + + public static function casesValue(): array + { + $apiTypeCases = []; + foreach (ApiType::cases() as $cases) + { + $apiTypeCases[] = $cases->value; + } + return $apiTypeCases; + } } diff --git a/src/Validator/ExtractorConfigurationValidator.php b/src/Validator/ExtractorConfigurationValidator.php index 5a391e3..fa8a63a 100644 --- a/src/Validator/ExtractorConfigurationValidator.php +++ b/src/Validator/ExtractorConfigurationValidator.php @@ -2,6 +2,9 @@ namespace Kiboko\Plugin\Sylius\Validator; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; +use function PHPUnit\Framework\isEmpty; + class ExtractorConfigurationValidator implements ConfigurationValidatorInterface { private static array $endpointsLegacy = [ @@ -456,40 +459,77 @@ class ExtractorConfigurationValidator implements ConfigurationValidatorInterface 'adjustment', 'order', ]; + + private static array $item = []; + + public static function getEndpointsApiType(): array + { + return match (self::$currentApiType) { + ApiType::ADMIN->value => self::$endpointsAdmin, + ApiType::SHOP->value => self::$endpointsShop, + ApiType::LEGACY->value => self::$endpointsLegacy + }; + } + + public static function getDoubleEndpointsApiType(): array + { + return match (self::$currentApiType) { + ApiType::ADMIN->value => self::$doubleEndpointsAdmin, + ApiType::SHOP->value => self::$doubleEndpointsShop, + ApiType::LEGACY->value => self::$doubleEndpointsLegacy + }; + } + public static string $currentApiType; + public static string $currentType; + public static function validate(array $item): array { - switch($item['api_type']) { - case ApiType::ADMIN->value: - $endpoints = self::$endpointsAdmin; - $doubleEndpoints = self::$doubleEndpointsAdmin; - break; - case ApiType::SHOP->value: - $endpoints = self::$endpointsShop; - $doubleEndpoints = self::$doubleEndpointsShop; - break; - case ApiType::LEGACY->value: - $endpoints = self::$endpointsLegacy; - $doubleEndpoints = self::$doubleEndpointsLegacy; - break; - default: - $endpoints = []; - $doubleEndpoints = []; - break; + if(\in_array($item['type'], self::getDoubleEndpointsApiType()) && !\array_key_exists('code', $item)) { + throw new InvalidConfigurationException('The code parameters is required and cannot be empty because you choose a type: ' . $item['type']); } - if (!\in_array($item['type'], array_merge(array_keys($endpoints), $doubleEndpoints))) { - throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s', implode(', ', array_merge(array_keys($endpoints), $doubleEndpoints)), json_encode($item['type'], \JSON_THROW_ON_ERROR))); + return $item; + } + + public static function validateApiType(string $apiType) + { + self::$currentApiType = $apiType; + if(!\in_array($apiType, ApiType::casesValue())){ + throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s.', implode(', ', ApiType::casesValue()), json_encode($apiType, \JSON_THROW_ON_ERROR))); } + return $apiType; + } + + public static function validateType(string $type) + { + self::$currentType = $type; + $endpoints = self::getEndpointsApiType(); + $doubleEndpoints = self::getDoubleEndpointsApiType(); + if (!\in_array($type, array_merge(array_keys($endpoints), $doubleEndpoints))) { + throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s.', implode(', ', array_merge(array_keys($endpoints), $doubleEndpoints)), json_encode($type, \JSON_THROW_ON_ERROR))); + } + return $type; + } + + public static function validateMethod(string $method) + { + $endpoints = self::getEndpointsApiType(); + $doubleEndpoints = self::getDoubleEndpointsApiType(); if ( - \array_key_exists($item['type'], $endpoints) - && !\in_array($item['method'], $endpoints[$item['type']]) - && !\in_array($item['type'], $doubleEndpoints) + \array_key_exists(self::$currentType, $endpoints) + && !\in_array($method, $endpoints[self::$currentType]) + && !\in_array(self::$currentType, $doubleEndpoints) ) { - throw new \InvalidArgumentException(sprintf('The value should be one of [%s], got %s.', implode(', ', $endpoints[$item['type']]), json_encode($item['method'], \JSON_THROW_ON_ERROR))); - } - if (\in_array($item['type'], $doubleEndpoints) && !\array_key_exists('code', $item)) { - throw new \InvalidArgumentException(sprintf('The %s type should have a "code" field set.', $item['type'])); + throw new \InvalidArgumentException(sprintf('The value should be one of [%s], got %s.', implode(', ', $endpoints[self::$currentType]), json_encode($method, \JSON_THROW_ON_ERROR))); } + return $method; + } - return $item; + public static function validateCode(string $code) + { + $doubleEndpoints = self::getDoubleEndpointsApiType(); + if (\in_array(self::$currentType, $doubleEndpoints)) { + throw new \InvalidArgumentException(sprintf('The %s type should have a "code" field set.', self::$currentType), json_encode($code, \JSON_THROW_ON_ERROR)); + } + return $code; } } diff --git a/src/Validator/LoaderConfigurationValidator.php b/src/Validator/LoaderConfigurationValidator.php index a028276..23f5fc2 100644 --- a/src/Validator/LoaderConfigurationValidator.php +++ b/src/Validator/LoaderConfigurationValidator.php @@ -2,6 +2,8 @@ namespace Kiboko\Plugin\Sylius\Validator; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; + class LoaderConfigurationValidator implements ConfigurationValidatorInterface { private static array $endpointsLegacy = [ @@ -249,19 +251,59 @@ class LoaderConfigurationValidator implements ConfigurationValidatorInterface 'verify', ], ]; - public static function validate(array $item): array + + + public static string $currentApiType; + public static string $currentType; + + public static function getEndpointsApiType(): array { - $endpoints = match ($item['api_type']) { + return match (self::$currentApiType) { ApiType::ADMIN->value => self::$endpointsAdmin, ApiType::SHOP->value => self::$endpointsShop, ApiType::LEGACY->value => self::$endpointsLegacy }; + } + public static function validate(array $item): array + { + $endpoints = self::getEndpointsApiType(); if (!\in_array($item['type'], array_keys($endpoints))) { - throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s', implode(', ', array_keys($endpoints)), json_encode($item['type'], \JSON_THROW_ON_ERROR))); + throw new \InvalidArgumentException(sprintf('the value "type" should be one of [%s], got %s', implode(', ', array_keys($endpoints)), json_encode($item['type'], \JSON_THROW_ON_ERROR))); } if (!\in_array($item['method'], $endpoints[$item['type']])) { - throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s', implode(', ', $endpoints[$item['type']]), json_encode($item['method'], \JSON_THROW_ON_ERROR))); + throw new \InvalidArgumentException(sprintf('the value "method" should be one of [%s], got %s', implode(', ', $endpoints[$item['type']]), json_encode($item['method'], \JSON_THROW_ON_ERROR))); } return $item; } + + public static function validateApiType(string $apiType) + { + self::$currentApiType = $apiType; + if(!\in_array($apiType, ApiType::casesValue())){ + throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s.', implode(', ', ApiType::casesValue()), json_encode($apiType, \JSON_THROW_ON_ERROR))); + } + return $apiType; + } + + public static function validateType(string $type) + { + self::$currentType = $type; + $endpoints = self::getEndpointsApiType(); + if (!\in_array($type, array_keys($endpoints))) { + throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s.', implode(', ', array_keys($endpoints)), json_encode($type, \JSON_THROW_ON_ERROR))); + } + return $type; + } + + public static function validateMethod(string $method) + { + $endpoints = self::getEndpointsApiType(); + if ( + \array_key_exists(self::$currentType, $endpoints) + && !\in_array($method, $endpoints[self::$currentType]) + ) { + throw new \InvalidArgumentException(sprintf('The value should be one of [%s], got %s.', implode(', ', $endpoints[self::$currentType]), json_encode($method, \JSON_THROW_ON_ERROR))); + } + return $method; + } } diff --git a/tests/functional/Builder/ClientTest.php b/tests/functional/Builder/ClientTest.php index 8e693a1..38f9074 100644 --- a/tests/functional/Builder/ClientTest.php +++ b/tests/functional/Builder/ClientTest.php @@ -41,6 +41,8 @@ public function testExpectingTokenOrPassword(): void $this->expectException(MissingAuthenticationMethodException::class); $this->expectExceptionMessage('Please check your client builder, you should either call withToken() or withPassword() methods.'); + $client->withApiType('legacy'); + $client->getNode(); } } diff --git a/tests/functional/Builder/Extractor/ExtractorTest.php b/tests/functional/Builder/Extractor/ExtractorTest.php index d6cdd46..8f60e49 100644 --- a/tests/functional/Builder/Extractor/ExtractorTest.php +++ b/tests/functional/Builder/Extractor/ExtractorTest.php @@ -46,6 +46,7 @@ public function testAllProducts(): void $builder = new Extractor($capacity); $builder->withClient($client->getNode()); + $builder->withApiType('legacy'); $this->assertBuildsExtractorExtractsExactly( [ @@ -189,6 +190,7 @@ public function testAllProductsWithSearch(): void $builder = new Extractor($capacity); $builder->withClient($client->getNode()); + $builder->withApiType('legacy'); $this->assertBuildsExtractorExtractsExactly( [ diff --git a/tests/functional/Builder/Loader/LoaderTest.php b/tests/functional/Builder/Loader/LoaderTest.php index b7d9ac7..799ba08 100644 --- a/tests/functional/Builder/Loader/LoaderTest.php +++ b/tests/functional/Builder/Loader/LoaderTest.php @@ -47,6 +47,7 @@ public function testUpsertProduct(): void $builder = new Loader($capacity); $builder->withClient($client->getNode()); + $builder->withApiType('legacy'); $this->assertBuildsLoaderLoadsExactly( [ @@ -95,6 +96,7 @@ public function testCreateProduct(): void $builder = new Loader($capacity); $builder->withClient($client->getNode()); + $builder->withApiType('legacy'); $this->assertBuildsLoaderLoadsExactly( [ diff --git a/tests/functional/Configuration/ExtractorTest.php b/tests/functional/Configuration/ExtractorTest.php index 3427e3c..f682f33 100644 --- a/tests/functional/Configuration/ExtractorTest.php +++ b/tests/functional/Configuration/ExtractorTest.php @@ -23,11 +23,13 @@ public static function validDataProvider(): iterable 'config' => [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', 'search' => [], ], 'expected' => [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', 'search' => [], ], ]; @@ -35,11 +37,13 @@ public static function validDataProvider(): iterable 'config' => [ 'type' => 'products', 'method' => 'listPerPage', + 'api_type' => 'legacy', 'search' => [], ], 'expected' => [ 'type' => 'products', 'method' => 'listPerPage', + 'api_type' => 'legacy', 'search' => [], ], ]; @@ -47,11 +51,13 @@ public static function validDataProvider(): iterable 'config' => [ 'type' => 'products', 'method' => 'get', + 'api_type' => 'legacy', 'search' => [], ], 'expected' => [ 'type' => 'products', 'method' => 'get', + 'api_type' => 'legacy', 'search' => [], ], ]; @@ -65,7 +71,7 @@ public function testValidConfig(array $config, array $expected): void $this->assertSame($expected, $this->processor->processConfiguration($client, [$config])); } - public function testWrongMethod(): void + public function testWrongApiType(): void { $client = new Configuration\Extractor(); @@ -73,13 +79,14 @@ public function testWrongMethod(): void Config\Definition\Exception\InvalidConfigurationException::class, ); $this->expectExceptionMessage( - 'Invalid configuration for path "extractor": The value should be one of [listPerPage, all, get], got "invalidValue".', + 'Invalid configuration for path "extractor.api_type": the value should be one of [admin, shop, legacy], got "invalidValue".', ); $this->processor->processConfiguration($client, [ [ + 'api_type' => 'invalidValue', 'type' => 'products', - 'method' => 'invalidValue', + 'method' => 'all' ], ]); } @@ -92,12 +99,34 @@ public function testWrongType(): void Config\Definition\Exception\InvalidConfigurationException::class, ); $this->expectExceptionMessage( - 'Invalid configuration for path "extractor.type": the value should be one of [channels, countries, carts, currencies, customers, exchangeRates, locales, orders, payments, paymentMethods, products, productAttributes, productAssociationTypes, productOptions, promotions, shipments, shippingCategories, taxCategories, taxRates, taxons, users, zones, productReviews, productVariants, promotionCoupons], got "wrong"', + 'Invalid configuration for path "extractor.type": the value should be one of [channels, countries, carts, currencies, customers, exchangeRates, locales, orders, payments, paymentMethods, products, productAttributes, productAssociationTypes, productOptions, promotions, shipments, shippingCategories, taxCategories, taxRates, taxons, users, zones, productReviews, productVariants, promotionCoupons], got "wrong".', ); $this->processor->processConfiguration($client, [ [ 'type' => 'wrong', + 'api_type' => 'legacy', + 'method' => 'all' + ], + ]); + } + + public function testWrongMethod(): void + { + $client = new Configuration\Extractor(); + + $this->expectException( + Config\Definition\Exception\InvalidConfigurationException::class, + ); + $this->expectExceptionMessage( + 'Invalid configuration for path "extractor.method": The value should be one of [listPerPage, all, get], got "invalidValue".', + ); + + $this->processor->processConfiguration($client, [ + [ + 'type' => 'products', + 'method' => 'invalidValue', + 'api_type' => 'legacy', ], ]); } @@ -110,13 +139,14 @@ public function testMissingCode(): void Config\Definition\Exception\InvalidConfigurationException::class, ); $this->expectExceptionMessage( - 'The productReviews type should have a "code" field set.', + 'The code parameters is required and cannot be empty because you choose a type: productReviews', ); $this->processor->processConfiguration($client, [ [ 'type' => 'productReviews', 'method' => 'get', + 'api_type' => 'legacy', ], ]); } diff --git a/tests/functional/Configuration/LoaderTest.php b/tests/functional/Configuration/LoaderTest.php index 7ee2598..b89c5c7 100644 --- a/tests/functional/Configuration/LoaderTest.php +++ b/tests/functional/Configuration/LoaderTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace functional\Configuration; +namespace functional\Kiboko\Plugin\Sylius\Configuration; use Kiboko\Plugin\Sylius\Configuration; use PHPUnit\Framework\TestCase; @@ -16,6 +16,45 @@ protected function setUp(): void { $this->processor = new Config\Definition\Processor(); } + public function testWrongApiType(): void + { + $client = new Configuration\Extractor(); + + $this->expectException( + Config\Definition\Exception\InvalidConfigurationException::class, + ); + $this->expectExceptionMessage( + 'Invalid configuration for path "extractor.api_type": the value should be one of [admin, shop, legacy], got "invalidValue".', + ); + + $this->processor->processConfiguration($client, [ + [ + 'api_type' => 'invalidValue', + 'type' => 'products', + 'method' => 'all' + ], + ]); + } + + public function testWrongType(): void + { + $client = new Configuration\Extractor(); + + $this->expectException( + Config\Definition\Exception\InvalidConfigurationException::class, + ); + $this->expectExceptionMessage( + 'Invalid configuration for path "extractor.type": the value should be one of [channels, countries, carts, currencies, customers, exchangeRates, locales, orders, payments, paymentMethods, products, productAttributes, productAssociationTypes, productOptions, promotions, shipments, shippingCategories, taxCategories, taxRates, taxons, users, zones, productReviews, productVariants, promotionCoupons], got "wrong".', + ); + + $this->processor->processConfiguration($client, [ + [ + 'type' => 'wrong', + 'api_type' => 'legacy', + 'method' => 'all' + ], + ]); + } public function testWrongMethod(): void { @@ -25,13 +64,14 @@ public function testWrongMethod(): void Config\Definition\Exception\InvalidConfigurationException::class, ); $this->expectExceptionMessage( - 'Invalid configuration for path "loader": the value should be one of [create, upsert, delete], got "invalidValue"', + 'Invalid configuration for path "loader.method": The value should be one of [create, upsert, delete], got "invalidValue".', ); $this->processor->processConfiguration($client, [ [ 'type' => 'products', 'method' => 'invalidValue', + 'api_type' => 'legacy', ], ]); } diff --git a/tests/functional/Factory/ExtractorTest.php b/tests/functional/Factory/ExtractorTest.php index c3c0de4..34bbca1 100644 --- a/tests/functional/Factory/ExtractorTest.php +++ b/tests/functional/Factory/ExtractorTest.php @@ -17,6 +17,7 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', ], ]; @@ -24,6 +25,7 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'listPerPage', + 'api_type' => 'legacy', ], ]; } @@ -43,12 +45,20 @@ public static function wrongConfigs(): \Generator 'config' => [ 'type' => 'wrong', 'method' => 'all', + 'api_type' => 'legacy', ], ]; yield [ 'config' => [ 'type' => 'products', 'method' => 'wrong', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'api_type' => 'legacy', ], ]; yield [ diff --git a/tests/functional/Factory/LoaderTest.php b/tests/functional/Factory/LoaderTest.php index cf460aa..d95436f 100644 --- a/tests/functional/Factory/LoaderTest.php +++ b/tests/functional/Factory/LoaderTest.php @@ -16,6 +16,7 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'create', + 'api_type' => 'legacy', ], ]; @@ -23,6 +24,7 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'upsert', + 'api_type' => 'legacy', ], ]; } @@ -42,17 +44,20 @@ public static function wrongConfigs(): \Generator 'config' => [ 'type' => 'wrong', 'method' => 'all', + 'api_type' => 'legacy', ], ]; yield [ 'config' => [ 'type' => 'products', 'method' => 'wrong', + 'api_type' => 'legacy', ], ]; yield [ 'config' => [ 'type' => 'products', + 'api_type' => 'legacy', ], ]; }