diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2cbc9610..13962afe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,8 +8,7 @@ on: release: types: [created] schedule: - - - cron: "0 1 * * 6" # Run at 1am every Saturday + - cron: "0 1 * * 6" # Run at 1am every Saturday workflow_dispatch: ~ jobs: @@ -23,14 +22,16 @@ jobs: matrix: php: [ "8.0", "8.1", "8.2", "8.3" ] symfony: [ "^5.4", "^6.4" ] - sylius: [ "~1.12.0", "~1.13.0" ] - node: [ "^18.0", "^20.0" ] + sylius: [ "^1.12", "^1.13" ] + node: [ "18.x", "20.x" ] mysql: [ "8.0" ] + exclude: - - sylius: "~1.13.0" - php: "8.0" - - symfony: "^6.4" - php: "8.0" + - sylius: ^1.13 + php: 8.0 + - sylius: ^1.12 + php: 8.0 + symfony: ^6.4 env: APP_ENV: test @@ -95,7 +96,6 @@ jobs: key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }} restore-keys: | ${{ runner.os }}-php-${{ matrix.php }}-composer- - - name: Restrict Symfony version if: matrix.symfony != '' @@ -103,30 +103,30 @@ jobs: composer global config --no-plugins allow-plugins.symfony/flex true composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10" composer config extra.symfony.require "${{ matrix.symfony }}" - - - name: Restrcting Sylius version + name: Restrict Sylius version if: matrix.sylius != '' run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction - name: Install PHP dependencies run: composer install --no-interaction + env: + SYMFONY_REQUIRE: ${{ matrix.symfony }} - name: Get Yarn cache directory id: yarn-cache - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + run: echo "::set-output name=dir::$(yarn cache dir)" - name: Cache Yarn - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.yarn-cache.outputs.dir }} key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }} restore-keys: | ${{ runner.os }}-node-${{ matrix.node }}-yarn- - - name: Install JS dependencies run: (cd tests/Application && yarn install) @@ -136,13 +136,11 @@ jobs: run: | (cd tests/Application && bin/console doctrine:database:create -vvv) (cd tests/Application && bin/console doctrine:schema:create -vvv) - - name: Prepare test application assets run: | (cd tests/Application && bin/console assets:install public -vvv) (cd tests/Application && yarn encore dev) - - name: Prepare test application cache run: (cd tests/Application && bin/console cache:warmup -vvv) @@ -159,18 +157,6 @@ jobs: name: Validate database schema run: (cd tests/Application && bin/console doctrine:schema:validate) - - - name: Run PHPStan - run: vendor/bin/phpstan analyse -c phpstan.neon -l 6 src/ - - - - name: Run ECS - run: vendor/bin/ecs check src - - - - name: Run Psalm - run: vendor/bin/psalm - - name: Run PHPSpec run: vendor/bin/phpspec run --ansi -f progress --no-interaction diff --git a/.github/workflows/coding_standard.yml b/.github/workflows/coding_standard.yml new file mode 100644 index 00000000..eb9c8e98 --- /dev/null +++ b/.github/workflows/coding_standard.yml @@ -0,0 +1,88 @@ +name: Coding standard + +on: + push: + branches-ignore: + - 'dependabot/**' + pull_request: ~ + release: + types: [ created ] + workflow_dispatch: ~ + +jobs: + tests: + runs-on: ubuntu-latest + + name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}" + + strategy: + fail-fast: false + matrix: + php: [ "8.0", "8.1", "8.2", "8.3" ] + symfony: [ "^5.4", "^6.4" ] + sylius: [ "^1.12", "^1.13" ] + node: [ "18.x", "20.x" ] + + exclude: + - sylius: ^1.13 + php: 8.0 + - sylius: ^1.12 + php: 8.0 + symfony: ^6.4 + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + extensions: intl + tools: symfony + coverage: none + + - name: Get Composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json', '**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php-${{ matrix.php }}-composer- + + - name: Restrict Symfony version + if: matrix.symfony != '' + run: | + composer global config --no-plugins allow-plugins.symfony/flex true + composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10" + composer config extra.symfony.require "${{ matrix.symfony }}" + + - name: Restrict Sylius version + if: matrix.sylius != '' + run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction + + - name: Install PHP dependencies + run: composer install --no-interaction + env: + SYMFONY_REQUIRE: ${{ matrix.symfony }} + + - name: Run PHPStan + run: vendor/bin/phpstan analyse -c phpstan.neon -l 8 src/ + + - name: Run ECS + run: vendor/bin/ecs check src + + - name: Failed build Slack notification + uses: rtCamp/action-slack-notify@v2 + if: ${{ failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') }} + env: + SLACK_CHANNEL: ${{ secrets.FAILED_BUILD_SLACK_CHANNEL }} + SLACK_COLOR: ${{ job.status }} + SLACK_ICON: https://github.com/rtCamp.png?size=48 + SLACK_MESSAGE: ':x:' + SLACK_TITLE: Failed build on ${{ github.event.repository.name }} repository + SLACK_USERNAME: ${{ secrets.FAILED_BUILD_SLACK_USERNAME }} + SLACK_WEBHOOK: ${{ secrets.FAILED_BUILD_SLACK_WEBHOOK }} diff --git a/composer.json b/composer.json index 1883aabf..b6cb588d 100644 --- a/composer.json +++ b/composer.json @@ -46,9 +46,7 @@ "symfony/dotenv": "^5.4 || ^6.0", "symfony/intl": "^5.4 || ^6.0", "symfony/web-profiler-bundle": "^5.4 || ^6.0", - "symplify/easy-coding-standard": "^10.0 || ^11.0", - "vimeo/psalm": "~4.12 || ^5.0.0", - "psalm/plugin-symfony": "~4.0 || ~5.0" + "symplify/easy-coding-standard": "^10.0 || ^11.0" }, "config": { "sort-packages": true, diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index 27b16bf4..00000000 --- a/psalm.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/src/Bus/Handler/GetTokenHandler.php b/src/Bus/Handler/GetTokenHandler.php index 76deaabe..ed6e021e 100644 --- a/src/Bus/Handler/GetTokenHandler.php +++ b/src/Bus/Handler/GetTokenHandler.php @@ -58,10 +58,6 @@ private function getUser(): ?UserInterface return $user instanceof UserInterface ? $user : null; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - */ public function __invoke(GetToken $getTokenQuery): ?AdyenTokenInterface { if (null === $this->getUser()) { diff --git a/src/Bus/Handler/PaymentStatusReceivedHandler.php b/src/Bus/Handler/PaymentStatusReceivedHandler.php index f336e9ba..39273685 100644 --- a/src/Bus/Handler/PaymentStatusReceivedHandler.php +++ b/src/Bus/Handler/PaymentStatusReceivedHandler.php @@ -101,17 +101,9 @@ private function updateOrderState(OrderInterface $order): void // This is necessary because in Sylius 1.11 namespace of SendOrderConfirmation has been changed if (null !== $token) { - /** - * @psalm-suppress MixedArgument - * @psalm-suppress UndefinedClass - */ if (class_exists('\Sylius\Bundle\ApiBundle\Command\SendOrderConfirmation')) { $this->commandBus->dispatch(new \Sylius\Bundle\ApiBundle\Command\SendOrderConfirmation($token)); } elseif (class_exists('\Sylius\Bundle\ApiBundle\Command\Checkout\SendOrderConfirmation')) { - /** - * @psalm-suppress MixedArgument - * @psalm-suppress UndefinedClass - */ $this->commandBus->dispatch(new \Sylius\Bundle\ApiBundle\Command\Checkout\SendOrderConfirmation($token)); } } diff --git a/src/Controller/Shop/AdyenDetailsAction.php b/src/Controller/Shop/AdyenDetailsAction.php index 6f775a0d..6b0709ea 100644 --- a/src/Controller/Shop/AdyenDetailsAction.php +++ b/src/Controller/Shop/AdyenDetailsAction.php @@ -31,6 +31,7 @@ public function __construct( public function __invoke(Request $request, string $code): Response { + /** @var string|null $referenceId */ $referenceId = $request->query->get(self::REFERENCE_ID_KEY); if (null === $referenceId) { diff --git a/src/Controller/Shop/PaymentsAction.php b/src/Controller/Shop/PaymentsAction.php index 0a87d6d3..d6291237 100644 --- a/src/Controller/Shop/PaymentsAction.php +++ b/src/Controller/Shop/PaymentsAction.php @@ -82,9 +82,6 @@ private function prepareTargetUrl(OrderInterface $order): string private function prepareOrder(Request $request, OrderInterface $order): void { - /** - * @psalm-suppress InternalMethod - */ if (null === $request->get('tokenValue')) { $request->getSession()->set(self::ORDER_ID_KEY, $order->getId()); } diff --git a/src/Controller/Shop/ProcessNotificationsAction.php b/src/Controller/Shop/ProcessNotificationsAction.php index 58105d54..e2cd8a52 100644 --- a/src/Controller/Shop/ProcessNotificationsAction.php +++ b/src/Controller/Shop/ProcessNotificationsAction.php @@ -50,7 +50,7 @@ public function __construct( public function __invoke(string $code, Request $request): Response { foreach ($this->notificationResolver->resolve($code, $request) as $notificationItem) { - if (!$notificationItem->success) { + if (null === $notificationItem || false === $notificationItem->success) { $this->logger->error(\sprintf( 'Payment with pspReference [%s] did not return success', $notificationItem->pspReference ?? '', diff --git a/src/Entity/Log.php b/src/Entity/Log.php index 2e3ea08f..a9ea8cd2 100644 --- a/src/Entity/Log.php +++ b/src/Entity/Log.php @@ -11,7 +11,6 @@ namespace BitBag\SyliusAdyenPlugin\Entity; -/** @psalm-suppress MissingConstructor */ class Log implements LogInterface { /** @var int */ diff --git a/src/Form/Type/CredentialType.php b/src/Form/Type/CredentialType.php index 74b442ae..83762ecd 100644 --- a/src/Form/Type/CredentialType.php +++ b/src/Form/Type/CredentialType.php @@ -31,7 +31,6 @@ public function buildView( return; } - /** @psalm-suppress InvalidPropertyAssignmentValue */ $view->vars['value'] = self::CREDENTIAL_PLACEHOLDER; } diff --git a/src/Grid/Filter/LoggerLevel.php b/src/Grid/Filter/LoggerLevel.php index fd98da19..37fe93a0 100644 --- a/src/Grid/Filter/LoggerLevel.php +++ b/src/Grid/Filter/LoggerLevel.php @@ -22,7 +22,6 @@ public function apply( $data, array $options, ): void { - /** @psalm-suppress MixedArrayAccess */ $dataSource->restrict($dataSource->getExpressionBuilder()->equals('level', $data['loggerLevel'])); } } diff --git a/src/Processor/PaymentResponseProcessor.php b/src/Processor/PaymentResponseProcessor.php index 6da99670..92ff8813 100644 --- a/src/Processor/PaymentResponseProcessor.php +++ b/src/Processor/PaymentResponseProcessor.php @@ -20,14 +20,14 @@ final class PaymentResponseProcessor implements PaymentResponseProcessorInterfac { private const DEFAULT_REDIRECT_ROUTE = 'sylius_shop_order_thank_you'; - /** @var ProcessorInterface[] */ + /** @var iterable */ private $processors; /** @var UrlGeneratorInterface */ private $urlGenerator; /** - * @param ProcessorInterface[] $processors + * @param iterable $processors */ public function __construct( iterable $processors, diff --git a/src/Repository/AdyenReferenceRepository.php b/src/Repository/AdyenReferenceRepository.php index badcc616..8c6950b9 100644 --- a/src/Repository/AdyenReferenceRepository.php +++ b/src/Repository/AdyenReferenceRepository.php @@ -34,19 +34,12 @@ private function getQueryBuilderForCodeAndReference(string $code, string $pspRef return $qb; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - */ public function getOneByCodeAndReference(string $code, string $pspReference): AdyenReferenceInterface { return $this->getQueryBuilderForCodeAndReference($code, $pspReference)->getQuery()->getSingleResult(); } /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * * @throws NoResultException */ public function getOneForRefundByCodeAndReference(string $code, string $pspReference): AdyenReferenceInterface diff --git a/src/Repository/AdyenTokenRepository.php b/src/Repository/AdyenTokenRepository.php index d6c72347..f857b6bc 100644 --- a/src/Repository/AdyenTokenRepository.php +++ b/src/Repository/AdyenTokenRepository.php @@ -18,19 +18,15 @@ final class AdyenTokenRepository extends EntityRepository implements AdyenTokenRepositoryInterface { - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function findOneByPaymentMethodAndCustomer( PaymentMethodInterface $paymentMethod, CustomerInterface $customer, ): ?AdyenTokenInterface { - return $this->findOneBy([ + $result = $this->findOneBy([ 'paymentMethod' => $paymentMethod, 'customer' => $customer, ]); + + return $result instanceof AdyenTokenInterface ? $result : null; } } diff --git a/src/Repository/AdyenTokenRepositoryInterface.php b/src/Repository/AdyenTokenRepositoryInterface.php index e9175dbe..7c060246 100644 --- a/src/Repository/AdyenTokenRepositoryInterface.php +++ b/src/Repository/AdyenTokenRepositoryInterface.php @@ -18,10 +18,6 @@ interface AdyenTokenRepositoryInterface extends RepositoryInterface { - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - */ public function findOneByPaymentMethodAndCustomer( PaymentMethodInterface $paymentMethod, CustomerInterface $customer, diff --git a/src/Repository/PaymentMethodRepository.php b/src/Repository/PaymentMethodRepository.php index 5d43efcc..1e76ba07 100644 --- a/src/Repository/PaymentMethodRepository.php +++ b/src/Repository/PaymentMethodRepository.php @@ -28,23 +28,14 @@ public function __construct(EntityRepository $baseRepository) $this->baseRepository = $baseRepository; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function find(int $id): ?PaymentMethodInterface { - return $this->baseRepository->find($id); + /** @var PaymentMethodInterface|null $result */ + $result = $this->baseRepository->find($id); + + return $result; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function getOneForAdyenAndCode(string $code): PaymentMethodInterface { return $this->baseRepository->createQueryBuilder('o') @@ -67,9 +58,6 @@ public function findOneForAdyenAndCode(string $code): ?PaymentMethodInterface } } - /** - * @psalm-suppress QueryBuilderSetParameter - */ private function getQueryForChannel(ChannelInterface $channel): QueryBuilder { return $this->baseRepository->createQueryBuilder('o') @@ -83,10 +71,6 @@ private function getQueryForChannel(ChannelInterface $channel): QueryBuilder ; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - */ public function findOneByChannel(ChannelInterface $channel): ?PaymentMethodInterface { return $this @@ -99,9 +83,6 @@ public function findOneByChannel(ChannelInterface $channel): ?PaymentMethodInter /** * @return array - * - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MixedReturnStatement */ public function findAllByChannel(ChannelInterface $channel): array { diff --git a/src/Repository/PaymentRepository.php b/src/Repository/PaymentRepository.php index 9a70ddc4..873178a7 100644 --- a/src/Repository/PaymentRepository.php +++ b/src/Repository/PaymentRepository.php @@ -24,14 +24,11 @@ public function __construct(EntityRepository $baseRepository) $this->baseRepository = $baseRepository; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function find(int $id): ?PaymentInterface { - return $this->baseRepository->find($id); + /** @var PaymentInterface|null $result */ + $result = $this->baseRepository->find($id); + + return $result; } } diff --git a/src/Repository/RefundPaymentRepository.php b/src/Repository/RefundPaymentRepository.php index c0d752b7..c0d357d1 100644 --- a/src/Repository/RefundPaymentRepository.php +++ b/src/Repository/RefundPaymentRepository.php @@ -24,12 +24,6 @@ public function __construct(EntityRepository $baseRepository) $this->baseRepository = $baseRepository; } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function getForOrderNumberAndRefundPaymentId( string $orderNumber, int $paymentId, @@ -49,14 +43,11 @@ public function getForOrderNumberAndRefundPaymentId( return $qb->getQuery()->getSingleResult(); } - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ public function find(int $id): ?RefundPaymentInterface { - return $this->baseRepository->find($id); + /** @var RefundPaymentInterface|null $result */ + $result = $this->baseRepository->find($id); + + return $result; } } diff --git a/src/Resolver/Notification/Serializer/NotificationItemNormalizer.php b/src/Resolver/Notification/Serializer/NotificationItemNormalizer.php index 1e657500..b2ea9d6b 100644 --- a/src/Resolver/Notification/Serializer/NotificationItemNormalizer.php +++ b/src/Resolver/Notification/Serializer/NotificationItemNormalizer.php @@ -26,9 +26,6 @@ final class NotificationItemNormalizer implements DenormalizerAwareInterface, De use DenormalizerAwareTrait; use NormalizerAwareTrait; - /** - * @psalm-suppress MixedReturnStatement - */ public function denormalize( $data, string $type, diff --git a/src/Resolver/Notification/Struct/NotificationItem.php b/src/Resolver/Notification/Struct/NotificationItem.php index 2ccafe11..df9619b7 100644 --- a/src/Resolver/Notification/Struct/NotificationItem.php +++ b/src/Resolver/Notification/Struct/NotificationItem.php @@ -13,9 +13,6 @@ use Symfony\Component\Serializer\Annotation\SerializedName; -/** - * @psalm-suppress MissingConstructor - */ class NotificationItem { /** @var string */ diff --git a/src/Resolver/Order/PaymentCheckoutOrderResolver.php b/src/Resolver/Order/PaymentCheckoutOrderResolver.php index f9b67898..32184197 100644 --- a/src/Resolver/Order/PaymentCheckoutOrderResolver.php +++ b/src/Resolver/Order/PaymentCheckoutOrderResolver.php @@ -49,17 +49,10 @@ private function getCurrentRequest(): Request return $result; } - /** - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress MoreSpecificReturnType - * @psalm-suppress LessSpecificReturnStatement - */ private function getCurrentOrder(): ?OrderInterface { /** * @var string|null $tokenValue - * - * @psalm-suppress InternalMethod */ $tokenValue = $this->getCurrentRequest()->get('tokenValue'); diff --git a/src/Resolver/Version/VersionResolver.php b/src/Resolver/Version/VersionResolver.php index 7d78325c..320a3040 100644 --- a/src/Resolver/Version/VersionResolver.php +++ b/src/Resolver/Version/VersionResolver.php @@ -19,12 +19,6 @@ final class VersionResolver implements VersionResolverInterface private const TEST_APPLICATION_VERSION = 'dev'; - /** - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedInferredReturnType - * @psalm-suppress InternalClass - * @psalm-suppress InternalMethod - */ private function getPluginVersion(): string { try { diff --git a/src/Validator/Constraint/HmacSignatureValidator.php b/src/Validator/Constraint/HmacSignatureValidator.php index bb3c298c..f7878b02 100644 --- a/src/Validator/Constraint/HmacSignatureValidator.php +++ b/src/Validator/Constraint/HmacSignatureValidator.php @@ -68,7 +68,7 @@ private function getPaymentCode(): string private function getNormalizedNotificationData(NotificationItemData $value): array { $params = (array) $this->normalizer->normalize($value); - $params['success'] = $value->success ? 'true' : 'false'; + $params['success'] = ($value->success ?? false) ? 'true' : 'false'; return $params; } diff --git a/tests/Application/.env b/tests/Application/.env index 8fe97708..f2a5f1ca 100644 --- a/tests/Application/.env +++ b/tests/Application/.env @@ -12,7 +12,7 @@ APP_SECRET=EDITME # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url # For a sqlite database, use: "sqlite:///%kernel.project_dir%/var/data.db" # Set "serverVersion" to your server version to avoid edge-case exceptions and extra database calls -DATABASE_URL=mysql://root:root@127.0.0.1/adyen_%kernel.environment%?serverVersion=5.5 +DATABASE_URL=mysql://root@127.0.0.1/adyen_%kernel.environment%?serverVersion=8.0 ###< doctrine/doctrine-bundle ### ###> lexik/jwt-authentication-bundle ### diff --git a/tests/Application/.env.test b/tests/Application/.env.test index d7006912..ce1e3d3a 100644 --- a/tests/Application/.env.test +++ b/tests/Application/.env.test @@ -2,4 +2,4 @@ APP_SECRET='ch4mb3r0f5ecr3ts' KERNEL_CLASS='Tests\BitBag\SyliusAdyenPlugin\Application\Kernel' -DATABASE_URL=mysql://root@127.0.0.1/adyen_%kernel.environment%?serverVersion=5.5 +DATABASE_URL=mysql://root@127.0.0.1/adyen_%kernel.environment%?serverVersion=8.0