From 3dfb1f5ea301e6964e162d35064bde04758c5209 Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Thu, 13 Jun 2024 09:51:26 +0200 Subject: [PATCH 1/6] [API] Enable contract tests for Locale --- disabledTests/Api/Shop/LocalesTest.php | 53 ------------ .../Api/Admin/LocalesTest.php | 85 ++++++++----------- tests/Api/Shop/LocalesTest.php | 49 +++++++++++ 3 files changed, 83 insertions(+), 104 deletions(-) delete mode 100644 disabledTests/Api/Shop/LocalesTest.php rename {disabledTests => tests}/Api/Admin/LocalesTest.php (64%) create mode 100644 tests/Api/Shop/LocalesTest.php diff --git a/disabledTests/Api/Shop/LocalesTest.php b/disabledTests/Api/Shop/LocalesTest.php deleted file mode 100644 index 8a313fafdfa..00000000000 --- a/disabledTests/Api/Shop/LocalesTest.php +++ /dev/null @@ -1,53 +0,0 @@ -loadFixturesFromFiles(['channel_without_locales.yaml', 'locale.yaml']); - - $this->client->request(method: 'GET', uri: '/api/v2/shop/locales', server: self::CONTENT_TYPE_HEADER); - $response = $this->client->getResponse(); - - $this->assertResponse($response, 'shop/locale/get_locales_response', Response::HTTP_OK); - } - - /** @test */ - public function it_gets_only_locales_from_current_channel(): void - { - $this->loadFixturesFromFiles(['locale.yaml', 'channel.yaml']); - - $this->client->request(method: 'GET', uri: '/api/v2/shop/locales', server: self::CONTENT_TYPE_HEADER); - $response = $this->client->getResponse(); - - $this->assertResponse($response, 'shop/locale/get_locales_from_channel_response', Response::HTTP_OK); - } - - /** @test */ - public function it_gets_locale(): void - { - $this->loadFixturesFromFiles(['channel.yaml']); - - $this->client->request(method: 'GET', uri: '/api/v2/shop/locales/en_US', server: self::CONTENT_TYPE_HEADER); - $response = $this->client->getResponse(); - - $this->assertResponse($response, 'shop/locale/get_locale_response', Response::HTTP_OK); - } -} diff --git a/disabledTests/Api/Admin/LocalesTest.php b/tests/Api/Admin/LocalesTest.php similarity index 64% rename from disabledTests/Api/Admin/LocalesTest.php rename to tests/Api/Admin/LocalesTest.php index a0757dba97b..ed8c76b5c82 100644 --- a/disabledTests/Api/Admin/LocalesTest.php +++ b/tests/Api/Admin/LocalesTest.php @@ -22,79 +22,50 @@ final class LocalesTest extends JsonApiTestCase { use AdminUserLoginTrait; - /** @test */ - public function it_does_not_allow_creating_a_locale_with_invalid_code(): void - { - $this->loadFixturesFromFiles(['channel.yaml', 'authentication/api_administrator.yaml']); - $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); - - $this->client->request( - 'POST', - '/api/v2/admin/locales', - [], - [], - $header, - json_encode([ - 'code' => 'lol', - ], \JSON_THROW_ON_ERROR), - ); - - $this->assertResponse( - $this->client->getResponse(), - 'admin/locale/post_locale_with_invalid_code_response', - Response::HTTP_UNPROCESSABLE_ENTITY, - ); - } - /** @test */ public function it_denies_access_to_a_locales_list_for_not_authenticated_user(): void { $this->loadFixturesFromFiles(['authentication/api_administrator.yaml']); - $this->client->request(method: 'GET', uri: '/api/v2/admin/locales'); + $this->requestGet('/api/v2/admin/locales'); - $response = $this->client->getResponse(); - $this->assertSame(Response::HTTP_UNAUTHORIZED, $response->getStatusCode()); + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_UNAUTHORIZED); } /** @test */ public function it_gets_a_locale(): void { $fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'locale.yaml']); - $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); /** @var LocaleInterface $locale */ $locale = $fixtures['locale_ga']; - $this->client->request( - method: 'GET', + $this->requestGet( uri: sprintf('/api/v2/admin/locales/%s', $locale->getCode()), - server: $header, + headers: $this->headerBuilder()->withJsonLdAccept()->withAdminUserAuthorization('api@example.com')->build(), ); - $this->assertResponse( - $this->client->getResponse(), - 'admin/locale/get_locale_response', - Response::HTTP_OK, - ); + $this->assertResponse($this->client->getResponse(), 'admin/locale/get_locale_response'); } /** @test */ public function it_gets_locales(): void { $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'locale.yaml']); - $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); - $this->client->request(method: 'GET', uri: '/api/v2/admin/locales', server: $header); + $this->requestGet( + uri: '/api/v2/admin/locales', + headers: $this->headerBuilder()->withJsonLdAccept()->withAdminUserAuthorization('api@example.com')->build(), + ); - $this->assertResponse($this->client->getResponse(), 'admin/locale/get_locales_response', Response::HTTP_OK); + $this->assertResponse($this->client->getResponse(), 'admin/locale/get_locales_response'); } /** @test */ public function it_creates_a_locale(): void { $this->loadFixturesFromFiles(['authentication/api_administrator.yaml']); - $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); + $header = $this->headerBuilder()->withJsonLdAccept()->withJsonLdContentType()->withAdminUserAuthorization('api@example.com')->build(); $this->client->request( method: 'POST', @@ -113,25 +84,37 @@ public function it_creates_a_locale(): void } /** @test */ - public function it_deletes_an_unused_locale(): void + public function it_does_not_allow_creating_a_locale_with_invalid_code(): void { - $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'locale.yaml']); - $header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER); + $this->loadFixturesFromFiles(['channel.yaml', 'authentication/api_administrator.yaml']); + $header = $this->headerBuilder()->withJsonLdAccept()->withJsonLdContentType()->withAdminUserAuthorization('api@example.com')->build(); $this->client->request( - method: 'DELETE', - uri: '/api/v2/admin/locales/en_US', + method: 'POST', + uri: '/api/v2/admin/locales', server: $header, + content: json_encode([ + 'code' => 'invalid', + ], \JSON_THROW_ON_ERROR), ); - $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT); - - $this->client->request( - method: 'GET', - uri: '/api/v2/admin/locales/en_US', - server: $header, + $this->assertResponse( + $this->client->getResponse(), + 'admin/locale/post_locale_with_invalid_code_response', + Response::HTTP_UNPROCESSABLE_ENTITY, ); + } + + /** @test */ + public function it_deletes_an_unused_locale(): void + { + $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'locale.yaml']); + $headers = $this->headerBuilder()->withJsonLdAccept()->withAdminUserAuthorization('api@example.com')->build(); + + $this->requestDelete(uri: '/api/v2/admin/locales/en_US', headers: $headers); + $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT); + $this->requestGet(uri: '/api/v2/admin/locales/en_US', headers: $headers); $this->assertResponseCode($this->client->getResponse(), Response::HTTP_NOT_FOUND); } } diff --git a/tests/Api/Shop/LocalesTest.php b/tests/Api/Shop/LocalesTest.php new file mode 100644 index 00000000000..02dbcbbb6f5 --- /dev/null +++ b/tests/Api/Shop/LocalesTest.php @@ -0,0 +1,49 @@ +loadFixturesFromFiles(['channel_without_locales.yaml', 'locale.yaml']); + + $this->requestGet(uri: '/api/v2/shop/locales', headers: self::CONTENT_TYPE_HEADER); + + $this->assertResponse($this->client->getResponse(), 'shop/locale/get_locales_response'); + } + + /** @test */ + public function it_gets_only_locales_from_current_channel(): void + { + $this->loadFixturesFromFiles(['locale.yaml', 'channel.yaml']); + + $this->requestGet(uri: '/api/v2/shop/locales', headers: self::CONTENT_TYPE_HEADER); + + $this->assertResponse($this->client->getResponse(), 'shop/locale/get_locales_from_channel_response'); + } + + /** @test */ + public function it_gets_locale(): void + { + $this->loadFixturesFromFiles(['channel.yaml']); + + $this->requestGet(uri: '/api/v2/shop/locales/en_US', headers: self::CONTENT_TYPE_HEADER); + + $this->assertResponse($this->client->getResponse(), 'shop/locale/get_locale_response'); + } +} From 2b1e4c8cb4caf90251a1787520bfc92a3927ea1f Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Thu, 13 Jun 2024 09:52:13 +0200 Subject: [PATCH 2/6] [API] Upgrade Locale resource --- .../config/api_platform/properties/Locale.xml | 1 + .../config/api_platform/resources/Locale.xml | 49 +++++++++- .../config/legacy_api_resources/Locale.xml | 98 ------------------- 3 files changed, 49 insertions(+), 99 deletions(-) delete mode 100644 src/Sylius/Bundle/ApiBundle/Resources/config/legacy_api_resources/Locale.xml diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/properties/Locale.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/properties/Locale.xml index a12b56ab574..9ef8e592d89 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/properties/Locale.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/properties/Locale.xml @@ -17,4 +17,5 @@ > + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml index 159121a6244..dae807a05e5 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml @@ -16,7 +16,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0 https://api-platform.com/schema/metadata/resources-3.0.xsd" > - + @@ -40,6 +40,41 @@ + + + + + + sylius:admin:locale:index + + + + + + + + + + + + sylius:admin:locale:create + + + + + + + + + sylius:admin:locale:show + + + + + + + + @@ -51,6 +86,18 @@ + + + + + + + sylius:shop:locale:index + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/legacy_api_resources/Locale.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/legacy_api_resources/Locale.xml deleted file mode 100644 index f12de7cf127..00000000000 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/legacy_api_resources/Locale.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - sylius - false - - - - GET - /admin/locales - - - admin:locale:index - sylius:admin:locale:index - - - - - - POST - /admin/locales - - - admin:locale:create - sylius:admin:locale:create - - - - - admin:locale:show - sylius:admin:locale:show - - - - - - GET - /shop/locales - - - shop:locale:index - sylius:shop:locale:index - - - - - - - - GET - /admin/locales/{code} - - - admin:locale:show - sylius:admin:locale:show - - - - - - DELETE - admin/locales/{code} - - - - GET - /shop/locales/{code} - - - shop:locale:show - sylius:shop:locale:show - - - - - - - - - - - - From 2023f57a61a976d1a794cc84259c9ec99848518d Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Thu, 13 Jun 2024 12:36:22 +0200 Subject: [PATCH 3/6] [API] Add query extension for Locale collection --- phpstan-baseline.neon | 5 -- .../LocaleCollectionExtension.php | 17 ++--- .../Resources/config/services/extensions.xml | 8 +-- .../LocaleCollectionExtensionSpec.php | 70 +++++++++++-------- 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index f85742315a4..4ff9cd52ab8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1490,11 +1490,6 @@ parameters: count: 1 path: src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/HideArchivedShippingMethodExtension.php - - - message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\Doctrine\\\\QueryCollectionExtension\\\\LocaleCollectionExtension\\:\\:applyToCollection\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/LocaleCollectionExtension.php - - message: "#^Method Sylius\\\\Bundle\\\\ApiBundle\\\\Doctrine\\\\QueryCollectionExtension\\\\OrdersByChannelExtension\\:\\:applyToCollection\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#" count: 1 diff --git a/src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/LocaleCollectionExtension.php b/src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/LocaleCollectionExtension.php index affbc06fbde..a0007943757 100644 --- a/src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/LocaleCollectionExtension.php +++ b/src/Sylius/Bundle/ApiBundle/Doctrine/QueryCollectionExtension/LocaleCollectionExtension.php @@ -17,21 +17,19 @@ use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; use ApiPlatform\Metadata\Operation; use Doctrine\ORM\QueryBuilder; -use Sylius\Bundle\ApiBundle\Context\UserContextInterface; +use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection; use Sylius\Bundle\ApiBundle\Serializer\ContextKeys; -use Sylius\Component\Core\Model\AdminUserInterface; +use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface; use Sylius\Component\Locale\Model\LocaleInterface; use Webmozart\Assert\Assert; final readonly class LocaleCollectionExtension implements QueryCollectionExtensionInterface { - public function __construct(private UserContextInterface $userContext) + public function __construct(private SectionProviderInterface $sectionProvider) { } - /** - * @param array $context - */ + /** @param array $context */ public function applyToCollection( QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, @@ -43,18 +41,17 @@ public function applyToCollection( return; } - $user = $this->userContext->getUser(); - if ($user instanceof AdminUserInterface && in_array('ROLE_API_ACCESS', $user->getRoles(), true)) { + if (!$this->sectionProvider->getSection() instanceof ShopApiSection) { return; } Assert::keyExists($context, ContextKeys::CHANNEL); $channel = $context[ContextKeys::CHANNEL]; - $localesParameterName = $queryNameGenerator->generateParameterName('locales'); - if ($channel->getLocales()->count() > 0) { + $localesParameterName = $queryNameGenerator->generateParameterName('locales'); $rootAlias = $queryBuilder->getRootAliases()[0]; + $queryBuilder ->andWhere(sprintf('%s.id in (:%s)', $rootAlias, $localesParameterName)) ->setParameter($localesParameterName, $channel->getLocales()) diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml index df2ec94bd32..af95e3da997 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/extensions.xml @@ -96,10 +96,10 @@ - - - - + + + + diff --git a/src/Sylius/Bundle/ApiBundle/spec/Doctrine/QueryCollectionExtension/LocaleCollectionExtensionSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Doctrine/QueryCollectionExtension/LocaleCollectionExtensionSpec.php index 31a794d6658..e82d39d9cde 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/Doctrine/QueryCollectionExtension/LocaleCollectionExtensionSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/Doctrine/QueryCollectionExtension/LocaleCollectionExtensionSpec.php @@ -18,44 +18,45 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\QueryBuilder; use PhpSpec\ObjectBehavior; -use Sylius\Bundle\ApiBundle\Context\UserContextInterface; +use Prophecy\Argument; +use Sylius\Bundle\ApiBundle\SectionResolver\AdminApiSection; +use Sylius\Bundle\ApiBundle\SectionResolver\ShopApiSection; use Sylius\Bundle\ApiBundle\Serializer\ContextKeys; -use Sylius\Component\Core\Model\AdminUserInterface; +use Sylius\Bundle\CoreBundle\SectionResolver\SectionProviderInterface; use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Locale\Model\LocaleInterface; use Symfony\Component\HttpFoundation\Request; final class LocaleCollectionExtensionSpec extends ObjectBehavior { - function let(UserContextInterface $userContext): void + function let(SectionProviderInterface $sectionProvider): void { - $this->beConstructedWith($userContext); + $this->beConstructedWith($sectionProvider); } - function it_throws_an_exception_if_context_has_not_channel( + public function it_does_not_apply_conditions_to_collection_for_unsupported_resource( + SectionProviderInterface $sectionProvider, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, ): void { - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('applyToCollection', [$queryBuilder, $queryNameGenerator, LocaleInterface::class, new Get()]) - ; + $sectionProvider->getSection()->shouldNotBeCalled(); + $queryBuilder->getRootAliases()->shouldNotBeCalled(); + $queryBuilder->andWhere(Argument::any())->shouldNotBeCalled(); + + $this->applyToCollection($queryBuilder, $queryNameGenerator, \stdClass::class); } - function it_does_not_apply_conditions_for_admin( - UserContextInterface $userContext, + function it_does_not_apply_conditions_for_non_shop_api_section( + SectionProviderInterface $sectionProvider, + AdminApiSection $adminApiSection, QueryBuilder $queryBuilder, - AdminUserInterface $admin, QueryNameGeneratorInterface $queryNameGenerator, ChannelInterface $channel, ): void { - $queryBuilder->getRootAliases()->willReturn(['o']); + $sectionProvider->getSection()->willReturn($adminApiSection); - $userContext->getUser()->willReturn($admin); - $admin->getRoles()->willReturn(['ROLE_API_ACCESS']); - - $queryBuilder->andWhere('o..id in :locales')->shouldNotBeCalled(); - $queryBuilder->setParameter('locales', $channel->getLocales())->shouldNotBeCalled(); + $queryBuilder->getRootAliases()->shouldNotBeCalled(); + $queryBuilder->andWhere(Argument::any())->shouldNotBeCalled(); $this->applyToCollection( $queryBuilder, @@ -69,25 +70,24 @@ function it_does_not_apply_conditions_for_admin( ); } - function it_applies_conditions_for_non_admin( - UserContextInterface $userContext, + function it_applies_conditions_for_shop_api_section( + SectionProviderInterface $sectionProvider, + ShopApiSection $shopApiSection, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, ChannelInterface $channel, LocaleInterface $locale, ): void { + $sectionProvider->getSection()->willReturn($shopApiSection); + $queryNameGenerator->generateParameterName('locales')->shouldBeCalled()->willReturn('locales'); - $queryBuilder->getRootAliases()->willReturn(['o']); - $userContext->getUser()->willReturn(null); + $locales = new ArrayCollection([$locale->getWrappedObject()]); + $channel->getLocales()->shouldBeCalled()->willReturn($locales); + $queryBuilder->getRootAliases()->willReturn(['o']); $queryBuilder->andWhere('o.id in (:locales)')->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject()); - - $localesCollection = new ArrayCollection([$locale]); - - $channel->getLocales()->shouldBeCalled()->willReturn($localesCollection); - - $queryBuilder->setParameter('locales', $localesCollection)->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject()); + $queryBuilder->setParameter('locales', $locales)->shouldBeCalled()->willReturn($queryBuilder->getWrappedObject()); $this->applyToCollection( $queryBuilder, @@ -100,4 +100,18 @@ function it_applies_conditions_for_non_admin( ], ); } + + function it_throws_an_exception_if_context_has_no_channel( + SectionProviderInterface $sectionProvider, + ShopApiSection $shopApiSection, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + ): void { + $sectionProvider->getSection()->willReturn($shopApiSection); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('applyToCollection', [$queryBuilder, $queryNameGenerator, LocaleInterface::class, new Get()]) + ; + } } From b766c1b4b94d41a099f31efec585e9f178657a08 Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Thu, 13 Jun 2024 15:02:21 +0200 Subject: [PATCH 4/6] [API] Enable Behat scenarios for Locale --- ...dent_translatable_entities_locales.feature | 2 +- .../managing_locales/adding_locale.feature | 2 +- .../locale_unique_code_validation.feature | 2 +- .../managing_locales/removing_locale.feature | 4 +- ...p_in_different_than_default_locale.feature | 7 +-- ...erent_locales_on_multiple_channels.feature | 7 +-- .../redirecting_to_default_locale.feature | 5 +- .../locale/switching_current_locale.feature | 8 ++-- .../config/services/contexts/api/admin.xml | 8 ++-- .../config/services/contexts/api/shop.xml | 48 +++++++++---------- .../Behat/Resources/config/suites/api.yml | 4 +- ...ging_locales.yml => managing_locales.yaml} | 0 12 files changed, 51 insertions(+), 46 deletions(-) rename src/Sylius/Behat/Resources/config/suites/api/locale/{managing_locales.yml => managing_locales.yaml} (100%) diff --git a/features/admin/locale/channel_independent_translatable_entities_locales.feature b/features/admin/locale/channel_independent_translatable_entities_locales.feature index a48591c9f00..8daf6e8c7ab 100644 --- a/features/admin/locale/channel_independent_translatable_entities_locales.feature +++ b/features/admin/locale/channel_independent_translatable_entities_locales.feature @@ -10,7 +10,7 @@ Feature: Channel independent translatable entities locales And it uses the "English (United States)" locale by default And I am logged in as an administrator - @todo @ui + @no-api @todo @ui Scenario: Using all locales to translate an entity Given the store has locale "German (Germany)" When I want to create a new translatable entity diff --git a/features/admin/locale/managing_locales/adding_locale.feature b/features/admin/locale/managing_locales/adding_locale.feature index 1359deded48..26cf3dc1ed0 100644 --- a/features/admin/locale/managing_locales/adding_locale.feature +++ b/features/admin/locale/managing_locales/adding_locale.feature @@ -7,7 +7,7 @@ Feature: Adding a new locale Background: Given I am logged in as an administrator - @todo @ui @api + @api @ui Scenario: Adding a new locale When I want to create a new locale And I choose Norwegian diff --git a/features/admin/locale/managing_locales/locale_unique_code_validation.feature b/features/admin/locale/managing_locales/locale_unique_code_validation.feature index 58f996bd1a3..1ec08969c63 100644 --- a/features/admin/locale/managing_locales/locale_unique_code_validation.feature +++ b/features/admin/locale/managing_locales/locale_unique_code_validation.feature @@ -8,7 +8,7 @@ Feature: Locale unique code validation Given the store has locale "Norwegian (Norway)" And I am logged in as an administrator - @todo @ui @api + @api @ui Scenario: Trying to add new locale with used code When I want to add a new locale Then I should not be able to choose "Norwegian (Norway)" diff --git a/features/admin/locale/managing_locales/removing_locale.feature b/features/admin/locale/managing_locales/removing_locale.feature index 941ee53fe42..a6cccbb8423 100644 --- a/features/admin/locale/managing_locales/removing_locale.feature +++ b/features/admin/locale/managing_locales/removing_locale.feature @@ -10,7 +10,7 @@ Feature: Removing locales And it uses the "English (United States)" locale by default And I am logged in as an administrator - @todo @ui @api + @api @ui Scenario: Deleting unused locale Given the store has a product "T-Shirt banana" And this product is named "Banana T-Shirt with Minions" in the "English (United States)" locale @@ -19,7 +19,7 @@ Feature: Removing locales Then I should be informed that locale "Polish (Poland)" has been deleted And only the "English (United States)" locale should be present in the system - @todo @ui @api + @api @ui Scenario: Deleting a locale in use Given the store has a product "T-Shirt banana" And this product is named "Banana T-Shirt with Minions" in the "English (United States)" locale diff --git a/features/shop/locale/browsing_shop_in_different_than_default_locale.feature b/features/shop/locale/browsing_shop_in_different_than_default_locale.feature index e340a529912..a84f9b5b22d 100644 --- a/features/shop/locale/browsing_shop_in_different_than_default_locale.feature +++ b/features/shop/locale/browsing_shop_in_different_than_default_locale.feature @@ -12,18 +12,19 @@ Feature: Browsing shop in different than default locale And this product is named "Koszulka bananowa" in the "Polish (Poland)" locale And this product is named "香蕉T恤" in the "Chinese (Simplified, China)" locale - @ui @api +# These scenarios should be implemented after implementing Product resource in APIP3 + @todo-api @ui Scenario: Browsing product details in non-default locale When I browse that channel And I check this product's details in the "Polish (Poland)" locale Then I should see the product name "Koszulka bananowa" - @ui @api + @todo-api @ui Scenario: Browsing product details in non-default locale When I check this product's details in the "Chinese (Simplified, China)" locale Then I should see the product name "香蕉T恤" - @ui @api + @todo-api @ui Scenario: Not being able to shop using a locale non-existent in the channel When I browse that channel And I try to check this product's details in the "Irish (Ireland)" locale diff --git a/features/shop/locale/handling_different_locales_on_multiple_channels.feature b/features/shop/locale/handling_different_locales_on_multiple_channels.feature index 1565e7be243..7edbe292c45 100644 --- a/features/shop/locale/handling_different_locales_on_multiple_channels.feature +++ b/features/shop/locale/handling_different_locales_on_multiple_channels.feature @@ -12,20 +12,21 @@ Feature: Handling different locales on multiple channels And that channel allows to shop using "Polish (Poland)" and "Norwegian (Norway)" locales And it uses the "Polish (Poland)" locale by default - @ui @api +# These scenarios should be implemented after implementing Order resource in APIP3 + @todo-api @ui Scenario: Showing locales only from the current channel When I browse the "Mobile" channel Then I should shop using the "Polish (Poland)" locale And I should be able to shop using the "Norwegian (Norway)" locale And I should not be able to shop using the "English (United States)" locale - @ui @api + @todo-api @ui Scenario: Browsing channels using their default locales When I browse the "Web" channel And I start browsing the "Mobile" channel Then I should shop using the "Polish (Poland)" locale - @ui @api + @todo-api @ui Scenario: Switching a locale applies only to the current channel When I browse the "Web" channel And I switch to the "Norwegian (Norway)" locale diff --git a/features/shop/locale/redirecting_to_default_locale.feature b/features/shop/locale/redirecting_to_default_locale.feature index 69048d2942f..72eb371d13f 100644 --- a/features/shop/locale/redirecting_to_default_locale.feature +++ b/features/shop/locale/redirecting_to_default_locale.feature @@ -10,13 +10,14 @@ Feature: Redirecting to the default locale And it uses the "English (United States)" locale by default And the store has a product "PHP T-Shirt" - @ui @api +# These scenarios should be implemented after implementing Order resource in APIP3 + @todo-api @ui Scenario: Staying on the current locale if it is available When I browse that channel And I use the locale "French (France)" Then I should shop using the "French (France)" locale - @ui @api + @todo-api @ui Scenario: Redirecting to default locale if it is not available When I browse that channel And I use the locale "Polish (Poland)" diff --git a/features/shop/locale/switching_current_locale.feature b/features/shop/locale/switching_current_locale.feature index 31c78ac0784..faedebf3b9d 100644 --- a/features/shop/locale/switching_current_locale.feature +++ b/features/shop/locale/switching_current_locale.feature @@ -9,17 +9,19 @@ Feature: Switching the current locale And that channel allows to shop using "English (United States)" and "Polish (Poland)" locales And it uses the "English (United States)" locale by default - @ui @api +# This scenario should be implemented after implementing Order resource in APIP3 + @todo-api @ui Scenario: Showing the current locale When I browse that channel Then I should shop using the "English (United States)" locale - @ui @api + @api @ui Scenario: Showing available locales When I browse that channel Then I should be able to shop using the "Polish (Poland)" locale - @ui @api +# This scenario should be implemented after implementing Order resource in APIP3 + @todo-api @ui Scenario: Switching the current locale When I browse that channel And I switch to the "Polish (Poland)" locale diff --git a/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml b/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml index 18bfa6b7997..0034a7437e1 100644 --- a/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml +++ b/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml @@ -100,10 +100,10 @@ %sylius.security.new_api_route% - - - - + + + + diff --git a/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml b/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml index 5b04fe020cc..f1c723fafd8 100644 --- a/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml +++ b/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml @@ -38,16 +38,16 @@ - - - - - - - - - - + + + + + + + + + %sylius.security.new_api_route% + @@ -104,15 +104,15 @@ %sylius.security.new_api_route% - - - - - - - - - + + + + + + + + %sylius.security.new_api_route% + @@ -172,11 +172,11 @@ - - - - - + + + + + diff --git a/src/Sylius/Behat/Resources/config/suites/api.yml b/src/Sylius/Behat/Resources/config/suites/api.yml index 39242cd9d43..784232f9424 100644 --- a/src/Sylius/Behat/Resources/config/suites/api.yml +++ b/src/Sylius/Behat/Resources/config/suites/api.yml @@ -27,8 +27,8 @@ imports: # - api/inventory/cart_inventory.yml # - api/inventory/checkout_inventory.yaml # - api/inventory/managing_inventory.yaml -# - api/locale/locales.yaml -# - api/locale/managing_locales.yml + - api/locale/locales.yaml + - api/locale/managing_locales.yaml # - api/order/managing_orders.yml # - api/order/modifying_placed_order_address.yaml # - api/order/order_history.yaml diff --git a/src/Sylius/Behat/Resources/config/suites/api/locale/managing_locales.yml b/src/Sylius/Behat/Resources/config/suites/api/locale/managing_locales.yaml similarity index 100% rename from src/Sylius/Behat/Resources/config/suites/api/locale/managing_locales.yml rename to src/Sylius/Behat/Resources/config/suites/api/locale/managing_locales.yaml From 6b9c2b1f7ee0ce2b0fbd4fb0a03a61879edccbe1 Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Thu, 13 Jun 2024 15:13:16 +0200 Subject: [PATCH 5/6] [API] Add state processor for deleting Locale --- .../DataPersister/LocaleDataPersister.php | 59 ------------ .../config/api_platform/resources/Locale.xml | 6 +- .../config/services/data_persisters.xml | 6 -- .../config/services/state_processors.xml | 6 ++ .../StateProcessor/Delete/LocaleProcessor.php | 44 +++++++++ .../DataPersister/LocaleDataPersisterSpec.php | 77 ---------------- .../Delete/LocaleProcessorSpec.php | 91 +++++++++++++++++++ 7 files changed, 146 insertions(+), 143 deletions(-) delete mode 100644 src/Sylius/Bundle/ApiBundle/DataPersister/LocaleDataPersister.php create mode 100644 src/Sylius/Bundle/ApiBundle/StateProcessor/Delete/LocaleProcessor.php delete mode 100644 src/Sylius/Bundle/ApiBundle/disabledSpec/DataPersister/LocaleDataPersisterSpec.php create mode 100644 src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Delete/LocaleProcessorSpec.php diff --git a/src/Sylius/Bundle/ApiBundle/DataPersister/LocaleDataPersister.php b/src/Sylius/Bundle/ApiBundle/DataPersister/LocaleDataPersister.php deleted file mode 100644 index bd41ba8601f..00000000000 --- a/src/Sylius/Bundle/ApiBundle/DataPersister/LocaleDataPersister.php +++ /dev/null @@ -1,59 +0,0 @@ - $context - */ - public function supports($data, array $context = []): bool - { - return $data instanceof LocaleInterface; - } - - /** - * @param array $context - */ - public function persist($data, array $context = []): object - { - return $this->decoratedDataPersister->persist($data, $context); - } - - /** - * @param LocaleInterface $data - * @param array $context - * - * @throws LocaleIsUsedException - */ - public function remove($data, array $context = []): mixed - { - if ($this->localeUsageChecker->isUsed($data->getCode())) { - throw new LocaleIsUsedException($data->getCode()); - } - - return $this->decoratedDataPersister->remove($data, $context); - } -} diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml index dae807a05e5..e7f80d3229f 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml @@ -73,7 +73,11 @@ - + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml index 19bdf604ba3..3cc0fd598f7 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/data_persisters.xml @@ -36,12 +36,6 @@ - - - - - - diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml index 6d68df58d46..720842e6d13 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml @@ -30,6 +30,12 @@ + + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Delete/LocaleProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Delete/LocaleProcessor.php new file mode 100644 index 00000000000..d94e66029b6 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Delete/LocaleProcessor.php @@ -0,0 +1,44 @@ + */ +final readonly class LocaleProcessor implements ProcessorInterface +{ + public function __construct( + private ProcessorInterface $removeProcessor, + private LocaleUsageCheckerInterface $localeUsageChecker, + ) { + } + + public function process($data, Operation $operation, array $uriVariables = [], array $context = []) + { + Assert::isInstanceOf($data, LocaleInterface::class); + Assert::isInstanceOf($operation, DeleteOperationInterface::class); + + if ($this->localeUsageChecker->isUsed($data->getCode())) { + throw new LocaleIsUsedException($data->getCode()); + } + + return $this->removeProcessor->process($data, $operation, $uriVariables, $context); + } +} diff --git a/src/Sylius/Bundle/ApiBundle/disabledSpec/DataPersister/LocaleDataPersisterSpec.php b/src/Sylius/Bundle/ApiBundle/disabledSpec/DataPersister/LocaleDataPersisterSpec.php deleted file mode 100644 index 70099d34b19..00000000000 --- a/src/Sylius/Bundle/ApiBundle/disabledSpec/DataPersister/LocaleDataPersisterSpec.php +++ /dev/null @@ -1,77 +0,0 @@ -beConstructedWith($decoratedDataPersister, $localeUsageChecker); - } - - public function it_supports_only_locale_interface(): void - { - $this->supports(new stdClass())->shouldReturn(false); - $this->supports(new Locale())->shouldReturn(true); - } - - public function it_persists_locale( - ContextAwareDataPersisterInterface $decoratedDataPersister, - Locale $locale, - ): void { - $decoratedDataPersister->persist($locale, [])->shouldBeCalled()->willReturn(new stdClass()); - - $this->persist($locale); - } - - public function it_removes_locale( - ContextAwareDataPersisterInterface $decoratedDataPersister, - LocaleUsageCheckerInterface $localeUsageChecker, - Locale $locale, - ): void { - $locale->getCode()->willReturn('en_US'); - - $localeUsageChecker->isUsed('en_US')->willReturn(false); - - $decoratedDataPersister->remove($locale, [])->shouldBeCalled(); - - $this->remove($locale); - } - - public function it_throws_an_exception_if_locale_is_used( - ContextAwareDataPersisterInterface $decoratedDataPersister, - LocaleUsageCheckerInterface $localeUsageChecker, - Locale $locale, - ): void { - $locale->getCode()->willReturn('en_US'); - - $localeUsageChecker->isUsed('en_US')->willReturn(true); - - $decoratedDataPersister->remove($locale, [])->shouldNotBeCalled(); - - $this - ->shouldThrow(LocaleIsUsedException::class) - ->during('remove', [$locale]) - ; - } -} diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Delete/LocaleProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Delete/LocaleProcessorSpec.php new file mode 100644 index 00000000000..fb55f7d7433 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Delete/LocaleProcessorSpec.php @@ -0,0 +1,91 @@ +beConstructedWith($removeProcessor, $localeUsageChecker); + } + + function it_throws_an_exception_if_object_is_not_a_locale( + ProcessorInterface $removeProcessor, + LocaleUsageCheckerInterface $localeUsageChecker, + ): void { + $removeProcessor->process(Argument::cetera())->shouldNotBeCalled(); + $localeUsageChecker->isUsed(Argument::any())->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('process', [new \stdClass(), new Delete()]) + ; + } + + function it_throws_an_exception_if_operation_is_not_delete( + ProcessorInterface $removeProcessor, + LocaleUsageCheckerInterface $localeUsageChecker, + LocaleInterface $locale, + ): void { + $removeProcessor->process(Argument::cetera())->shouldNotBeCalled(); + $localeUsageChecker->isUsed(Argument::any())->shouldNotBeCalled(); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('process', [$locale, new Post()]) + ; + } + + function it_throws_an_exception_if_a_given_locale_is_used( + ProcessorInterface $removeProcessor, + LocaleUsageCheckerInterface $localeUsageChecker, + LocaleInterface $locale, + ): void { + $locale->getCode()->willReturn('pl_PL'); + $localeUsageChecker->isUsed('pl_PL')->willReturn(true); + + $removeProcessor->process(Argument::cetera())->shouldNotBeCalled(); + + $this + ->shouldThrow(LocaleIsUsedException::class) + ->during('process', [$locale, new Delete()]) + ; + } + + function it_removes_a_locale( + ProcessorInterface $removeProcessor, + LocaleUsageCheckerInterface $localeUsageChecker, + LocaleInterface $locale, + ): void { + $operation = new Delete(); + + $locale->getCode()->willReturn('pl_PL'); + $localeUsageChecker->isUsed('pl_PL')->willReturn(false); + + $removeProcessor->process($locale, $operation, [], [])->shouldBeCalled(); + + $this->process($locale, $operation); + } +} From f8d7956ac19024d1ae6dc9a068249c66d5cc4716 Mon Sep 17 00:00:00 2001 From: Grzegorz Sadowski Date: Fri, 14 Jun 2024 07:18:40 +0200 Subject: [PATCH 6/6] [API] Move paginationEnabled option to the specific operation instead of the entire Locale resource --- .../Resources/config/api_platform/resources/Locale.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml index e7f80d3229f..f3313797beb 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/api_platform/resources/Locale.xml @@ -16,7 +16,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://api-platform.com/schema/metadata/resources-3.0 https://api-platform.com/schema/metadata/resources-3.0.xsd" > - + @@ -91,7 +91,7 @@ - +