Resolve conflicts between 2.0 and api-platform-3

This commit is contained in:
Wojdylak 2024-04-23 08:12:51 +02:00
commit 12c05d0f14
No known key found for this signature in database
GPG key ID: 7509E560A6821ABE
546 changed files with 7696 additions and 5146 deletions

View file

@ -47,12 +47,12 @@ jobs:
name: End-to-end tests (Custom)
needs: static-checks
uses: ./.github/workflows/ci_e2e-custom.yaml
frontend:
name: Frontend
needs: static-checks
uses: ./.github/workflows/ci_frontend.yaml
with:
type: minimal
# frontend:
# name: Frontend
# needs: static-checks
# uses: ./.github/workflows/ci_frontend.yaml
# with:
# type: minimal
packages:
name: Packages
needs: static-checks

View file

@ -56,7 +56,7 @@ jobs:
run: |
composer config minimum-stability dev
composer config prefer-stable true
- name: Prepare manifest.json files
run: |
mkdir -p public/build/admin
@ -91,8 +91,8 @@ jobs:
- name: Run non-UI Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" --rerun
- name: Run non-JS Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
# - name: Run non-JS Behat
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
- name: Upload logs
uses: actions/upload-artifact@v3

View file

@ -76,7 +76,7 @@ jobs:
- name: "Checkout"
if: "${{ inputs.branch == '' }}"
uses: actions/checkout@v4
- name: Prepare manifest.json files
run: |
mkdir -p public/build/admin
@ -87,7 +87,7 @@ jobs:
echo "{}" > public/build/shop/manifest.json
echo "{}" > public/build/app/admin/manifest.json
echo "{}" > public/build/app/shop/manifest.json
- name: Build application
uses: SyliusLabs/BuildTestAppAction@v2.2
with:
@ -111,8 +111,8 @@ jobs:
- name: Run non-UI Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" --rerun
- name: Run non-JS Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
# - name: Run non-JS Behat
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
- name: Upload logs
uses: actions/upload-artifact@v3

View file

@ -90,7 +90,7 @@ jobs:
echo "{}" > public/build/shop/manifest.json
echo "{}" > public/build/app/admin/manifest.json
echo "{}" > public/build/app/shop/manifest.json
- name: Build application
uses: SyliusLabs/BuildTestAppAction@v2.2
with:
@ -116,8 +116,8 @@ jobs:
- name: Run non-UI Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli" --suite-tags="@api,@domain,@hybrid" --rerun
- name: Run non-JS Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
# - name: Run non-JS Behat
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
- name: Upload logs
uses: actions/upload-artifact@v3
@ -129,85 +129,85 @@ jobs:
var/log
if-no-files-found: ignore
behat-ui-js:
needs: get-matrix
runs-on: ubuntu-latest
name: "JS, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}, Twig ${{ matrix.twig }}, API Platform ${{ matrix.api-platform }}"
timeout-minutes: 45
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.get-matrix.outputs.matrix) }}
env:
APP_ENV: test_cached
DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?charset=utf8mb4&serverVersion=${{ matrix.mysql }}"
steps:
- name: Set variables
shell: bash
env:
BRANCH: ${{ inputs.branch }}
run: |
if [ "$BRANCH" == "1.12" ]; then
echo "USE_LEGACY_POSTGRES_SETUP=yes" >> $GITHUB_ENV
else
echo "USE_LEGACY_POSTGRES_SETUP=no" >> $GITHUB_ENV
fi
- name: "Checkout (With Branch)"
if: "${{ inputs.branch != '' }}"
uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }}
- name: "Checkout"
if: "${{ inputs.branch == '' }}"
uses: actions/checkout@v4
- name: Get Composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: "Restore dependencies"
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
restore-keys: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
- name: Restrict Twig
if: matrix.twig == '^2.12'
run: composer require --no-update --no-scripts --no-interaction "twig/twig:${{ matrix.twig }}"
- name: Build application
uses: SyliusLabs/BuildTestAppAction@v2.2
with:
build_type: "sylius"
cache_key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
cache_restore_key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
e2e: "yes"
e2e_js: "yes"
database_version: ${{ matrix.mysql }}
legacy_postgresql_setup: ${{ env.USE_LEGACY_POSTGRES_SETUP }}
php_version: ${{ matrix.php }}
symfony_version: ${{ matrix.symfony }}
node_version: "20.x"
- name: Install Behat driver
run: vendor/bin/bdi detect drivers
- name: Run Behat (Chromedriver)
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
- name: Run Behat (Panther)
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@javascript&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@javascript&&~@todo&&~@cli" --suite-tags="@ui" --rerun
- name: Upload logs
uses: actions/upload-artifact@v3
if: failure()
with:
name: "Logs (JS, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, ApiPlatform ${{ matrix.api-platform }}, Twig ${{ matrix.twig }}, MySQL ${{ matrix.mysql }})"
path: |
etc/build/
var/log
if-no-files-found: ignore
# behat-ui-js:
# needs: get-matrix
# runs-on: ubuntu-latest
# name: "JS, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}, Twig ${{ matrix.twig }}, API Platform ${{ matrix.api-platform }}"
# timeout-minutes: 45
# strategy:
# fail-fast: false
# matrix: ${{ fromJson(needs.get-matrix.outputs.matrix) }}
#
# env:
# APP_ENV: test_cached
# DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?charset=utf8mb4&serverVersion=${{ matrix.mysql }}"
#
# steps:
# - name: Set variables
# shell: bash
# env:
# BRANCH: ${{ inputs.branch }}
# run: |
# if [ "$BRANCH" == "1.12" ]; then
# echo "USE_LEGACY_POSTGRES_SETUP=yes" >> $GITHUB_ENV
# else
# echo "USE_LEGACY_POSTGRES_SETUP=no" >> $GITHUB_ENV
# fi
#
# - name: "Checkout (With Branch)"
# if: "${{ inputs.branch != '' }}"
# uses: actions/checkout@v4
# with:
# ref: ${{ inputs.branch }}
#
# - name: "Checkout"
# if: "${{ inputs.branch == '' }}"
# uses: actions/checkout@v4
#
# - name: Get Composer cache directory
# id: composer-cache
# run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
#
# - name: "Restore dependencies"
# uses: actions/cache@v3
# with:
# path: ${{ steps.composer-cache.outputs.dir }}
# key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
# restore-keys: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
#
# - name: Restrict Twig
# if: matrix.twig == '^2.12'
# run: composer require --no-update --no-scripts --no-interaction "twig/twig:${{ matrix.twig }}"
#
# - name: Build application
# uses: SyliusLabs/BuildTestAppAction@v2.2
# with:
# build_type: "sylius"
# cache_key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
# cache_restore_key: "${{ github.run_id }}-${{ runner.os }}-${{ hashFiles('composer.json') }}-symfony-${{ matrix.symfony }}-api-platform-${{ matrix.api-platform }}"
# e2e: "yes"
# e2e_js: "yes"
# database_version: ${{ matrix.mysql }}
# legacy_postgresql_setup: ${{ env.USE_LEGACY_POSTGRES_SETUP }}
# php_version: ${{ matrix.php }}
# symfony_version: ${{ matrix.symfony }}
# node_version: "20.x"
#
# - name: Install Behat driver
# run: vendor/bin/bdi detect drivers
#
# - name: Run Behat (Chromedriver)
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@mink:chromedriver&&~@todo&&~@cli" --suite-tags="@ui" --rerun
#
# - name: Run Behat (Panther)
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@javascript&&~@todo&&~@cli" --suite-tags="@ui" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="@javascript&&~@todo&&~@cli" --suite-tags="@ui" --rerun
#
# - name: Upload logs
# uses: actions/upload-artifact@v3
# if: failure()
# with:
# name: "Logs (JS, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, ApiPlatform ${{ matrix.api-platform }}, Twig ${{ matrix.twig }}, MySQL ${{ matrix.mysql }})"
# path: |
# etc/build/
# var/log
# if-no-files-found: ignore

View file

@ -66,7 +66,7 @@ jobs:
- name: "Checkout"
if: "${{ inputs.branch == '' }}"
uses: actions/checkout@v4
- name: Prepare manifest.json files
run: |
mkdir -p public/build/admin
@ -77,7 +77,7 @@ jobs:
echo "{}" > public/build/shop/manifest.json
echo "{}" > public/build/app/admin/manifest.json
echo "{}" > public/build/app/shop/manifest.json
- name: Build application
uses: SyliusLabs/BuildTestAppAction@v2.2
with:
@ -101,8 +101,8 @@ jobs:
- name: Run non-UI Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli&&~@no-postgres" --suite-tags="@api,@domain,@hybrid" || vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@todo&&~@cli&&~@no-postgres" --suite-tags="@api,@domain,@hybrid" --rerun
- name: Run non-JS Behat
run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli&&~@no-postgres" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli&&~@no-postgres" --suite-tags="@ui" --rerun
# - name: Run non-JS Behat
# run: vendor/bin/behat --colors --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli&&~@no-postgres" --suite-tags="@ui" || vendor/bin/behat --strict --no-interaction -vvv -f progress --tags="~@javascript&&~@mink:chromedriver&&~@todo&&~@cli&&~@no-postgres" --suite-tags="@ui" --rerun
- name: Upload logs
uses: actions/upload-artifact@v3

View file

@ -5,7 +5,7 @@
{
"php": "8.2",
"symfony": "^6.4",
"api-platform": "^2.7.10"
"api-platform": "^3.1"
}
]
},
@ -25,7 +25,7 @@
{
"php": "8.2",
"symfony": "^6.4",
"api-platform": "^2.7.10",
"api-platform": "^3.1",
"mysql": "8.0",
"twig": "^3.3"
}
@ -68,7 +68,7 @@
"static-checks": {
"php": [ "8.2" ],
"symfony": [ "^6.4" ],
"api-platform": [ "^2.7.10" ]
"api-platform": [ "^3.1" ]
},
"e2e-mariadb": {
"php": [ "8.2" ],
@ -79,7 +79,7 @@
"e2e-mysql": {
"php": [ "8.2" ],
"symfony": [ "^6.4" ],
"api-platform": [ "^2.7.10" ],
"api-platform": [ "^3.1" ],
"mysql": [ "5.7", "8.0" ],
"twig": [ "^3.3" ]
},

View file

@ -3,21 +3,11 @@
This document explains why certain conflicts were added to `composer.json` and
references related issues.
- `lexik/jwt-authentication-bundle: ^2.18`
After bumping to this version ApiBundle starts failing due to requesting a non-existing `api_platform.openapi.factory.legacy` service.
As we are not using this service across the ApiBundle we added this conflict to unlock the builds, until we investigate the problem.
- `doctrine/orm:>= 2.16.0`
This version makes Sylius Fixtures loading fail on the product review fixtures.
References: https://github.com/doctrine/orm/issues/10869
- `symfony/validator:5.4.25`
This version introduced a bug, causing validation constraints to not work.
References: https://github.com/symfony/symfony/issues/50780
- `stof/doctrine-extensions-bundle:1.8.0`
This version introduced configuring the metadata cache for the extensions, what breaks the `Timestampable` behaviour.
@ -28,11 +18,6 @@ references related issues.
- https://github.com/stof/StofDoctrineExtensionsBundle/issues/455
- https://github.com/doctrine-extensions/DoctrineExtensions/issues/2600
- `api-platform/core:2.7.17`:
This version introduced class aliases, which lead to a fatal error:
`The autoloader expected class "ApiPlatform\Core\Bridge\Symfony\Bundle\DependencyInjection\ApiPlatformExtension" to be defined in file ".../vendor/api-platform/core/src/Core/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php". The file was found but the class was not in it, the class name or namespace probably has a typo.`
- `twig/twig:3.9.0`:
This version has a bug, which lead to a fatal error:

View file

@ -98,6 +98,34 @@
+ private string $targetState = PaymentInterface::STATE_CART,
)
```
* The signature of method `applyToCollection` of the following classes has been changed:
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\AcceptedProductReviewsExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\AddressesExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\AvailableProductAssociationsInProductCollectionExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\CountryCollectionExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\CurrencyCollectionExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\EnabledProductVariantsExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\HideArchivedShippingMethodExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\LocaleCollectionExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrdersByChannelExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrdersByLoggedInUserExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\ProductsByChannelAndLocaleCodeExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\ProductsByTaxonExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\ProductsWithEnableFlagExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\ProductsWithEnableFlagExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\RestrictingFilterEagerLoadingExtension`
* `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\TaxonCollectionExtension`
```php
public function applyToCollection(
QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
- string $operationName = null,
+ \ApiPlatform\Metadata\Operation $operation = null,
array $context = [],
): void;
```
* The `swiftmailer/swiftmailer` dependency has been removed. Use `symfony/mailer` instead.

View file

@ -1 +1,159 @@
# UPGRADE FROM `1.13` TO `2.0`
* API Platform has dropped `DataProviders` and `DataPersisters` in favor of `Providers` and `Processors`, respectively.
Due to this change, Sylius custom `DataProviders` and `DataPersisters` have been adapted to the new API Platform interfaces
and their namespaced have been changed to `StateProvider` and `StateProcessor` respectively:
- `Sylius\Bundle\ApiBundle\DataPersister\*DataPersister` => `Sylius\Bundle\ApiBundle\StateProcessor\*Processor`
- `Sylius\Bundle\ApiBundle\DataProvider\*DataProvider` => `Sylius\Bundle\ApiBundle\StateProvider\*Provider`
* API Platform has also dropped `DataTransformers` in favor of which `some of them` have been refactored into `SerializerContextBuilders` as follows:
- `Sylius\Bundle\ApiBundle\DataTransformer\ChannelCodeAwareInputCommandDataTransformer` => `Sylius\Bundle\ApiBundle\SerializerContextBuilder\ChannelCodeAwareContextBuilder`
- `Sylius\Bundle\ApiBundle\DataTransformer\LocaleCodeAwareInputCommandDataTransformer` => `Sylius\Bundle\ApiBundle\SerializerContextBuilder\LocaleCodeAwareContextBuilder`
- `Sylius\Bundle\ApiBundle\DataTransformer\LoggedInCustomerEmailIfNotSetAwareCommandDataTransformer` => `Sylius\Bundle\ApiBundle\SerializerContextBuilder\LoggedInCustomerEmailIfNotSetAwareContextBuilder`
- `Sylius\Bundle\ApiBundle\DataTransformer\LoggedInShopUserIdAwareCommandDataTransformer` => `Sylius\Bundle\ApiBundle\SerializerContextBuilder\ChannelCodeAwareContextBuilder`
* The constructor of `Sylius\Bundle\ApiBundle\Command\Account\RegisterShopUser` has been changed:
```php
public function __construct(
- public string $firstName,
- public string $lastName,
- public string $email,
- public string $password,
- public bool $subscribedToNewsletter = false,
+ protected string $firstName,
+ protected string $lastName,
+ protected string $email,
+ protected string $password,
+ protected ?string $channelCode,
+ protected ?string $localeCode,
+ protected bool $subscribedToNewsletter = false,
) {
}
```
* The constructor of `Sylius\Bundle\ApiBundle\Command\Account\RequestResetPasswordToken` has been changed:
```php
public function __construct(
- public string $email,
+ protected string $email,
+ protected ?string $channelCode,
+ protected ?string $localeCode,
) {
}
```
* The constructor of `Sylius\Bundle\ApiBundle\Command\SendContactRequest` has been changed:
```php
public function __construct(
- private ?string $email = null,
- private ?string $message = null,
+ protected ?string $channelCode,
+ protected ?string $localeCode,
+ protected ?string $email = null,
+ protected ?string $message = null,
) {
}
```
* The constructor of `Sylius\Bundle\ApiBundle\Command\Account\VerifyShopUser` has been changed:
```php
public function __construct(
- public string $token,
- private ?string $localeCode = null,
- private ?string $channelCode = null,
+ protected string $token,
+ protected string $channelCode,
+ protected string $localeCode,
) {
}
```
* The constructor of `Sylius\Bundle\ApiBundle\Command\Account\ChangeShopUserPassword` has been changed:
```php
public function __construct(
- public ?string $newPassword,
- public ?string $confirmNewPassword,
- public ?string $currentPassword,
+ protected mixed $shopUserId,
+ protected string $newPassword,
+ protected string $confirmNewPassword,
+ protected string $currentPassword,
) {
}
```
* The constructor of `Sylius\Bundle\ApiBundle\Command\Account\RequestShopUserVerification` has been created:
```php
public function __construct(
+ protected string|int|null $shopUserId,
+ protected ?string $channelCode,
+ protected ?string $localeCode,
) {
}
```
All the `setter` methods have been removed from the commands above and also there are some new `getter` methods accordingly to arguments visibility changes.
* The parameter type and order of the `Sylius\Bundle\ApiBundle\Controller\UploadAvatarImageAction::__construct` has been changed:
```php
public function __construct(
private FactoryInterface $avatarImageFactory,
private AvatarImageRepositoryInterface $avatarImageRepository,
- private ImageUploaderInterface $imageUploader,
- private IriConverterInterface $iriConverter,
+ private RepositoryInterface $adminUserRepository,
+ private ImageUploaderInterface $imageUploader,
)
```
* Updated API routes related to avatar management:
Previous Routes:
* `'GET' - /api/v2/admin/avatar-images/{id}`
* `'POST' - /api/v2/admin/avatar-images`
* `'DELETE' - /api/v2/admin/avatar-images/{id}`
New Routes:
* `'GET' - /api/v2/admin/administrators/{id}/avatar-image`
* `'POST' - /api/v2/admin/administrators/{id}/avatar-image`
* `'DELETE' - /api/v2/admin/administrators/{id}/avatar-image`
* Updated API routes related to shop user management:
Previous Routes:
* `'POST' - /api/v2/shop/reset-password-requests`
* `'PATCH' - /api/v2/shop/reset-password-requests/{resetPasswordToken}`
* `'POST' - /api/v2/shop/account-verification-requests`
* `'PATCH - /api/v2/shop/account-verification-requests/{token}`
New Routes:
* `'POST' - /api/v2/shop/reset-password`
* `'PATCH' - /api/v2/shop/reset-password/{resetPasswordToken}`
* `'POST' - /api/v2/shop/verify-shop-user`
* `'PATCH' - /api/v2/shop/verify-shop-user/{token}`
* Updated API routes related to admin user management:
Previous Routes:
* `'POST' - /api/v2/admin/reset-password-requests`
* `'PATCH' - /api/v2/admin/reset-password-requests/{resetPasswordToken}`
New Routes:
* `'POST' - /api/v2/admin/reset-password`
* `'PATCH' - /api/v2/admin/reset-password/{resetPasswordToken}`
* The `getCurrentPrefix` method has been removed from the `Sylius\Bundle\ApiBundle\Provider\PathPrefixProviderInterface`.
* The `Sylius\Bundle\ApiBundle\Provider\PathPrefixProvider` constructor has been changed due to refactor.
Now, we provide the list of possible prefixes that we check in this service. This list can be set under
the parameter: `sylius.api_path_prefixes`.
```diff
public function __construct(
- private UserContextInterface $userContext,
private string $apiRoute,
+ private array $pathPrefixes,
) {
...
}
```

View file

@ -4,10 +4,39 @@
"static", "self", "parent",
"array", "string", "int", "float", "bool", "iterable", "callable", "void", "object", "mixed", "never",
"ApiPlatform\\Core\\Api\\FilterInterface",
"ApiPlatform\\Core\\Api\\IriConverterInterface",
"ApiPlatform\\Core\\Api\\OperationType",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Common\\Filter\\OrderFilterInterface",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\ContextAwareQueryCollectionExtensionInterface",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryItemExtensionInterface",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\QueryResultCollectionExtensionInterface",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Filter\\AbstractContextAwareFilter",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Util\\QueryNameGenerator",
"ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Util\\QueryNameGeneratorInterface",
"ApiPlatform\\Core\\Bridge\\Symfony\\Routing\\RouteNameResolverInterface",
"ApiPlatform\\Core\\Cache\\CachedTrait",
"ApiPlatform\\Core\\DataPersister\\ContextAwareDataPersisterInterface",
"ApiPlatform\\Core\\DataPersister\\ResumableDataPersisterInterface",
"ApiPlatform\\Core\\DataProvider\\ContextAwareCollectionDataProviderInterface",
"ApiPlatform\\Core\\DataProvider\\ItemDataProviderInterface",
"ApiPlatform\\Core\\DataProvider\\OperationDataProviderTrait",
"ApiPlatform\\Core\\DataProvider\\RestrictedDataProviderInterface",
"ApiPlatform\\Core\\DataProvider\\SubresourceDataProviderInterface",
"ApiPlatform\\Core\\DataTransformer\\DataTransformerInterface",
"ApiPlatform\\Core\\EventListener\\EventPriorities",
"ApiPlatform\\Core\\Exception\\InvalidArgumentException",
"ApiPlatform\\Core\\Exception\\InvalidIdentifierException",
"ApiPlatform\\Core\\Exception\\ItemNotFoundException",
"ApiPlatform\\Core\\Exception\\ResourceClassNotFoundException",
"ApiPlatform\\Core\\Identifier\\IdentifierConverterInterface",
"ApiPlatform\\Core\\Metadata\\Extractor\\ExtractorInterface",
"ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceNameCollectionFactoryInterface",
"ApiPlatform\\Core\\Metadata\\Extractor\\XmlExtractor",
"ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceMetadataFactoryInterface",
"ApiPlatform\\Core\\Metadata\\Resource\\ResourceMetadata",
"ApiPlatform\\Core\\OpenApi\\Model\\Parameter",
"ApiPlatform\\Core\\Serializer\\SerializerContextBuilderInterface",
"ApiPlatform\\Core\\Util\\AttributesExtractor",
"ApiPlatform\\Core\\Util\\RequestParser",
"Behat\\Behat\\Tester\\ScenarioTester",
"Behat\\Behat\\Tester\\ServiceContainer\\TesterExtension",
"Behat\\Gherkin\\Node\\FeatureNode",

View file

@ -30,7 +30,7 @@
"ext-intl": "*",
"ext-json": "*",
"ext-simplexml": "*",
"api-platform/core": "^2.7.10",
"api-platform/core": "^3.2.2",
"babdev/pagerfanta-bundle": "^3.0",
"behat/transliterator": "^1.3",
"doctrine/collections": "^1.6",
@ -93,7 +93,7 @@
"symfony/console": "^6.4.1",
"symfony/cache-contracts": "^2.5 || ^3.0",
"symfony/dependency-injection": "^6.4.1",
"symfony/deprecation-contracts": "^2.5.2",
"symfony/deprecation-contracts": "^3.1",
"symfony/doctrine-bridge": "^6.4.0",
"symfony/doctrine-messenger": "^6.4.1",
"symfony/event-dispatcher": "^6.4.0",
@ -128,7 +128,7 @@
"symfony/string": "^6.4.0",
"symfony/templating": "^6.4.0",
"symfony/translation": "^6.4.0",
"symfony/translation-contracts": "^2.5.2",
"symfony/translation-contracts": "^3.3",
"symfony/twig-bundle": "^6.4.0",
"symfony/validator": "^6.4.0",
"symfony/webpack-encore-bundle": "^1.17.1",
@ -187,7 +187,6 @@
"conflict": {
"api-platform/core": "2.7.17",
"doctrine/orm": ">= 2.16.0",
"lexik/jwt-authentication-bundle": "^2.18",
"stof/doctrine-extensions-bundle": "1.8.0",
"twig/twig": "3.9.0"
},
@ -277,6 +276,7 @@
"src/Sylius/*/*/Tests/",
"src/Sylius/Component/Core/Test/Tests/",
"src/Sylius/*/*/spec/",
"src/Sylius/*/*/disabledSpec/",
"src/Sylius/*/*/test/",
"src/Sylius/*/*/phparkitect.php"
]

View file

@ -47,7 +47,7 @@ return [
Sylius\Bundle\ThemeBundle\SyliusThemeBundle::class => ['all' => true],
Sylius\Bundle\AdminBundle\SyliusAdminBundle::class => ['all' => true],
Sylius\Bundle\ShopBundle\SyliusShopBundle::class => ['all' => true],
ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],

View file

@ -0,0 +1,158 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Sylius\Tests\Api\Admin;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Tests\Api\JsonApiTestCase;
use Sylius\Tests\Api\Utils\AdminUserLoginTrait;
use Symfony\Component\HttpFoundation\Response;
final class AdminUsersTest extends JsonApiTestCase
{
use AdminUserLoginTrait;
/** @test */
public function it_allows_admin_users_to_log_in(): void
{
$this->loadFixturesFromFile('authentication/api_administrator.yaml');
$this->client->request(
method: 'POST',
uri: '/api/v2/admin/administrators/token',
server: self::CONTENT_TYPE_HEADER,
content: json_encode([
'email' => 'api@example.com',
'password' => 'sylius',
], \JSON_THROW_ON_ERROR),
);
$response = $this->client->getResponse();
$this->assertResponse($response, 'admin/admin_user/log_in_admin_response', Response::HTTP_OK);
}
/** @test */
public function it_gets_administrators(): void
{
$this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'administrator.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
$this->client->request(method: 'GET', uri: '/api/v2/admin/administrators', server: $header);
$this->assertResponse(
$this->client->getResponse(),
'admin/admin_user/get_administrators_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_gets_an_administrator(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'administrator.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var AdminUserInterface $administrator */
$administrator = $fixtures['admin_user_wilhelm'];
$this->client->request(
method: 'GET',
uri: sprintf('/api/v2/admin/administrators/%s', $administrator->getId()),
server: $header,
);
$this->assertResponse(
$this->client->getResponse(),
'admin/admin_user/get_administrator_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_creates_an_administrator(): void
{
$this->loadFixturesFromFile('authentication/api_administrator.yaml');
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
$this->client->request(
method: 'POST',
uri: '/api/v2/admin/administrators',
server: $header,
content: json_encode([
'email' => 'j.api@test.com',
'username' => 'johnApi',
'plainPassword' => 'very-secure',
'enabled' => true,
'firstName' => 'John',
'lastName' => 'Api',
'localeCode' => 'ga_IE',
], \JSON_THROW_ON_ERROR),
);
$this->assertResponse(
$this->client->getResponse(),
'admin/admin_user/create_administrator_response',
Response::HTTP_CREATED,
);
}
/** @test */
public function it_updates_an_administrator(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'administrator.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var AdminUserInterface $administrator */
$administrator = $fixtures['admin_user_wilhelm'];
$this->client->request(
method: 'PUT',
uri: sprintf('/api/v2/admin/administrators/%s', $administrator->getId()),
server: $header,
content: json_encode([
'email' => 'j.api@test.com',
'username' => 'johnApi',
'plainPassword' => 'very-secure',
'enabled' => false,
'firstName' => 'John',
'lastName' => 'Api',
'localeCode' => 'ga_IE',
], \JSON_THROW_ON_ERROR),
);
$this->assertResponse(
$this->client->getResponse(),
'admin/admin_user/put_administrator_response',
Response::HTTP_OK,
);
}
/** @test */
public function it_deletes_an_administrator(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'administrator.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var AdminUserInterface $administrator */
$administrator = $fixtures['admin_user_wilhelm'];
$this->client->request(
method: 'DELETE',
uri: sprintf('/api/v2/admin/administrators/%s', $administrator->getId()),
server: $header,
);
$this->assertResponseCode($this->client->getResponse(), Response::HTTP_NO_CONTENT);
}
}

View file

@ -30,12 +30,12 @@ final class AvatarImageTest extends JsonApiTestCase
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'avatar_image.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var AvatarImageInterface $avatarImage */
$avatarImage = $fixtures['avatar_image'];
/** @var AdminUserInterface $adminUser */
$adminUser = $fixtures['admin'];
$this->client->request(
method: 'GET',
uri: sprintf('/api/v2/admin/avatar-images/%s', $avatarImage->getId()),
uri: sprintf('/api/v2/admin/administrators/%s/avatar-image', $adminUser->getId()),
server: $header,
);
@ -100,7 +100,7 @@ final class AvatarImageTest extends JsonApiTestCase
$this->client->request(
method: 'GET',
uri: sprintf('/api/v2/admin/avatar-images/%s', 'wrong input'),
uri: sprintf('/api/v2/admin/administrators/%s/avatar-image', 'wrong input'),
server: $header,
);
@ -120,10 +120,7 @@ final class AvatarImageTest extends JsonApiTestCase
$this->client->request(
method: 'POST',
uri: '/api/v2/admin/avatar-images',
parameters: [
'owner' => sprintf('/api/v2/admin/administrators/%s', $adminUser->getId()),
],
uri: sprintf('/api/v2/admin/administrators/%s/avatar-image', $adminUser->getId()),
files: ['file' => $this->getUploadedFile('fixtures/ford.jpg', 'ford.jpg')],
server: $header,
);
@ -142,12 +139,12 @@ final class AvatarImageTest extends JsonApiTestCase
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'avatar_image.yaml']);
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
/** @var AvatarImageInterface $avatarImage */
$avatarImage = $fixtures['avatar_image'];
/** @var AdminUserInterface $adminUser */
$adminUser = $fixtures['admin'];
$this->client->request(
method: 'DELETE',
uri: sprintf('/api/v2/admin/avatar-images/%s', $avatarImage->getId()),
uri: sprintf('/api/v2/admin/administrators/%s/avatar-image', $adminUser->getId()),
server: $header,
);

View file

@ -11,7 +11,7 @@
declare(strict_types=1);
namespace Api\Admin;
namespace Sylius\Tests\Api\Admin;
use Sylius\Component\Core\Model\PaymentMethodInterface;
use Sylius\Tests\Api\JsonApiTestCase;

View file

@ -11,7 +11,7 @@
declare(strict_types=1);
namespace Api\Admin;
namespace Sylius\Tests\Api\Admin;
use Sylius\Component\Product\Model\ProductAssociationInterface;
use Sylius\Tests\Api\JsonApiTestCase;

View file

@ -26,7 +26,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_gets_customer(): void
{
$fixtures = $this->loadFixturesFromFiles(['authentication/customer.yaml']);
$fixtures = $this->loadFixturesFromFiles(['authentication/shop_user.yaml']);
/** @var CustomerInterface $customer */
$customer = $fixtures['customer_oliver'];
@ -46,7 +46,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_logs_in(): void
{
$this->loadFixturesFromFiles(['authentication/customer.yaml']);
$this->loadFixturesFromFiles(['authentication/shop_user.yaml']);
$this->client->request(
method: 'POST',
@ -89,7 +89,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_updates_customers_data(): void
{
$loadedData = $this->loadFixturesFromFiles(['authentication/customer.yaml']);
$loadedData = $this->loadFixturesFromFiles(['authentication/shop_user.yaml']);
/** @var CustomerInterface $customer */
$customer = $loadedData['customer_oliver'];
@ -118,7 +118,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_sends_reset_password_email(): void
{
$loadedData = $this->loadFixturesFromFiles(['authentication/customer.yaml', 'channel.yaml']);
$loadedData = $this->loadFixturesFromFiles(['authentication/shop_user.yaml', 'channel.yaml']);
/** @var CustomerInterface $customer */
$customer = $loadedData['customer_oliver'];
@ -141,7 +141,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_validates_wrong_reset_password_request(): void
{
$this->loadFixturesFromFiles(['authentication/customer.yaml', 'channel.yaml']);
$this->loadFixturesFromFiles(['authentication/shop_user.yaml', 'channel.yaml']);
$this->client->request(
method: 'POST',
@ -161,7 +161,7 @@ final class CustomersTest extends JsonApiTestCase
/** @test */
public function it_resets_account_password(): void
{
$loadedData = $this->loadFixturesFromFiles(['authentication/customer.yaml', 'channel.yaml']);
$loadedData = $this->loadFixturesFromFiles(['authentication/shop_user.yaml', 'channel.yaml']);
/** @var ShopUserInterface $shopUser */
$shopUser = $loadedData['shop_user_oliver'];

View file

@ -11,7 +11,7 @@
declare(strict_types=1);
namespace Api\Shop;
namespace Sylius\Tests\Api\Shop;
use Sylius\Component\Addressing\Model\ProvinceInterface;
use Sylius\Tests\Api\JsonApiTestCase;

View file

@ -0,0 +1,107 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Sylius\Tests\Api\Shop;
use Sylius\Tests\Api\JsonApiTestCase;
use Sylius\Tests\Api\Utils\ShopUserLoginTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
final class ShopUsersTest extends JsonApiTestCase
{
use ShopUserLoginTrait;
/** @test */
public function it_sends_shop_user_password_reset_email(): void
{
$this->loadFixturesFromFiles(['channel.yaml', 'authentication/shop_user.yaml']);
$this->client->request(
method: Request::METHOD_POST,
uri: '/api/v2/shop/reset-password',
server: self::CONTENT_TYPE_HEADER,
content: json_encode([
'email' => 'api@example.com',
], JSON_THROW_ON_ERROR),
);
$response = $this->client->getResponse();
$this->assertResponseCode($response, Response::HTTP_ACCEPTED);
}
/** @test */
public function it_resets_shop_user_password_with_valid_token(): void
{
$this->loadFixturesFromFiles(['channel.yaml', 'authentication/shop_user_with_reset_password_token.yaml']);
$validToken = 'valid_token';
$this->client->request(
method: Request::METHOD_PATCH,
uri: sprintf('/api/v2/shop/reset-password/%s', $validToken),
server: self::CONTENT_TYPE_HEADER,
content: json_encode([
'newPassword' => 'newPassword',
'confirmNewPassword' => 'newPassword',
], JSON_THROW_ON_ERROR),
);
$response = $this->client->getResponse();
$this->assertResponseCode($response, Response::HTTP_ACCEPTED);
}
/** @test */
public function it_prevents_shop_user_from_resetting_password_with_invalid_token(): void
{
$this->loadFixturesFromFiles(['channel.yaml', 'authentication/shop_user_with_reset_password_token.yaml']);
$validToken = 'invalid_token';
$this->client->request(
method: Request::METHOD_PATCH,
uri: sprintf('/api/v2/shop/reset-password/%s', $validToken),
server: self::CONTENT_TYPE_HEADER,
content: json_encode([
'newPassword' => 'newPassword',
'confirmNewPassword' => 'newPassword',
], JSON_THROW_ON_ERROR),
);
$response = $this->client->getResponse();
$this->assertResponseCode($response, Response::HTTP_UNPROCESSABLE_ENTITY);
}
/** @test */
public function it_prevents_shop_user_from_resetting_password_with_expired_token(): void
{
$this->loadFixturesFromFiles(['channel.yaml', 'authentication/shop_user_with_expired_reset_password_token.yaml']);
$validToken = 'valid_token';
$this->client->request(
method: Request::METHOD_PATCH,
uri: sprintf('/api/v2/shop/reset-password/%s', $validToken),
server: self::CONTENT_TYPE_HEADER,
content: json_encode([
'newPassword' => 'newPassword',
'confirmNewPassword' => 'newPassword',
], JSON_THROW_ON_ERROR),
);
$response = $this->client->getResponse();
$this->assertResponseCode($response, Response::HTTP_UNPROCESSABLE_ENTITY);
}
}

View file

@ -10,7 +10,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
And the store operates in "United States" and "Poland"
And I am logged in as an administrator
@api @ui
@todo @api @ui
Scenario: Adding a new channel without specifying the lowest price for discounted products checking period
When I want to create a new channel
And I specify its code as "MOBILE"
@ -23,7 +23,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
Then I should be notified that it has been successfully created
And the "Mobile" channel should have the lowest price for discounted products checking period set to 30 days
@api @ui
@todo @api @ui
Scenario: Adding a new channel with a specified lowest price for discounted products checking period
When I want to create a new channel
And I specify its code as "MOBILE"
@ -37,7 +37,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
Then I should be notified that it has been successfully created
And the "Mobile" channel should have the lowest price for discounted products checking period set to 15 days
@api @ui
@todo @api @ui
Scenario: Being prevented from creating a new channel with the lowest price for discounted products checking period equal to zero
When I want to create a new channel
And I specify its code as "MOBILE"
@ -50,7 +50,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
And I try to add it
Then I should be notified that the lowest price for discounted products checking period must be greater than 0
@api @ui
@todo @api @ui
Scenario: Being prevented from creating a new channel with a negative lowest price for discounted products checking period
When I want to create a new channel
And I specify its code as "MOBILE"
@ -64,7 +64,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
And I try to add it
Then I should be notified that the lowest price for discounted products checking period must be greater than 0
@api @ui
@todo @api @ui
Scenario: Being prevented from creating a new channel with a too big lowest price for discounted products checking period
When I want to create a new channel
And I specify its code as "MOBILE"

View file

@ -10,7 +10,7 @@ Feature: Choosing whether to show the lowest product price or not while creating
And the store operates in "United States" and "Poland"
And I am logged in as an administrator
@api @ui
@todo @api @ui
Scenario: Adding a new channel with lowest price before the product has been discounted enabled by default
When I want to create a new channel
And I specify its code as "MOBILE"
@ -23,7 +23,7 @@ Feature: Choosing whether to show the lowest product price or not while creating
Then I should be notified that it has been successfully created
And the "Mobile" channel should have the lowest price of discounted products prior to the current discount enabled
@api @ui
@todo @api @ui
Scenario: Adding a new channel with lowest price before the product has been discounted enabled
When I want to create a new channel
And I specify its code as "MOBILE"
@ -37,7 +37,7 @@ Feature: Choosing whether to show the lowest product price or not while creating
Then I should be notified that it has been successfully created
And the "Mobile" channel should have the lowest price of discounted products prior to the current discount enabled
@api @ui
@todo @api @ui
Scenario: Adding a new channel with lowest price before the product has been discounted disabled
When I want to create a new channel
And I specify its code as "MOBILE"

View file

@ -11,7 +11,7 @@ Feature: Adding a new channel with menu taxon
And the store classifies its products as "Clothes" and "Guns"
And I am logged in as an administrator
@ui @javascript @api
@todo @ui @javascript @api
Scenario: Adding a new channel with menu taxon
When I want to create a new channel
And I specify its code as "MOBILE"

View file

@ -38,7 +38,7 @@ Feature: Specifying the lowest price for discounted products checking period whi
And I try to save my changes
Then I should be notified that the lowest price for discounted products checking period must be lower
@api @no-ui
@todo @api @no-ui
Scenario: Changing the lowest price for discounted products checking period
When I want to modify the price history config of channel "EU"
And I change the lowest price for discounted products checking period to 30 days
@ -46,21 +46,21 @@ Feature: Specifying the lowest price for discounted products checking period whi
Then I should be notified that it has been successfully edited
And its lowest price for discounted products checking period should be set to 30 days
@api @no-ui
@todo @api @no-ui
Scenario: Being prevented from changing the lowest price for discounted products checking period to zero
When I want to modify the price history config of channel "EU"
And I change the lowest price for discounted products checking period to 0 days
And I try to save my changes
Then I should be notified that the lowest price for discounted products checking period must be greater than 0
@api @no-ui
@todo @api @no-ui
Scenario: Being prevented from changing the lowest price for discounted products checking period to a negative value
When I want to modify the price history config of channel "EU"
And I change the lowest price for discounted products checking period to -10 days
And I try to save my changes
Then I should be notified that the lowest price for discounted products checking period must be greater than 0
@api @no-ui
@todo @api @no-ui
Scenario: Being prevented from changing the lowest price for discounted products checking period to a too big value
When I want to modify the price history config of channel "EU"
And I change the lowest price for discounted products checking period to 99999999999 days

View file

@ -27,7 +27,7 @@ Feature: Choosing whether to show the lowest product price or not while editing
Then I should be notified that it has been successfully edited
And the "EU Channel" channel should have the lowest price of discounted products prior to the current discount disabled
@api @no-ui
@todo @api @no-ui
Scenario: Enabling showing the lowest price of discounted products on a channel
When I want to modify the price history config of channel "US Channel"
And I change showing of the lowest price of discounted products to be enabled
@ -35,7 +35,7 @@ Feature: Choosing whether to show the lowest product price or not while editing
Then I should be notified that it has been successfully edited
And the "US Channel" channel should have the lowest price of discounted products prior to the current discount enabled
@api @no-ui
@todo @api @no-ui
Scenario: Disabling showing the lowest price of discounted products on a channel
When I want to modify the price history config of channel "EU Channel"
And I change showing of the lowest price of discounted products to be disabled

View file

@ -11,7 +11,7 @@ Feature: Editing menu taxon on channel
And channel "Web Store" has menu taxon "Clothes"
And I am logged in as an administrator
@api @ui @javascript
@todo @api @ui @javascript
Scenario: Editing menu taxon on the channel
When I want to modify a channel "Web Store"
And I change its menu taxon to "Guns"

View file

@ -35,7 +35,7 @@ Feature: Excluding chosen taxons from displaying the lowest price of discounted
And this channel should have "Caps" taxon excluded from displaying the lowest price of discounted products
And this channel should not have "T-Shirts" taxon excluded from displaying the lowest price of discounted products
@api @no-ui
@todo @api @no-ui
Scenario: Excluding a singular taxon from displaying the lowest price of discounted products
When I want to modify the price history config of channel "Poland"
And I exclude the "T-Shirts" taxon from showing the lowest price of discounted products
@ -43,7 +43,7 @@ Feature: Excluding chosen taxons from displaying the lowest price of discounted
Then I should be notified that it has been successfully edited
And this channel should have "T-Shirts" taxon excluded from displaying the lowest price of discounted products
@api @no-ui
@todo @api @no-ui
Scenario: Excluding multiple taxons from displaying the lowest price of discounted products
When I want to modify the price history config of channel "Poland"
And I exclude the "T-Shirts" and "Caps" taxons from showing the lowest price of discounted products

View file

@ -8,7 +8,7 @@ Feature: Selecting default tax zone for a channel
Given the store operates on a single channel in "United States"
And I am logged in as an administrator
@api @ui
@todo @api @ui
Scenario: Adding a new channel with default tax zone
When I want to create a new channel
And I specify its code as "MOBILE"
@ -22,7 +22,7 @@ Feature: Selecting default tax zone for a channel
Then I should be notified that it has been successfully created
And the default tax zone for the "Mobile store" channel should be "United States"
@api @ui
@todo @api @ui
Scenario: Selecting default tax zone for existing channel
Given the store operates on a channel named "Web store"
When I want to modify this channel
@ -31,7 +31,7 @@ Feature: Selecting default tax zone for a channel
Then I should be notified that it has been successfully edited
And the default tax zone for the "Web store" channel should be "United States"
@api @ui
@todo @api @ui
Scenario: Removing existing channel default tax zone
Given the store operates on a channel named "Web store"
And its default tax zone is zone "US"

View file

@ -7,7 +7,7 @@ Feature: Adding an avatar to an administrator
Background:
Given I am logged in as an administrator
@ui @api
@ui @api @avatar # temporarily enabled to test only the avatar
Scenario: Adding an avatar to administrator account
Given I am editing my details
When I upload the "troll.jpg" image as my avatar

View file

@ -7,7 +7,7 @@ Feature: Changing an administrator's avatar
Background:
Given I am logged in as an administrator
@ui @api
@ui @api @avatar # temporarily enabled to test only the avatar
Scenario: Changing an avatar of an administrator
Given I have the "ford.jpg" image as my avatar
And I am editing my details

View file

@ -8,7 +8,7 @@ Feature: Removing an administrator avatar
Given I am logged in as an administrator
And this administrator has the "troll.jpg" image as avatar
@ui @api
@ui @api @avatar # temporarily enabled to test only the avatar
Scenario: Removing an administrator avatar
Given I am editing my details
When I remove the avatar

View file

@ -16,7 +16,7 @@ Feature: Changing a customer password
And I save my changes
Then I should be notified that my password has been successfully changed
@api @ui
@todo @api @ui
Scenario: Logging to store after password change
Given I've changed my password from "whitehouse" to "blackhouse"
When I log in as "francis@underwood.com" with "blackhouse" password

View file

@ -11,7 +11,7 @@ Feature: Filtering out disabled channels
And there is product "Old Wardrobe" available in "Furniture" channel
And the channel "Fashion" is disabled
@ui @api
@todo @ui @api
Scenario: Seeing Furniture shop products
When I browse the "Furniture" channel
And I check latest products

View file

@ -8,7 +8,7 @@ Feature: Requesting contact
Given the store operates on a single channel in "United States"
And this channel has contact email set as "contact@goodshop.com"
@ui @api @email
@ui @email #api
Scenario: Requesting contact as a logged in customer
Given there is a user "lucifer@morningstar.com"
And I am logged in as "lucifer@morningstar.com"

View file

@ -33,6 +33,10 @@ parameters:
# To investigate, occurs after release of doctrine/orm 2.14, the processing of these classes ends with exit code 143
- 'src/Sylius/Bundle/CoreBundle/Doctrine/DQL/**.php'
- 'src/Sylius/Bundle/CoreBundle/Doctrine/ORM/SqlWalker/**.php'
# Temporary exclusion during upgrade to API Platform 3
- 'src/Sylius/Bundle/ApiBundle/**.php'
ignoreErrors:
- '/(Interface|Class) [a-zA-Z\\]+ specifies template type (\w+) of interface [a-zA-Z\\]+ as [a-zA-Z\\]+ (of [a-zA-Z\\]+ )?but it''s already specified as/' # turns off a weird generics check behavior, we are basing on Psalm for generics checks
- '/Access to an undefined property Doctrine\\Common\\Collections\\ArrayCollection/'

View file

@ -13,11 +13,9 @@ declare(strict_types=1);
namespace Sylius\Behat\Context\Api\Admin;
use ApiPlatform\Api\IriConverterInterface;
use Behat\Behat\Context\Context;
use Sylius\Behat\Client\ApiClientInterface;
use Sylius\Behat\Client\RequestBuilder;
use Sylius\Behat\Client\RequestFactoryInterface;
use Sylius\Behat\Client\ResponseCheckerInterface;
use Sylius\Behat\Context\Api\Resources;
use Sylius\Behat\Service\SharedStorageInterface;
@ -32,10 +30,8 @@ final class ManagingAdministratorsContext implements Context
public function __construct(
private ApiClientInterface $client,
private ResponseCheckerInterface $responseChecker,
private IriConverterInterface $iriConverter,
private SharedStorageInterface $sharedStorage,
private \ArrayAccess $minkParameters,
private RequestFactoryInterface $requestFactory,
) {
}
@ -157,13 +153,12 @@ final class ManagingAdministratorsContext implements Context
public function iUploadTheImageAsMyAvatar(string $avatar, AdminUserInterface $administrator): void
{
$builder = RequestBuilder::create(
sprintf('/api/v2/%s/%s', 'admin', Resources::AVATAR_IMAGES),
sprintf('/api/v2/admin/%s/%s/%s', Resources::ADMINISTRATORS, $administrator->getId(), Resources::AVATAR_IMAGE),
Request::METHOD_POST,
);
$builder->withHeader('CONTENT_TYPE', 'multipart/form-data');
$builder->withHeader('HTTP_ACCEPT', 'application/ld+json');
$builder->withHeader('HTTP_Authorization', 'Bearer ' . $this->sharedStorage->get('token'));
$builder->withParameter('owner', $this->iriConverter->getIriFromResource($administrator));
$builder->withFile('file', new UploadedFile($this->minkParameters['files_path'] . $avatar, basename($avatar)));
$response = $this->client->request($builder->build());
@ -181,7 +176,10 @@ final class ManagingAdministratorsContext implements Context
$avatar = $administrator->getAvatar();
Assert::notNull($avatar);
$this->client->delete(Resources::AVATAR_IMAGES, (string) $avatar->getId());
$this->client->customAction(
sprintf('/api/v2/admin/administrators/%s/%s', $administrator->getId(), Resources::AVATAR_IMAGE),
Request::METHOD_DELETE,
);
}
/**

View file

@ -13,13 +13,12 @@ declare(strict_types=1);
namespace Sylius\Behat\Context\Api\Admin;
use ApiPlatform\Api\IriConverterInterface;
use Behat\Behat\Context\Context;
use Sylius\Behat\Client\ApiClientInterface;
use Sylius\Behat\Client\ResponseCheckerInterface;
use Sylius\Behat\Context\Api\Admin\Helper\ValidationTrait;
use Sylius\Behat\Context\Api\Resources;
use Sylius\Behat\Service\Converter\SectionAwareIriConverterInterface;
use Sylius\Behat\Service\Converter\IriConverterInterface;
use Sylius\Behat\Service\SharedStorageInterface;
use Sylius\Bundle\CoreBundle\CatalogPromotion\Calculator\FixedDiscountPriceCalculator;
use Sylius\Bundle\CoreBundle\CatalogPromotion\Calculator\PercentageDiscountPriceCalculator;
@ -34,7 +33,7 @@ use Sylius\Component\Core\Model\ProductVariantInterface;
use Sylius\Component\Core\Model\TaxonInterface;
use Webmozart\Assert\Assert;
final class ManagingCatalogPromotionsContext implements Context
final readonly class ManagingCatalogPromotionsContext implements Context
{
use ValidationTrait;
@ -42,7 +41,6 @@ final class ManagingCatalogPromotionsContext implements Context
private ApiClientInterface $client,
private ResponseCheckerInterface $responseChecker,
private IriConverterInterface $iriConverter,
private SectionAwareIriConverterInterface $sectionAwareIriConverter,
private SharedStorageInterface $sharedStorage,
) {
}
@ -146,7 +144,7 @@ final class ManagingCatalogPromotionsContext implements Context
*/
public function iMakeItAvailableInChannel(ChannelInterface $channel): void
{
$this->client->addRequestData('channels', [$this->sectionAwareIriConverter->getIriFromResourceInSection($channel, 'admin')]);
$this->client->addRequestData('channels', [$this->iriConverter->getIriFromResourceInSection($channel, 'admin')]);
}
/**
@ -156,7 +154,7 @@ final class ManagingCatalogPromotionsContext implements Context
{
$channels = $this->responseChecker->getValue($this->client->show(Resources::CATALOG_PROMOTIONS, $catalogPromotion->getCode()), 'channels');
foreach (array_keys($channels, $this->sectionAwareIriConverter->getIriFromResourceInSection($channel, 'admin')) as $key) {
foreach (array_keys($channels, $this->iriConverter->getIriFromResourceInSection($channel, 'admin')) as $key) {
unset($channels[$key]);
}
@ -1175,7 +1173,7 @@ final class ManagingCatalogPromotionsContext implements Context
$this->responseChecker->hasValueInCollection(
$this->client->show(Resources::CATALOG_PROMOTIONS, $catalogPromotion->getCode()),
'channels',
$this->sectionAwareIriConverter->getIriFromResourceInSection($channel, 'admin'),
$this->iriConverter->getIriFromResourceInSection($channel, 'admin'),
),
sprintf('Catalog promotion is not assigned to %s channel', $channel->getName()),
);
@ -1194,7 +1192,7 @@ final class ManagingCatalogPromotionsContext implements Context
$this->responseChecker->hasValueInCollection(
$this->client->show(Resources::CATALOG_PROMOTIONS, $catalogPromotion->getCode()),
'channels',
$this->sectionAwareIriConverter->getIriFromResourceInSection($channel, 'admin'),
$this->iriConverter->getIriFromResourceInSection($channel, 'admin'),
),
sprintf('Catalog promotion is assigned to %s channel', $channel->getName()),
);

View file

@ -13,13 +13,12 @@ declare(strict_types=1);
namespace Sylius\Behat\Context\Api\Admin;
use ApiPlatform\Api\IriConverterInterface;
use Behat\Behat\Context\Context;
use Sylius\Behat\Client\ApiClientInterface;
use Sylius\Behat\Client\ResponseCheckerInterface;
use Sylius\Behat\Context\Api\Admin\Helper\ValidationTrait;
use Sylius\Behat\Context\Api\Resources;
use Sylius\Behat\Service\Converter\SectionAwareIriConverterInterface;
use Sylius\Behat\Service\Converter\IriConverterInterface;
use Sylius\Component\Addressing\Model\CountryInterface;
use Sylius\Component\Addressing\Model\ZoneInterface;
use Sylius\Component\Core\Formatter\StringInflector;
@ -39,7 +38,6 @@ final class ManagingChannelsContext implements Context
private ApiClientInterface $client,
private ResponseCheckerInterface $responseChecker,
private IriConverterInterface $iriConverter,
private SectionAwareIriConverterInterface $sectionAwareIriConverter,
) {
}
@ -90,7 +88,7 @@ final class ManagingChannelsContext implements Context
*/
public function iChangeItsMenuTaxonTo(TaxonInterface $taxon): void
{
$this->client->addRequestData('menuTaxon', $this->sectionAwareIriConverter->getIriFromResourceInSection($taxon, 'admin'));
$this->client->addRequestData('menuTaxon', $this->iriConverter->getIriFromResourceInSection($taxon, 'admin'));
}
/**
@ -113,7 +111,7 @@ final class ManagingChannelsContext implements Context
{
$this->client->addRequestData(
'baseCurrency',
null === $currency ? $currency : $this->sectionAwareIriConverter->getIriFromResourceInSection($currency, 'admin'),
null === $currency ? $currency : $this->iriConverter->getIriFromResourceInSection($currency, 'admin'),
);
}
@ -146,7 +144,7 @@ final class ManagingChannelsContext implements Context
*/
public function iMakeItAvailableInLocale(LocaleInterface $locale): void
{
$this->client->addRequestData('locales', [$this->sectionAwareIriConverter->getIriFromResourceInSection($locale, 'admin')]);
$this->client->addRequestData('locales', [$this->iriConverter->getIriFromResourceInSection($locale, 'admin')]);
}
/**
@ -154,7 +152,7 @@ final class ManagingChannelsContext implements Context
*/
public function iMakeItAvailableOnlyInLocale(LocaleInterface $locale): void
{
$this->client->replaceRequestData('locales', [$this->sectionAwareIriConverter->getIriFromResourceInSection($locale, 'admin')]);
$this->client->replaceRequestData('locales', [$this->iriConverter->getIriFromResourceInSection($locale, 'admin')]);
}
/**
@ -165,7 +163,7 @@ final class ManagingChannelsContext implements Context
{
$this->client->addRequestData(
'defaultLocale',
null === $locale ? $locale : $this->sectionAwareIriConverter->getIriFromResourceInSection($locale, 'admin'),
null === $locale ? $locale : $this->iriConverter->getIriFromResourceInSection($locale, 'admin'),
);
}
@ -199,8 +197,8 @@ final class ManagingChannelsContext implements Context
public function iChooseAndAsOperatingCountries(CountryInterface $country, CountryInterface $otherCountry): void
{
$this->client->addRequestData('countries', [
$this->sectionAwareIriConverter->getIriFromResourceInSection($country, 'admin'),
$this->sectionAwareIriConverter->getIriFromResourceInSection($otherCountry, 'admin'),
$this->iriConverter->getIriFromResourceInSection($country, 'admin'),
$this->iriConverter->getIriFromResourceInSection($otherCountry, 'admin'),
]);
}
@ -225,7 +223,7 @@ final class ManagingChannelsContext implements Context
*/
public function iSpecifyMenuTaxonAs(TaxonInterface $taxon): void
{
$this->client->addRequestData('menuTaxon', $this->sectionAwareIriConverter->getIriFromResourceInSection($taxon, 'admin'));
$this->client->addRequestData('menuTaxon', $this->iriConverter->getIriFromResourceInSection($taxon, 'admin'));
}
/**
@ -409,7 +407,7 @@ final class ManagingChannelsContext implements Context
{
Assert::same(
$this->responseChecker->getValue($this->client->show(Resources::CHANNELS, $channel->getCode()), 'menuTaxon'),
$this->sectionAwareIriConverter->getIriFromResourceInSection($taxon, 'admin'),
$this->iriConverter->getIriFromResourceInSection($taxon, 'admin'),
sprintf('Channel %s does not have %s menu taxon', $channel->getName(), $taxon->getName()),
);
}
@ -477,7 +475,7 @@ final class ManagingChannelsContext implements Context
$channel->getCode(),
),
'menuTaxon',
$this->sectionAwareIriConverter->getIriFromResourceInSection($taxon, 'admin'),
$this->iriConverter->getIriFromResourceInSection($taxon, 'admin'),
),
);
}
@ -557,7 +555,7 @@ final class ManagingChannelsContext implements Context
'currencies',
);
Assert::true(in_array($this->sectionAwareIriConverter->getIriFromResourceInSection($currency, 'admin'), $currencies));
Assert::true(in_array($this->iriConverter->getIriFromResourceInSection($currency, 'admin'), $currencies));
}
/**
@ -579,7 +577,7 @@ final class ManagingChannelsContext implements Context
{
Assert::same(
$this->responseChecker->getValue($this->client->show(Resources::CHANNELS, $channel->getCode()), 'defaultTaxZone'),
$this->sectionAwareIriConverter->getIriFromResourceInSection($zone, 'admin'),
$this->iriConverter->getIriFromResourceInSection($zone, 'admin'),
sprintf('Channel %s does not have %s default tax zone', $channel->getName(), $zone),
);
}
@ -594,7 +592,7 @@ final class ManagingChannelsContext implements Context
'locales',
);
Assert::true(in_array($this->sectionAwareIriConverter->getIriFromResourceInSection($locale, 'admin'), $locales));
Assert::true(in_array($this->iriConverter->getIriFromResourceInSection($locale, 'admin'), $locales));
}
/**
@ -652,7 +650,7 @@ final class ManagingChannelsContext implements Context
{
Assert::contains(
$this->responseChecker->getError($this->client->getLastResponse()),
sprintf('%s: Please enter channel %s.', $element, $element),
sprintf('%s: Please enter channel %s.', StringInflector::nameToCamelCase($element), $element),
);
}
@ -663,7 +661,7 @@ final class ManagingChannelsContext implements Context
{
Assert::contains(
$this->responseChecker->getError($this->client->getLastResponse()),
'Expected IRI or nested document for attribute "baseCurrency", "NULL" given.',
'The type of the "baseCurrency" attribute must be "array" (nested document) or "string" (IRI), "NULL" given.',
);
}
@ -674,7 +672,7 @@ final class ManagingChannelsContext implements Context
{
Assert::contains(
$this->responseChecker->getError($this->client->getLastResponse()),
'Expected IRI or nested document for attribute "defaultLocale", "NULL" given.',
'The type of the "defaultLocale" attribute must be "array" (nested document) or "string" (IRI), "NULL" given.',
);
}

View file

@ -153,12 +153,12 @@ final class ManagingCountriesContext implements Context
*/
public function iDeleteTheProvinceOfThisCountry(ProvinceInterface $province, CountryInterface $country): void
{
$iri = $this->iriConverter->getItemIriFromResourceClass($province::class, ['code' => $province->getCode()]);
$iri = $this->iriConverter->getIriFromResource($province);
$provinces = $this->responseChecker->getValue($this->client->show(Resources::COUNTRIES, $country->getCode()), 'provinces');
foreach ($provinces as $countryProvince) {
if ($iri === $countryProvince) {
$this->client->removeSubResource('provinces', $countryProvince);
foreach ($provinces as $provinceIri) {
if ($iri === $provinceIri) {
$this->client->removeSubResource('provinces', $provinceIri);
}
}
}

Some files were not shown because too many files have changed in this diff Show more