diff --git a/.github/workflows/infection.yaml b/.github/workflows/infection.yaml index c5adb1e..3220a7b 100644 --- a/.github/workflows/infection.yaml +++ b/.github/workflows/infection.yaml @@ -23,8 +23,8 @@ jobs: - name: Infection run: | - wget -q https://github.com/infection/infection/releases/download/0.26.18/infection.phar - wget -q https://github.com/infection/infection/releases/download/0.26.18/infection.phar.asc + wget -q https://github.com/infection/infection/releases/download/0.26.20/infection.phar + wget -q https://github.com/infection/infection/releases/download/0.26.20/infection.phar.asc chmod +x infection.phar ./infection.phar diff --git a/composer.lock b/composer.lock index f96587f..2b9c0a8 100644 --- a/composer.lock +++ b/composer.lock @@ -4866,16 +4866,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.1.1", + "version": "10.2.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0d9401b7e8245d71079e249e3cb868e9d2337887" + "reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0d9401b7e8245d71079e249e3cb868e9d2337887", - "reference": "0d9401b7e8245d71079e249e3cb868e9d2337887", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c17815c129f133f3019cc18e8d0c8622e6d9bcd", + "reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd", "shasum": "" }, "require": { @@ -4915,7 +4915,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "10.2-dev" } }, "autoload": { @@ -4947,7 +4947,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.1.1" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.6" }, "funding": [ { @@ -4963,7 +4963,7 @@ "type": "tidelift" } ], - "time": "2023-04-17T12:17:05+00:00" + "time": "2023-07-17T12:08:28+00:00" }, { "name": "psr/event-dispatcher", diff --git a/phpunit.xml b/phpunit.xml index eadaa79..41806ce 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,31 +1,36 @@ - - + + - tests/functional/ + tests/functional - + - src + src - + diff --git a/src/ApiType.php b/src/ApiType.php new file mode 100644 index 0000000..8be5d1d --- /dev/null +++ b/src/ApiType.php @@ -0,0 +1,11 @@ +clientId = $clientId; + $this->secret = $secret; + + return $this; } public function withToken(Node\Expr $token, Node\Expr $refreshToken): self @@ -67,17 +80,16 @@ public function withFileSystem(Node\Expr $fileSystem): self return $this; } + public function withClientBuilder(Node\Expr $client): self + { + $this->client = $client; + + return $this; + } + public function getNode(): Node\Expr\MethodCall { - $instance = new Node\Expr\MethodCall( - var: new Node\Expr\New_( - new Node\Name\FullyQualified('Diglin\\Sylius\\ApiClient\\SyliusClientBuilder'), - ), - name: new Node\Identifier('setBaseUri'), - args: [ - new Node\Arg($this->baseUrl), - ], - ); + $instance = $this->client; if (null !== $this->httpClient) { $instance = new Node\Expr\MethodCall( @@ -126,6 +138,17 @@ public function getNode(): Node\Expr\MethodCall ); } + private function getClientBuilderNode(): Node\Expr\MethodCall + { + return new Node\Expr\MethodCall( + var: $this->client, + name: new Node\Identifier('setBaseUri'), + args: [ + new Node\Arg($this->baseUrl), + ], + ); + } + private function getFactoryMethod(): string { if (null !== $this->password) { @@ -143,19 +166,23 @@ private function getFactoryArguments(): array { if (null !== $this->password) { return [ - $this->clientId, - $this->secret, $this->username, $this->password, ]; } if (null !== $this->refreshToken) { + if ($this->apiType === ApiType::LEGACY->value) { + return [ + $this->clientId, + $this->secret, + $this->token, + $this->refreshToken, + ]; + } + return [ - $this->clientId, - $this->secret, $this->token, - $this->refreshToken, ]; } diff --git a/src/Builder/Extractor.php b/src/Builder/Extractor.php index cfe674f..c6e6abd 100644 --- a/src/Builder/Extractor.php +++ b/src/Builder/Extractor.php @@ -12,9 +12,11 @@ final class Extractor implements StepBuilderInterface { private ?Node\Expr $logger = null; private ?Node\Expr $client = null; + private ?Node $type = null; - public function __construct(private readonly Builder $capacity) - { + public function __construct( + private readonly Builder $capacity, + ) { } public function withClient(Node\Expr $client): self @@ -24,6 +26,13 @@ public function withClient(Node\Expr $client): self return $this; } + public function withClientType(Node $type): self + { + $this->type = $type; + + return $this; + } + public function withLogger(Node\Expr $logger): self { $this->logger = $logger; @@ -55,18 +64,7 @@ class: new Node\Stmt\Class_( name: new Node\Identifier(name: '__construct'), subNodes: [ 'flags' => Node\Stmt\Class_::MODIFIER_PUBLIC, - 'params' => [ - new Node\Param( - var: new Node\Expr\Variable('client'), - type: new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusLegacyClientInterface::class), - flags: Node\Stmt\Class_::MODIFIER_PUBLIC, - ), - new Node\Param( - var: new Node\Expr\Variable('logger'), - type: new Node\Name\FullyQualified(name: \Psr\Log\LoggerInterface::class), - flags: Node\Stmt\Class_::MODIFIER_PUBLIC, - ), - ], + 'params' => $this->getParamsNode(), ], ), new Node\Stmt\ClassMethod( @@ -133,4 +131,20 @@ class: new Node\Stmt\Class_( ], ); } + + public function getParamsNode(): array + { + return [ + new Node\Param( + var: new Node\Expr\Variable('client'), + type: $this->type, + flags: Node\Stmt\Class_::MODIFIER_PRIVATE, + ), + new Node\Param( + var: new Node\Expr\Variable('logger'), + type: new Node\Name\FullyQualified(name: \Psr\Log\LoggerInterface::class), + flags: Node\Stmt\Class_::MODIFIER_PRIVATE, + ), + ]; + } } diff --git a/src/Builder/Loader.php b/src/Builder/Loader.php index d5c4f57..dd7a24e 100644 --- a/src/Builder/Loader.php +++ b/src/Builder/Loader.php @@ -12,9 +12,11 @@ final class Loader implements StepBuilderInterface { private ?Node\Expr $logger = null; private ?Node\Expr $client = null; + private ?Node $type = null; - public function __construct(private readonly Builder $capacity) - { + public function __construct( + private readonly Builder $capacity + ) { } public function withClient(Node\Expr $client): self @@ -24,6 +26,13 @@ public function withClient(Node\Expr $client): self return $this; } + public function withClientType(Node $type): self + { + $this->type = $type; + + return $this; + } + public function withLogger(Node\Expr $logger): self { $this->logger = $logger; @@ -55,18 +64,7 @@ class: new Node\Stmt\Class_( name: new Node\Identifier(name: '__construct'), subNodes: [ 'flags' => Node\Stmt\Class_::MODIFIER_PUBLIC, - 'params' => [ - new Node\Param( - var: new Node\Expr\Variable('client'), - type: new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusLegacyClientInterface::class), - flags: Node\Stmt\Class_::MODIFIER_PRIVATE, - ), - new Node\Param( - var: new Node\Expr\Variable('logger'), - type: new Node\Name\FullyQualified(name: \Psr\Log\LoggerInterface::class), - flags: Node\Stmt\Class_::MODIFIER_PRIVATE, - ), - ], + 'params' => $this->getParamsNode(), ], ), new Node\Stmt\ClassMethod( @@ -139,4 +137,20 @@ class: new Node\Stmt\Class_( ], ); } + + public function getParamsNode(): array + { + return [ + new Node\Param( + var: new Node\Expr\Variable('client'), + type: $this->type, + flags: Node\Stmt\Class_::MODIFIER_PRIVATE, + ), + new Node\Param( + var: new Node\Expr\Variable('logger'), + type: new Node\Name\FullyQualified(name: \Psr\Log\LoggerInterface::class), + flags: Node\Stmt\Class_::MODIFIER_PRIVATE, + ), + ]; + } } diff --git a/src/Builder/Search.php b/src/Builder/Search.php index fe16ec9..5f1572f 100644 --- a/src/Builder/Search.php +++ b/src/Builder/Search.php @@ -9,14 +9,15 @@ final class Search implements Builder { - public function __construct(private array $filters = []) - { + public function __construct( + private array $filters = [] + ) { } public function addFilter( Node\Expr $field, Node\Expr $operator, - Node\Expr $value = null, + ?Node\Expr $value = null, ?Node\Expr $scope = null, ?Node\Expr $locale = null ): self { @@ -28,7 +29,7 @@ public function addFilter( value: $operator, ), new Node\Arg( - value: $value, + value: $value ?? new Node\Expr\ConstFetch(new Node\Name('null')), ), ]; @@ -41,7 +42,7 @@ public function addFilter( } if (null !== $locale) { $options[] = new Node\Expr\ArrayItem( - value: $scope, + value: $locale, key: new Node\Scalar\String_('locale'), ); } @@ -60,7 +61,7 @@ public function addFilter( return $this; } - public function getNode(): Node + public function getNode(): Node\Expr { $instance = new Node\Expr\New_( class: new Node\Name\FullyQualified(\Diglin\Sylius\ApiClient\Search\SearchBuilder::class) diff --git a/src/Capacity/All.php b/src/Capacity/All.php index 61593ca..fd4a51f 100644 --- a/src/Capacity/All.php +++ b/src/Capacity/All.php @@ -9,67 +9,35 @@ use PhpParser\Node; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; -use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue; +use function Kiboko\Component\SatelliteToolbox\Configuration\compileValueWhenExpression; -final class All implements CapacityInterface +final readonly class All implements CapacityInterface { - private static array $endpoints = [ - // Simple resources Endpoints - 'channels', - 'countries', - 'carts', - 'channels', - 'countries', - 'currencies', - 'customers', - 'exchangeRates', - 'locales', - 'orders', - 'payments', - 'paymentMethods', - 'products', - 'productAttributes', - 'productAssociationTypes', - 'productOptions', - 'promotions', - 'shipments', - 'shippingCategories', - 'taxCategories', - 'taxRates', - 'taxons', - 'users', - 'zones', - ]; - - private static array $doubleEndpoints = [ - // Double resources Endpoints - 'productReviews', - 'productVariants', - 'promotionCoupons', - ]; - - public function __construct(private readonly ExpressionLanguage $interpreter) - { + public function __construct( + private readonly ExpressionLanguage $interpreter + ) { } public function applies(array $config): bool { + $endpoints = [...Sylius\Validator\ExtractorConfigurationValidator::ADMIN_VALID_TYPES, ...Sylius\Validator\ExtractorConfigurationValidator::SHOP_VALID_TYPES]; + return isset($config['type']) - && (\in_array($config['type'], self::$endpoints) || \in_array($config['type'], self::$doubleEndpoints)) + && \array_key_exists($config['type'], $endpoints) && isset($config['method']) && 'all' === $config['method']; } - private function compileFilters(array ...$filters): Node + private function compileFilters(array ...$filters): Node\Expr { $builder = new Sylius\Builder\Search(); foreach ($filters as $filter) { $builder->addFilter( - field: compileValue($this->interpreter, $filter['field']), - operator: compileValue($this->interpreter, $filter['operator']), - value: compileValue($this->interpreter, $filter['value']), - scope: \array_key_exists('scope', $filter) ? compileValue($this->interpreter, $filter['scope']) : null, - locale: \array_key_exists('locale', $filter) ? compileValue($this->interpreter, $filter['locale']) : null + field: compileValueWhenExpression($this->interpreter, $filter['field']), + operator: compileValueWhenExpression($this->interpreter, $filter['operator']), + value: compileValueWhenExpression($this->interpreter, $filter['value']), + scope: \array_key_exists('scope', $filter) ? compileValueWhenExpression($this->interpreter, $filter['scope']) : null, + locale: \array_key_exists('locale', $filter) ? compileValueWhenExpression($this->interpreter, $filter['locale']) : null ); } diff --git a/src/Capacity/Create.php b/src/Capacity/Create.php index 0b02a08..5a7a34d 100644 --- a/src/Capacity/Create.php +++ b/src/Capacity/Create.php @@ -10,40 +10,12 @@ final class Create implements CapacityInterface { - private static array $endpoints = [ - // Core Endpoints - 'channels', - 'countries', - 'carts', - 'channels', - 'countries', - 'currencies', - 'customers', - 'exchangeRates', - 'locales', - 'orders', - 'payments', - 'paymentMethods', - 'products', - 'productAttributes', - 'productAssociationTypes', - 'productOptions', - 'productReviews', - 'productVariants', - 'promotions', - 'promotionCoupons', - 'shipments', - 'taxCategories', - 'taxRates', - 'taxons', - 'users', - 'zones', - ]; - public function applies(array $config): bool { + $endpoints = [...Sylius\Validator\ExtractorConfigurationValidator::ADMIN_VALID_TYPES, ...Sylius\Validator\ExtractorConfigurationValidator::SHOP_VALID_TYPES]; + return isset($config['type']) - && \in_array($config['type'], self::$endpoints) + && \array_key_exists($config['type'], $endpoints) && isset($config['method']) && 'create' === $config['method']; } diff --git a/src/Capacity/ListPerPage.php b/src/Capacity/ListPerPage.php index fef12ef..3c7c60f 100644 --- a/src/Capacity/ListPerPage.php +++ b/src/Capacity/ListPerPage.php @@ -11,56 +11,24 @@ use function Kiboko\Component\SatelliteToolbox\Configuration\compileValue; -final class ListPerPage implements CapacityInterface +final readonly class ListPerPage implements CapacityInterface { - private static array $endpoints = [ - // Simple resources Endpoints - 'channels', - 'countries', - 'carts', - 'channels', - 'countries', - 'currencies', - 'customers', - 'exchangeRates', - 'locales', - 'orders', - 'payments', - 'paymentMethods', - 'products', - 'productAttributes', - 'productAssociationTypes', - 'productOptions', - 'promotions', - 'shipments', - 'shippingCategories', - 'taxCategories', - 'taxRates', - 'taxons', - 'users', - 'zones', - ]; - - private static array $doubleEndpoints = [ - // Double resources Endpoints - 'productReviews', - 'productVariants', - 'promotionCoupons', - ]; - - public function __construct(private readonly ExpressionLanguage $interpreter) - { + public function __construct( + private readonly ExpressionLanguage $interpreter + ) { } public function applies(array $config): bool { + $endpoints = [...Sylius\Validator\ExtractorConfigurationValidator::ADMIN_VALID_TYPES, ...Sylius\Validator\ExtractorConfigurationValidator::SHOP_VALID_TYPES]; + return isset($config['type']) - && (\in_array($config['type'], self::$endpoints) || \in_array($config['type'], self::$doubleEndpoints)) + && \array_key_exists($config['type'], $endpoints) && isset($config['method']) && 'listPerPage' === $config['method']; } - private function compileFilters(array ...$filters): Node + private function compileFilters(array ...$filters): Node\Expr { $builder = new Sylius\Builder\Search(); foreach ($filters as $filter) { diff --git a/src/Capacity/Upsert.php b/src/Capacity/Upsert.php index 83b7079..c524cc8 100644 --- a/src/Capacity/Upsert.php +++ b/src/Capacity/Upsert.php @@ -10,42 +10,12 @@ final class Upsert implements CapacityInterface { - private static array $endpoints = [ - // Core Endpoints - 'carts', - 'channels', - 'countries', - 'carts', - 'channels', - 'countries', - 'currencies', - 'customers', - 'exchangeRates', - 'locales', - 'orders', - 'paymentMethods', - 'payments', - 'products', - 'productAttributes', - 'productAssociationTypes', - 'productOptions', - 'productReviews', - 'productVariants', - 'promotions', - 'promotionCoupons', - 'shipments', - 'shippingCategories', - 'taxCategories', - 'taxRates', - 'taxons', - 'users', - 'zones', - ]; - public function applies(array $config): bool { + $endpoints = [...Sylius\Validator\ExtractorConfigurationValidator::ADMIN_VALID_TYPES, ...Sylius\Validator\ExtractorConfigurationValidator::SHOP_VALID_TYPES]; + return isset($config['type']) - && \in_array($config['type'], self::$endpoints) + && \array_key_exists($config['type'], $endpoints) && isset($config['method']) && 'upsert' === $config['method']; } diff --git a/src/Configuration.php b/src/Configuration.php index a0b0315..dc5395b 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -5,6 +5,8 @@ namespace Kiboko\Plugin\Sylius; use Kiboko\Contract\Configurator\PluginConfigurationInterface; +use Kiboko\Plugin\Sylius\Validator\ExtractorConfigurationValidator; +use Kiboko\Plugin\Sylius\Validator\LoaderConfigurationValidator; use Symfony\Component\Config\Definition\Builder\TreeBuilder; final class Configuration implements PluginConfigurationInterface @@ -20,13 +22,33 @@ public function getConfigTreeBuilder(): TreeBuilder /* @phpstan-ignore-next-line */ $builder->getRootNode() ->validate() - ->ifTrue(fn (array $value) => \array_key_exists('extractor', $value) && \array_key_exists('loader', $value)) + ->ifTrue(fn (array $value) => \array_key_exists('extractor', $value) && \array_key_exists('loader', $value)) ->thenInvalid('Your configuration should either contain the "extractor" or the "loader" key, not both.') ->end() + ->validate() + ->always(function (array $value) { + if (\array_key_exists('extractor', $value)) { + ExtractorConfigurationValidator::validate($value['extractor']['type'], $value['extractor']['method'], $value['version']); + } + + if (\array_key_exists('loader', $value)) { + LoaderConfigurationValidator::validate($value['loader']['type'], $value['loader']['method'], $value['version']); + } + + return $value; + }) + ->end() ->children() ->arrayNode('expression_language') ->scalarPrototype()->end() ->end() + ->scalarNode('version') + ->isRequired() + ->validate() + ->ifNotInArray(['admin', 'shop']) + ->thenInvalid('Invalid version %s') + ->end() + ->end() ->append(node: $extractor->getConfigTreeBuilder()->getRootNode()) ->append(node: $loader->getConfigTreeBuilder()->getRootNode()) ->append(node: $client->getConfigTreeBuilder()->getRootNode()) diff --git a/src/Configuration/Client.php b/src/Configuration/Client.php index bd4840f..1074543 100644 --- a/src/Configuration/Client.php +++ b/src/Configuration/Client.php @@ -11,62 +11,25 @@ final class Client implements Config\Definition\ConfigurationInterface { - public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder + public function getConfigTreeBuilder(): Config\Definition\Builder\TreeBuilder { $builder = new Config\Definition\Builder\TreeBuilder('client'); /* @phpstan-ignore-next-line */ $builder->getRootNode() ->validate() - ->ifArray() - ->then(function (array $value) { - if (isset($value['username']) && !isset($value['password'])) { - throw new Config\Definition\Exception\InvalidConfigurationException('The configuration option "password" should be defined if you use the username authentication method for Sylius API.'); - } - if (isset($value['token']) && !isset($value['refresh_token'])) { - throw new Config\Definition\Exception\InvalidConfigurationException('The configuration option "refreshToken" should be defined if you use the token authentication method for Sylius API.'); - } - if (isset($value['username'], $value['token']) || (!isset($value['username']) && !isset($value['token'])) - ) { - throw new Config\Definition\Exception\InvalidConfigurationException('You must choose between "username" and "token" as authentication method for Sylius API, both are mutually exclusive.'); - } - - return $value; - }) + ->ifTrue(fn ($value) => !empty($value['token']) && (!empty($value['username']) || !empty($value['password']))) + ->thenInvalid('You cannot specify both a token and a username/password combination.') + ->end() + ->validate() + ->ifTrue(fn ($value) => (!empty($value['username']) && empty($value['password'])) || (empty($value['username']) && !empty($value['password']))) + ->thenInvalid('Both username and password must be defined together.') + ->end() + ->validate() + ->ifTrue(fn ($value) => empty($value['token']) && (empty($value['username']) || empty($value['password']))) + ->thenInvalid('You must specify either a token or a username and password combination.') ->end() ->children() - ->arrayNode('context') - ->children() - ->scalarNode('http_client') - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() - ->scalarNode('http_request_factory') - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() - ->scalarNode('http_stream_factory') - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() - ->scalarNode('filesystem') - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() - ->end() - ->end() ->scalarNode('api_url') ->isRequired() ->cannotBeEmpty() @@ -75,22 +38,6 @@ public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Bui ->then(asExpression()) ->end() ->end() - ->scalarNode('client_id') - ->isRequired() - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() - ->scalarNode('secret') - ->isRequired() - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() ->scalarNode('username') ->cannotBeEmpty() ->validate() @@ -112,13 +59,6 @@ public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Bui ->then(asExpression()) ->end() ->end() - ->scalarNode('refresh_token') - ->cannotBeEmpty() - ->validate() - ->ifTrue(isExpression()) - ->then(asExpression()) - ->end() - ->end() ->end() ; diff --git a/src/Configuration/Extractor.php b/src/Configuration/Extractor.php index ccf5a4e..e491b82 100644 --- a/src/Configuration/Extractor.php +++ b/src/Configuration/Extractor.php @@ -11,128 +11,7 @@ final class Extractor implements Config\Definition\ConfigurationInterface { - private static array $endpoints = [ - // Core Endpoints - 'channels' => [ - 'listPerPage', - 'all', - 'get', - ], - 'countries' => [ - 'listPerPage', - 'all', - 'get', - ], - 'carts' => [ - 'listPerPage', - 'all', - 'get', - ], - 'currencies' => [ - 'listPerPage', - 'all', - 'get', - ], - 'customers' => [ - 'listPerPage', - 'all', - 'get', - ], - 'exchangeRates' => [ - 'listPerPage', - 'all', - 'get', - ], - 'locales' => [ - 'listPerPage', - 'all', - 'get', - ], - 'orders' => [ - 'listPerPage', - 'all', - 'get', - ], - 'payments' => [ - 'listPerPage', - 'all', - 'get', - ], - 'paymentMethods' => [ - 'listPerPage', - 'all', - 'get', - ], - 'products' => [ - 'listPerPage', - 'all', - 'get', - ], - 'productAttributes' => [ - 'listPerPage', - 'all', - 'get', - ], - 'productAssociationTypes' => [ - 'listPerPage', - 'all', - 'get', - ], - 'productOptions' => [ - 'listPerPage', - 'all', - 'get', - ], - 'promotions' => [ - 'listPerPage', - 'all', - 'get', - ], - 'shipments' => [ - 'listPerPage', - 'all', - 'get', - ], - 'shippingCategories' => [ - 'listPerPage', - 'all', - 'get', - ], - 'taxCategories' => [ - 'listPerPage', - 'all', - 'get', - ], - 'taxRates' => [ - 'listPerPage', - 'all', - 'get', - ], - 'taxons' => [ - 'listPerPage', - 'all', - 'get', - ], - 'users' => [ - 'listPerPage', - 'all', - 'get', - ], - 'zones' => [ - 'listPerPage', - 'all', - 'get', - ], - ]; - - private static array $doubleEndpoints = [ - // Double resources Endpoints - 'productReviews', - 'productVariants', - 'promotionCoupons', - ]; - - public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder + public function getConfigTreeBuilder(): Config\Definition\Builder\TreeBuilder { $filters = new Search(); @@ -140,45 +19,17 @@ public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Bui /* @phpstan-ignore-next-line */ $builder->getRootNode() - ->validate() - ->ifArray() - ->then(function (array $item) { - if ( - \array_key_exists($item['type'], self::$endpoints) - && !\in_array($item['method'], self::$endpoints[$item['type']]) - && !\in_array($item['type'], self::$doubleEndpoints) - ) { - throw new \InvalidArgumentException(sprintf('The value should be one of [%s], got %s.', implode(', ', self::$endpoints[$item['type']]), json_encode($item['method'], \JSON_THROW_ON_ERROR))); - } - - return $item; - }) - ->end() - ->validate() - ->ifArray() - ->then(function (array $item) { - if (\in_array($item['type'], self::$doubleEndpoints) && !\array_key_exists('code', $item)) { - throw new \InvalidArgumentException(sprintf('The %s type should have a "code" field set.', $item['type'])); - } - - return $item; - }) - ->end() ->children() ->scalarNode('type') ->isRequired() - ->validate() - ->ifNotInArray(array_merge(array_keys(self::$endpoints), self::$doubleEndpoints)) - ->thenInvalid( - sprintf( - 'the value should be one of [%s], got %%s', - implode(', ', array_merge(array_keys(self::$endpoints), self::$doubleEndpoints)) - ) - ) - ->end() + ->cannotBeEmpty() + ->end() + ->scalarNode('method') + ->isRequired() + ->cannotBeEmpty() ->end() - ->scalarNode('method')->end() ->scalarNode('code') + ->cannotBeEmpty() ->validate() ->ifTrue(isExpression()) ->then(asExpression()) diff --git a/src/Configuration/Loader.php b/src/Configuration/Loader.php index a62d237..74c812e 100644 --- a/src/Configuration/Loader.php +++ b/src/Configuration/Loader.php @@ -8,126 +8,21 @@ final class Loader implements Config\Definition\ConfigurationInterface { - private static array $endpoints = [ - // Core Endpoints - 'channels' => [ - 'create', - 'delete', - ], - 'countries' => [ - 'create', - 'delete', - ], - 'carts' => [ - 'create', - 'delete', - ], - 'currencies' => [ - 'create', - 'delete', - ], - 'customers' => [ - 'create', - 'delete', - ], - 'exchangeRates' => [ - 'create', - 'delete', - ], - 'locales' => [ - 'create', - 'delete', - ], - 'orders' => [ - 'create', - 'delete', - ], - 'payments' => [ - 'create', - 'delete', - ], - 'paymentMethods' => [ - 'create', - 'delete', - ], - 'products' => [ - 'create', - 'upsert', - 'delete', - ], - 'productAttributes' => [ - 'create', - 'delete', - ], - 'productAssociationTypes' => [ - 'create', - 'delete', - ], - 'productOptions' => [ - 'create', - 'delete', - ], - 'promotions' => [ - 'create', - 'delete', - ], - 'shipments' => [ - 'create', - 'delete', - ], - 'shippingCategories' => [ - 'create', - 'delete', - ], - 'taxCategories' => [ - 'create', - 'delete', - ], - 'taxRates' => [ - 'create', - 'delete', - ], - 'taxons' => [ - 'create', - 'delete', - ], - 'users' => [ - 'create', - 'delete', - ], - 'zones' => [ - 'create', - 'delete', - ], - ]; - - public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder + public function getConfigTreeBuilder(): Config\Definition\Builder\TreeBuilder { $builder = new Config\Definition\Builder\TreeBuilder('loader'); /* @phpstan-ignore-next-line */ $builder->getRootNode() - ->validate() - ->ifArray() - ->then(function (array $item) { - if (!\in_array($item['method'], self::$endpoints[$item['type']])) { - throw new \InvalidArgumentException(sprintf('the value should be one of [%s], got %s', implode(', ', self::$endpoints[$item['type']]), json_encode($item['method'], \JSON_THROW_ON_ERROR))); - } - - return $item; - }) - ->end() ->children() ->scalarNode('type') ->isRequired() - ->validate() - ->ifNotInArray(array_keys(self::$endpoints)) - ->thenInvalid( - sprintf('the value should be one of [%s]', implode(', ', array_keys(self::$endpoints))) - ) - ->end() + ->cannotBeEmpty() + ->end() + ->scalarNode('method') + ->isRequired() + ->cannotBeEmpty() ->end() - ->scalarNode('method')->end() ->end() ; diff --git a/src/Configuration/Search.php b/src/Configuration/Search.php index b03d484..0ab9dc7 100644 --- a/src/Configuration/Search.php +++ b/src/Configuration/Search.php @@ -11,7 +11,7 @@ final class Search implements Config\Definition\ConfigurationInterface { - public function getConfigTreeBuilder(): \Symfony\Component\Config\Definition\Builder\TreeBuilder + public function getConfigTreeBuilder(): Config\Definition\Builder\TreeBuilder { $builder = new Config\Definition\Builder\TreeBuilder('search'); diff --git a/src/Factory/Client.php b/src/Factory/Client.php index 5c61386..6b28900 100644 --- a/src/Factory/Client.php +++ b/src/Factory/Client.php @@ -19,8 +19,10 @@ private Processor $processor; private ConfigurationInterface $configuration; - public function __construct(private ExpressionLanguage $interpreter) - { + public function __construct( + private ExpressionLanguage $interpreter, + private Sylius\ApiType $type = Sylius\ApiType::ADMIN, + ) { $this->processor = new Processor(); $this->configuration = new Sylius\Configuration\Client(); } @@ -37,7 +39,7 @@ public function normalize(array $config): array { try { return $this->processor->processConfiguration($this->configuration, $config); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException($exception->getMessage(), 0, $exception); } } @@ -72,31 +74,46 @@ public function compile(array $config): Repository\Client try { $clientBuilder = new Sylius\Builder\Client( compileValueWhenExpression($this->interpreter, $config['api_url']), - compileValueWhenExpression($this->interpreter, $config['client_id']), - compileValueWhenExpression($this->interpreter, $config['secret']), ); - if (isset($config['context'])) { - if (isset($config['context']['http_client'])) { - $clientBuilder->withHttpClient($this->buildFactoryNode($config['context']['http_client'])); - } - if (isset($config['context']['http_request_factory'])) { - $clientBuilder->withHttpRequestFactory($this->buildFactoryNode($config['context']['http_request_factory'])); - } - if (isset($config['context']['http_stream_factory'])) { - $clientBuilder->withHttpStreamFactory($this->buildFactoryNode($config['context']['http_stream_factory'])); - } - if (isset($config['context']['filesystem'])) { - $clientBuilder->withFileSystem($this->buildFactoryNode($config['context']['filesystem'])); - } - } + // if (isset($config['context'])) { + // if (isset($config['context']['http_client'])) { + // $clientBuilder->withHttpClient($this->buildFactoryNode($config['context']['http_client'])); + // } + // if (isset($config['context']['http_request_factory'])) { + // $clientBuilder->withHttpRequestFactory($this->buildFactoryNode($config['context']['http_request_factory'])); + // } + // if (isset($config['context']['http_stream_factory'])) { + // $clientBuilder->withHttpStreamFactory($this->buildFactoryNode($config['context']['http_stream_factory'])); + // } + // if (isset($config['context']['filesystem'])) { + // $clientBuilder->withFileSystem($this->buildFactoryNode($config['context']['filesystem'])); + // } + // } + + $clientBuilder->withClientBuilder( + new Node\Expr\New_( + new Node\Name\FullyQualified( + Sylius\ApiType::ADMIN == $this->type ? \Diglin\Sylius\ApiClient\SyliusAdminClientBuilder::class : \Diglin\Sylius\ApiClient\SyliusShopClientBuilder::class + ), + ) + ); + + // if (isset($config['client_id']) && isset($config['secret'])) { + // if (isset($config['api_type']) && $config['api_type'] === Sylius\Validator\ApiType::LEGACY->value) { + // $clientBuilder->withSecret( + // compileValueWhenExpression($this->interpreter, $config['client_id']), + // compileValueWhenExpression($this->interpreter, $config['secret']) + // ); + // } + // } - if (isset($config['password'])) { + if (isset($config['username'], $config['password'])) { $clientBuilder->withPassword( compileValueWhenExpression($this->interpreter, $config['username']), compileValueWhenExpression($this->interpreter, $config['password']), ); - } elseif (isset($config['refresh_token'])) { + } elseif (isset($config['token'])) { $clientBuilder->withToken( compileValueWhenExpression($this->interpreter, $config['token']), compileValueWhenExpression($this->interpreter, $config['refresh_token']), @@ -106,7 +123,7 @@ public function compile(array $config): Repository\Client return new Repository\Client($clientBuilder); } catch (Sylius\MissingAuthenticationMethodException $exception) { throw new Configurator\InvalidConfigurationException(message: 'Your Sylius API configuration is missing an authentication method, you should either define "username" or "token" options.', previous: $exception); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException(message: $exception->getMessage(), previous: $exception); } } diff --git a/src/Factory/Extractor.php b/src/Factory/Extractor.php index cbd3980..5551259 100644 --- a/src/Factory/Extractor.php +++ b/src/Factory/Extractor.php @@ -40,7 +40,7 @@ public function normalize(array $config): array { try { return $this->processor->processConfiguration($this->configuration, $config); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException($exception->getMessage(), 0, $exception); } } diff --git a/src/Factory/Loader.php b/src/Factory/Loader.php index e75a917..e69e6e5 100644 --- a/src/Factory/Loader.php +++ b/src/Factory/Loader.php @@ -39,7 +39,7 @@ public function normalize(array $config): array { try { return $this->processor->processConfiguration($this->configuration, $config); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException($exception->getMessage(), 0, $exception); } } diff --git a/src/Factory/Repository/RepositoryTrait.php b/src/Factory/Repository/RepositoryTrait.php index 5544a6d..e292132 100644 --- a/src/Factory/Repository/RepositoryTrait.php +++ b/src/Factory/Repository/RepositoryTrait.php @@ -15,7 +15,7 @@ trait RepositoryTrait /** @var string[] */ private array $packages; - public function addFiles(FileInterface|DirectoryInterface ...$files): Configurator\RepositoryInterface + public function addFiles(DirectoryInterface|FileInterface ...$files): Configurator\RepositoryInterface { array_push($this->files, ...$files); diff --git a/src/Factory/Search.php b/src/Factory/Search.php index 331ce62..3657333 100644 --- a/src/Factory/Search.php +++ b/src/Factory/Search.php @@ -33,7 +33,7 @@ public function normalize(array $config): array { try { return $this->processor->processConfiguration($this->configuration, $config); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException($exception->getMessage(), 0, $exception); } } @@ -59,7 +59,7 @@ public function compile(array $config): Repository\Search } return new Repository\Search($builder); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new Configurator\InvalidConfigurationException(message: $exception->getMessage(), previous: $exception); } } diff --git a/src/Service.php b/src/Service.php index 8827b51..9c89c3f 100644 --- a/src/Service.php +++ b/src/Service.php @@ -7,6 +7,7 @@ use Kiboko\Contract\Configurator; use Kiboko\Contract\Configurator\ConfigurationExceptionInterface; use Kiboko\Contract\Configurator\InvalidConfigurationException; +use PhpParser\Node; use Symfony\Component\Config\Definition\Exception as Symfony; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; @@ -50,7 +51,7 @@ public function normalize(array $config): array { try { return $this->processor->processConfiguration($this->configuration, $config); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new InvalidConfigurationException($exception->getMessage(), 0, $exception); } } @@ -61,7 +62,7 @@ public function validate(array $config): bool $this->processor->processConfiguration($this->configuration, $config); return true; - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException) { return false; } } @@ -91,7 +92,10 @@ public function compile(array $config): Factory\Repository\Extractor|Factory\Rep $client = $clientFactory->compile($config['client']); - $extractorBuilder->withClient($client->getBuilder()->getNode()); + $extractorBuilder + ->withClientType(ApiType::ADMIN == ApiType::from($config['version']) ? new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusAdminClientInterface::class) : new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusShopClientInterface::class)) + ->withClient($client->getBuilder()->getNode()) + ; $extractor->merge($client); @@ -105,7 +109,10 @@ public function compile(array $config): Factory\Repository\Extractor|Factory\Rep $client = $clientFactory->compile($config['client']); - $loaderBuilder->withClient($client->getBuilder()->getNode()); + $loaderBuilder + ->withClientType(ApiType::ADMIN == ApiType::from($config['version']) ? new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusAdminClientInterface::class) : new Node\Name\FullyQualified(name: \Diglin\Sylius\ApiClient\SyliusShopClientInterface::class)) + ->withClient($client->getBuilder()->getNode()) + ; $loader->merge($client); @@ -114,7 +121,7 @@ public function compile(array $config): Factory\Repository\Extractor|Factory\Rep throw new InvalidConfigurationException('Could not determine if the factory should build an extractor or a loader.'); } catch (MissingAuthenticationMethodException $exception) { throw new InvalidConfigurationException('Your Sylius API configuration is missing an authentication method, you should either define "username" or "token" options.', 0, $exception); - } catch (Symfony\InvalidTypeException|Symfony\InvalidConfigurationException $exception) { + } catch (Symfony\InvalidConfigurationException|Symfony\InvalidTypeException $exception) { throw new InvalidConfigurationException($exception->getMessage(), 0, $exception); } } diff --git a/src/Validator/ExtractorConfigurationValidator.php b/src/Validator/ExtractorConfigurationValidator.php new file mode 100644 index 0000000..ef5d2e6 --- /dev/null +++ b/src/Validator/ExtractorConfigurationValidator.php @@ -0,0 +1,280 @@ + [ + 'get', + ], + 'adjustment' => [ + 'get', + ], + 'administrator' => [ + 'all', + 'get', + ], + 'catalogPromotionTranslation' => [ + 'get', + ], + 'catalogPromotion' => [ + 'all', + 'get', + ], + 'channel' => [ + 'all', + 'get', + ], + 'shopBillingData' => [ + 'get', + ], + 'country' => [ + 'all', + 'get', + ], + 'province' => [ + 'all', + 'get', + ], + 'currency' => [ + 'all', + 'get', + ], + 'customerGroups' => [ + 'all', + 'get', + ], + 'customer' => [ + 'all', + 'get', + ], + 'exchangeRate' => [ + 'all', + 'get', + ], + 'gatewayConfiguration' => [ + 'get', + ], + 'locale' => [ + 'all', + 'get', + ], + 'orderItemUnit' => [ + 'get', + ], + 'orderItem' => [ + 'get', + ], + 'order' => [ + 'all', + 'get', + ], + 'paymentMethod' => [ + 'all', + 'get', + ], + 'payment' => [ + 'all', + 'get', + ], + 'shipment' => [ + 'all', + 'get', + ], + 'productAssociationType' => [ + 'all', + 'get', + ], + 'productAttribute' => [ + 'all', + 'get', + ], + 'productOption' => [ + 'all', + 'get', + ], + 'productReview' => [ + 'all', + 'get', + ], + 'productTaxon' => [ + 'all', + 'get', + ], + 'productTranslation' => [ + 'get', + ], + 'productVariantTranslation' => [ + 'get', + ], + 'productVariant' => [ + 'all', + 'get', + ], + 'product' => [ + 'all', + 'get', + ], + 'promotionCoupon' => [ + 'all', + 'get', + ], + 'promotionTranslation' => [ + 'get', + ], + 'promotion' => [ + 'all', + 'get', + ], + 'shippingCategory' => [ + 'all', + 'get', + ], + 'shippingMethodTranslation' => [ + 'get', + ], + 'shippingMethod' => [ + 'all', + 'get', + ], + 'taxCategory' => [ + 'all', + 'get', + ], + 'taxRate' => [ + 'all', + 'get', + ], + 'taxonImage' => [ + 'all', + 'get', + ], + 'taxon' => [ + 'all', + 'get', + ], + 'zoneMember' => [ + 'get', + ], + 'zone' => [ + 'all', + 'get', + ], + ]; + + final public const SHOP_VALID_TYPES = [ + 'address' => [ + 'all', + 'get', + ], + 'adjustment' => [ + 'get', + ], + 'catalogPromotion' => [ + 'get', + ], + 'channel' => [ + 'all', + 'get', + ], + 'country' => [ + 'all', + 'get', + ], + 'province' => [ + 'get', + ], + 'currency' => [ + 'all', + 'get', + ], + 'customer' => [ + 'get', + ], + 'exchangeRate' => [ + 'all', + 'get', + ], + 'locale' => [ + 'all', + 'get', + ], + 'orderItemUnit' => [ + 'get', + ], + 'orderItem' => [ + 'get', + ], + 'order' => [ + 'all', + 'get', + ], + 'paymentMethod' => [ + 'all', + 'get', + ], + 'payment' => [ + 'get', + ], + 'shipment' => [ + 'get', + ], + 'productAssociationType' => [ + 'get', + ], + 'productAttribute' => [ + 'get', + ], + 'productOption' => [ + 'get', + ], + 'productReview' => [ + 'all', + 'get', + ], + 'productTaxon' => [ + 'get', + ], + 'productVariant' => [ + 'all', + 'get', + ], + 'product' => [ + 'all', + 'get', + ], + 'shippingMethod' => [ + 'all', + 'get', + ], + 'taxonImage' => [ + 'get', + ], + 'taxon' => [ + 'all', + 'get', + ], + ]; + + public static function validate(string $type, string $method, string $version = 'admin'): void + { + $validTypes = 'admin' === $version ? self::ADMIN_VALID_TYPES : self::SHOP_VALID_TYPES; + + if (null === $validTypes) { + throw new InvalidConfigurationException(sprintf('Unknown version "%s".', $version)); + } + + if (!\array_key_exists($type, $validTypes)) { + throw new InvalidConfigurationException(sprintf('Invalid extractor type "%s" for version "%s". Valid types are: %s.', $type, $version, implode(', ', array_keys($validTypes)))); + } + + if (!\in_array($method, $validTypes[$type], true)) { + throw new InvalidConfigurationException(sprintf('Invalid method "%s" for extractor type "%s" and version "%s". Valid methods are: %s.', $method, $type, $version, implode(', ', $validTypes[$type]))); + } + } +} diff --git a/src/Validator/LoaderConfigurationValidator.php b/src/Validator/LoaderConfigurationValidator.php new file mode 100644 index 0000000..c5ed589 --- /dev/null +++ b/src/Validator/LoaderConfigurationValidator.php @@ -0,0 +1,200 @@ + [ + 'create', + 'delete', + 'update', + ], + 'administrator' => [ + 'create', + 'delete', + 'update', + ], + 'avatarImage' => [ + 'create', + 'delete', + ], + 'catalogPromotion' => [ + 'create', + 'update', + 'delete', + ], + 'channel' => [ + 'create', + 'update', + 'delete', + ], + 'country' => [ + 'create', + 'update', + ], + 'province' => [ + 'update', + ], + 'currency' => [ + 'create', + ], + 'customerGroup' => [ + 'create', + 'delete', + 'update', + ], + 'customer' => [ + 'create', + 'delete', + 'update', + ], + 'exchangeRate' => [ + 'create', + 'delete', + 'update', + ], + 'locale' => [ + 'create', + 'delete', + ], + 'paymentMethod' => [ + 'create', + 'delete', + 'update', + ], + 'productAssociationType' => [ + 'create', + 'delete', + 'update', + ], + 'productAssociation' => [ + 'create', + 'delete', + 'update', + ], + 'productAttribute' => [ + 'create', + 'delete', + 'update', + ], + 'productImage' => [ + 'delete', + 'update', + ], + 'productOption' => [ + 'create', + 'update', + 'delete', + ], + 'productReview' => [ + 'create', + 'update', + 'delete', + ], + 'productTaxon' => [ + 'create', + 'update', + 'delete', + ], + 'productVariant' => [ + 'create', + 'update', + 'delete', + ], + 'product' => [ + 'create', + 'delete', + 'update', + ], + 'promotionCoupon' => [ + 'create', + 'update', + 'delete', + ], + 'promotion' => [ + 'create', + 'update', + 'delete', + ], + 'shippingCategory' => [ + 'create', + 'delete', + 'update', + ], + 'shippingMethod' => [ + 'create', + 'delete', + 'update', + ], + 'taxCategory' => [ + 'create', + 'delete', + 'update', + ], + 'taxRate' => [ + 'create', + 'delete', + 'update', + ], + 'taxonImage' => [ + 'delete', + 'update', + ], + 'taxon' => [ + 'create', + 'update', + 'delete', + ], + 'zone' => [ + 'create', + 'delete', + 'update', + ], + ]; + + final public const SHOP_VALID_TYPES = [ + 'address' => [ + 'create', + 'delete', + 'update', + ], + 'customer' => [ + 'create', + 'update', + ], + 'order' => [ + 'create', + 'update', + 'delete', + ], + 'orderItem' => [ + 'create', + 'delete', + ], + 'productReview' => [ + 'create', + ], + ]; + + public static function validate(string $type, string $method, string $version = 'admin'): void + { + $validTypes = 'admin' === $version ? self::ADMIN_VALID_TYPES : self::SHOP_VALID_TYPES; + + if (null === $validTypes) { + throw new InvalidConfigurationException(sprintf('Unknown version "%s".', $version)); + } + + if (!\array_key_exists($type, $validTypes)) { + throw new InvalidConfigurationException(sprintf('Invalid loader type "%s" for version "%s". Valid types are: %s.', $type, $version, implode(', ', array_keys($validTypes)))); + } + + if (!\in_array($method, $validTypes[$type], true)) { + throw new InvalidConfigurationException(sprintf('Invalid method "%s" for extractor type "%s" and version "%s". Valid methods are: %s.', $method, $type, $version, implode(', ', $validTypes[$type]))); + } + } +} 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..7d2a52c 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,97 @@ public static function validDataProvider(): iterable 'config' => [ 'type' => 'products', 'method' => 'get', + 'api_type' => 'legacy', 'search' => [], ], 'expected' => [ 'type' => 'products', 'method' => 'get', + 'api_type' => 'legacy', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'get', + 'api_type' => 'admin', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'get', + 'api_type' => 'admin', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'admin', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'admin', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'admin', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'admin', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'get', + 'api_type' => 'shop', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'get', + 'api_type' => 'shop', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'shop', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'shop', + 'search' => [], + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'shop', + 'search' => [], + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'shop', 'search' => [], ], ]; @@ -65,7 +155,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 +163,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 +183,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 +223,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..0de9720 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; @@ -17,6 +17,130 @@ protected function setUp(): void $this->processor = new Config\Definition\Processor(); } + public static function validDataProvider(): iterable + { + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'create', + 'api_type' => 'legacy', + ], + 'expected' => [ + 'type' => 'products', + 'method' => 'create', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'upsert', + 'api_type' => 'legacy', + ], + 'expected' => [ + 'type' => 'products', + 'method' => 'upsert', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'create', + 'api_type' => 'admin', + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'create', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'method' => 'upsert', + 'api_type' => 'admin', + ], + 'expected' => [ + 'type' => 'product', + 'method' => 'upsert', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'type' => 'customer', + 'method' => 'create', + 'api_type' => 'shop', + ], + 'expected' => [ + 'type' => 'customer', + 'method' => 'create', + 'api_type' => 'shop', + ], + ]; + yield [ + 'config' => [ + 'type' => 'customer', + 'method' => 'upsert', + 'api_type' => 'shop', + ], + 'expected' => [ + 'type' => 'customer', + 'method' => 'upsert', + 'api_type' => 'shop', + ], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('validDataProvider')] + public function testValidConfig(array $config, array $expected): void + { + $client = new Configuration\Loader(); + + $this->assertSame($expected, $this->processor->processConfiguration($client, [$config])); + } + + public function testWrongApiType(): void + { + $client = new Configuration\Loader(); + + $this->expectException( + Config\Definition\Exception\InvalidConfigurationException::class, + ); + $this->expectExceptionMessage( + 'Invalid configuration for path "loader.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\Loader(); + + $this->expectException( + Config\Definition\Exception\InvalidConfigurationException::class, + ); + $this->expectExceptionMessage( + 'Invalid configuration for path "loader.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], got "wrong".', + ); + + $this->processor->processConfiguration($client, [ + [ + 'type' => 'wrong', + 'api_type' => 'legacy', + 'method' => 'all' + ], + ]); + } + public function testWrongMethod(): void { $client = new Configuration\Loader(); @@ -25,13 +149,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..dc1970d 100644 --- a/tests/functional/Factory/ExtractorTest.php +++ b/tests/functional/Factory/ExtractorTest.php @@ -6,6 +6,7 @@ use Kiboko\Contract\Configurator\InvalidConfigurationException; use Kiboko\Plugin\Sylius\Factory\Extractor; +use Kiboko\Plugin\Sylius\Factory\Loader; use PHPUnit\Framework\TestCase; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; @@ -17,18 +18,75 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', ], ]; - yield [ [ 'type' => 'products', 'method' => 'listPerPage', + 'api_type' => 'legacy', + ], + ]; + yield [ + [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'admin', + ], + ]; + yield [ + [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'admin', + ], + ]; + yield [ + [ + 'type' => 'product', + 'method' => 'all', + 'api_type' => 'shop', + ], + ]; + yield [ + [ + 'type' => 'product', + 'method' => 'listPerPage', + 'api_type' => 'shop', ], ]; } - public static function wrongConfigs(): \Generator + public static function wrongApiType(): \Generator + { + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'all', + 'api_type' => 'wrong', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'api_type' => 'wrong', + ], + ]; + yield [ + 'config' => [ + 'method' => 'all', + 'api_type' => 'wrong', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'wrong', + ], + ]; + } + + public static function missingApiType(): \Generator { yield [ 'config' => [ @@ -39,21 +97,142 @@ public static function wrongConfigs(): \Generator 'wrong', ], ]; + yield [ + 'config' => [ + 'type' => 'products', + ], + ]; + yield [ + 'config' => [ + 'method' => 'all', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'all', + ], + ]; + } + + public static function missingCapacityConfigs(): \Generator + { + yield [ + 'config' => [ + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'shop', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'legacy', + 'method' => 'all', + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'admin', + 'method' => 'all', + ], + ]; + yield [ + 'config' => [ + 'type' => 'product', + 'api_type' => 'shop', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'shop', + 'method' => 'all', + ], + ]; + yield [ + 'config' => [ + 'type' => 'wrong', + 'method' => 'all', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'wrong', + 'api_type' => 'legacy', + ], + ]; yield [ 'config' => [ 'type' => 'wrong', 'method' => 'all', + 'api_type' => 'admin', ], ]; yield [ 'config' => [ 'type' => 'products', 'method' => 'wrong', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'type' => 'wrong', + 'method' => 'all', + 'api_type' => 'shop', ], ]; yield [ 'config' => [ 'type' => 'products', + 'method' => 'wrong', + 'api_type' => 'shop', + ], + ]; + } + + public static function wrongConfigs(): \Generator + { + yield [ + 'config' => [ + 'azerty' => 'tata', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'azerty' => 'tata', + 'meyuiop' => 'toto', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'azerty' => 'tata', + 'meyuiop' => 'toto', + 'qsdfgh' => 'tutu', + 'api_type' => 'shop', ], ]; } @@ -66,7 +245,34 @@ public function testValidateConfiguration(array $config): void $client->compile($config); } - #[\PHPUnit\Framework\Attributes\DataProvider('wrongConfigs')] + + #[\PHPUnit\Framework\Attributes\DataProvider('wrongApiType')] + public function testWrongApiType(array $config) + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('The value of api_type should be one of [admin, shop, legacy], got "wrong".'); + + $client = new Loader(); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } + + + #[\PHPUnit\Framework\Attributes\DataProvider('missingApiType')] + public function testMissingApiType(array $config) + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('Your Sylius API configuration is using some unsupported capacity, check your "api_type" properties to a suitable set.'); + + $client = new Loader(); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } + + + #[\PHPUnit\Framework\Attributes\DataProvider('missingCapacityConfigs')] public function testMissingCapacity(array $config): void { $this->expectException(InvalidConfigurationException::class); @@ -77,4 +283,16 @@ public function testMissingCapacity(array $config): void $this->assertFalse($client->validate($config)); $client->compile($config); } + + #[\PHPUnit\Framework\Attributes\DataProvider('wrongConfigs')] + public function testWrongConfigs(array $config): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('Your Sylius API configuration is using some unsupported capacity, check your "type" and "method" properties to a suitable set.'); + + $client = new Extractor(new ExpressionLanguage()); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } } diff --git a/tests/functional/Factory/LoaderTest.php b/tests/functional/Factory/LoaderTest.php index cf460aa..a04cf87 100644 --- a/tests/functional/Factory/LoaderTest.php +++ b/tests/functional/Factory/LoaderTest.php @@ -5,8 +5,10 @@ namespace functional\Kiboko\Plugin\Sylius\Factory; use Kiboko\Contract\Configurator\InvalidConfigurationException; +use Kiboko\Plugin\Sylius\Factory\Extractor; use Kiboko\Plugin\Sylius\Factory\Loader; use PHPUnit\Framework\TestCase; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; final class LoaderTest extends TestCase { @@ -16,6 +18,7 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'create', + 'api_type' => 'legacy', ], ]; @@ -23,11 +26,23 @@ public static function validDataProvider(): \Generator [ 'type' => 'products', 'method' => 'upsert', + 'api_type' => 'legacy', ], ]; } - public static function wrongConfigs(): \Generator + public static function wrongApiType(): \Generator + { + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'upsert', + 'api_type' => 'wrong', + ], + ]; + } + + public static function missingApiType(): \Generator { yield [ 'config' => [ @@ -38,25 +53,85 @@ public static function wrongConfigs(): \Generator 'wrong', ], ]; + yield [ + 'config' => [ + 'type' => 'products', + ], + ]; + yield [ + 'config' => [ + 'method' => 'upsert', + ], + ]; + yield [ + 'config' => [ + 'type' => 'products', + 'method' => 'upsert', + ], + ]; + } + + public static function missingCapacityConfigs(): \Generator + { + yield [ + 'config' => [ + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'api_type' => 'legacy', + 'type' => 'products', + ], + ]; + yield [ + 'config' => [ + 'method' => 'upsert', + 'api_type' => 'legacy', + ], + ]; yield [ 'config' => [ 'type' => 'wrong', - 'method' => 'all', + 'method' => 'upsert', + 'api_type' => 'legacy', ], ]; yield [ 'config' => [ 'type' => 'products', 'method' => 'wrong', + 'api_type' => 'legacy', ], ]; + } + + public static function wrongConfigs(): \Generator + { yield [ 'config' => [ - 'type' => 'products', + 'azerty' => 'tata', + 'api_type' => 'legacy', + ], + ]; + yield [ + 'config' => [ + 'azerty' => 'tata', + 'meyuiop' => 'toto', + 'api_type' => 'admin', + ], + ]; + yield [ + 'config' => [ + 'azerty' => 'tata', + 'meyuiop' => 'toto', + 'qsdfgh' => 'tutu', + 'api_type' => 'shop', ], ]; } + #[\PHPUnit\Framework\Attributes\DataProvider('validDataProvider')] public function testValidateConfiguration(array $config): void { @@ -65,7 +140,32 @@ public function testValidateConfiguration(array $config): void $client->compile($config); } - #[\PHPUnit\Framework\Attributes\DataProvider('wrongConfigs')] + #[\PHPUnit\Framework\Attributes\DataProvider('wrongApiType')] + public function testWrongApiType(array $config) + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('The value of api_type should be one of [admin, shop, legacy], got "wrong".'); + + $client = new Loader(); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } + + + #[\PHPUnit\Framework\Attributes\DataProvider('missingApiType')] + public function testMissingApiType(array $config) + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('Your Sylius API configuration is using some unsupported capacity, check your "api_type" properties to a suitable set.'); + + $client = new Loader(); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('missingCapacityConfigs')] public function testMissingCapacity(array $config): void { $this->expectException(InvalidConfigurationException::class); @@ -76,4 +176,16 @@ public function testMissingCapacity(array $config): void $this->assertFalse($client->validate($config)); $client->compile($config); } + + #[\PHPUnit\Framework\Attributes\DataProvider('wrongConfigs')] + public function testWrongConfigs(array $config): void + { + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionCode(0); + $this->expectExceptionMessage('Your Sylius API configuration is using some unsupported capacity, check your "type" and "method" properties to a suitable set.'); + + $client = new Loader(); + $this->assertFalse($client->validate($config)); + $client->compile($config); + } } diff --git a/tests/functional/ServiceTest.php b/tests/functional/ServiceTest.php index 4f09f9f..1b24106 100644 --- a/tests/functional/ServiceTest.php +++ b/tests/functional/ServiceTest.php @@ -20,6 +20,7 @@ public static function validDataProvider(): \Generator 'extractor' => [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', 'search' => [], ], 'client' => [ @@ -34,6 +35,7 @@ public static function validDataProvider(): \Generator 'extractor' => [ 'type' => 'products', 'method' => 'all', + 'api_type' => 'legacy', ], 'client' => [ 'api_url' => '1234', @@ -52,6 +54,7 @@ public static function validDataProvider(): \Generator 'loader' => [ 'type' => 'products', 'method' => 'upsert', + 'api_type' => 'legacy', ], 'client' => [ 'api_url' => '1234', @@ -66,6 +69,7 @@ public static function validDataProvider(): \Generator 'loader' => [ 'type' => 'products', 'method' => 'upsert', + 'api_type' => 'legacy', ], 'client' => [ 'api_url' => '1234', @@ -113,6 +117,7 @@ public function testMissingAuthentication(): void 'loader' => [ 'type' => 'products', 'method' => 'upsert', + 'api_type' => 'legacy', 'code' => 'azerty123', ], 'client' => [