diff --git a/.github/actions/roave-bc-check/Dockerfile b/.github/actions/roave-bc-check/Dockerfile deleted file mode 100644 index 1cfac7d..0000000 --- a/.github/actions/roave-bc-check/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM nyholm/roave-bc-check-ga - -RUN docker-php-ext-install -j$(nproc) exif - -RUN apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev && \ - docker-php-ext-configure gd \ - --with-freetype \ - --with-jpeg \ - NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \ - docker-php-ext-install -j$(nproc) gd && \ - apk del --no-cache freetype-dev libpng-dev libjpeg-turbo-dev diff --git a/.github/actions/roave-bc-check/action.yml b/.github/actions/roave-bc-check/action.yml deleted file mode 100644 index ebb18ea..0000000 --- a/.github/actions/roave-bc-check/action.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: 'Roave BC Check' -description: 'Roave BC Check' -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 42bc2fc..25a7072 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: matrix: php: [ "8.1", "8.2", "8.3" ] symfony: [ "5.4.*", "^6.4" ] - sylius: ["1.12.16", "1.13.1"] + sylius: ["1.13.3"] node: ["18.x"] mysql: ["8.0"] @@ -192,9 +192,24 @@ jobs: roave_bc_check: name: Roave BC Check runs-on: ubuntu-latest + env: + PHP_VERSION: 8.2 steps: - - uses: actions/checkout@master - - name: fetch tags - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - - name: Roave BC Check - uses: ./.github/actions/roave-bc-check + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ env.PHP_VERSION }}" + extensions: intl + tools: flex,symfony + coverage: none + + - name: Install roave/backward-compatibility-check. + run: composer require --dev roave/backward-compatibility-check --no-plugins + + - name: Run roave/backward-compatibility-check. + run: vendor/bin/roave-backward-compatibility-check --format=github-actions diff --git a/composer.json b/composer.json index f475547..833e70e 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "license": "MIT", "require": { "php": "^8.1", - "sylius/sylius": "^1.12", + "sylius/sylius": "^1.13.3", "symfony/webpack-encore-bundle": "^1.15" }, "require-dev": { diff --git a/features/managing_table_rates.feature b/features/managing_table_rates.feature index 4ed7495..5f57b05 100644 --- a/features/managing_table_rates.feature +++ b/features/managing_table_rates.feature @@ -41,7 +41,7 @@ Feature: Managing table rates @ui Scenario: Updating a table rate Given the store has a shipping table rate "East Coast Rates" for currency "USD" - And this shipping table rate has a rate "$5" for shipments up to 1000 kg + And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg And I want to modify the "East Coast Rates" table rate When I change its name to "Edited Rates" And I save my changes @@ -52,8 +52,8 @@ Feature: Managing table rates Scenario: Adding weight rates into a table rate Given the store has a shipping table rate "East Coast Rates" for currency "USD" And I want to modify the "East Coast Rates" table rate - When I add a new rate of "$5" for shipments up to 5 kg - And I add a new rate of "$10" for shipments up to 20 kg + When I add a new rate of "$5.00" for shipments up to 5 kg + And I add a new rate of "$10.00" for shipments up to 20 kg And I save my changes Then I should be notified that it has been successfully edited And this shipping table rate should have 2 rates @@ -63,21 +63,21 @@ Feature: Managing table rates When I try to add a new shipping table And I specify its code as "VALIDATE_ME" And I specify its currency as "USD" - And I add a new rate of "$10" for shipments up to 20 kg + And I add a new rate of "$10.00" for shipments up to 20 kg But I do not specify its name And I try to add it Then I should be notified that name is required When I try to add a new shipping table And I specify its name as "Validate Me" And I specify its currency as "USD" - And I add a new rate of "$10" for shipments up to 20 kg + And I add a new rate of "$10.00" for shipments up to 20 kg But I do not specify its code And I try to add it Then I should be notified that code is required When I try to add a new shipping table And I specify its code as "VALIDATE_ME" And I specify its name as "Validate Me" - And I add a new rate of "$10" for shipments up to 20 kg + And I add a new rate of "$10.00" for shipments up to 20 kg But I do not specify its currency And I try to add it Then I should be notified that currency is required @@ -92,7 +92,7 @@ Feature: Managing table rates @ui Scenario: Trying to change table rate code (even if its field is disabled) Given the store has a shipping table rate "East Coast Rates" for currency "USD" - And this shipping table rate has a rate "$5" for shipments up to 1000 kg + And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg And I want to modify the "East Coast Rates" table rate Then the code field should be disabled When I change its code to "ANOTHER_CODE" @@ -103,7 +103,7 @@ Feature: Managing table rates Scenario: Trying to change table rate currency (even if its field is disabled) Given the store also operates on another channel named "Europe" in "EUR" currency And the store has a shipping table rate "East Coast Rates" for currency "USD" - And this shipping table rate has a rate "$5" for shipments up to 1000 kg + And this shipping table rate has a rate "$5.00" for shipments up to 1000 kg And I want to modify the "East Coast Rates" table rate Then the currency field should be disabled When I change its currency to "EUR" diff --git a/features/seeing_correct_shipping_fees_for_table_rate_based_method.feature b/features/seeing_correct_shipping_fees_for_table_rate_based_method.feature index e8fbce5..680eaa8 100644 --- a/features/seeing_correct_shipping_fees_for_table_rate_based_method.feature +++ b/features/seeing_correct_shipping_fees_for_table_rate_based_method.feature @@ -8,8 +8,8 @@ Feature: Seeing correct shipping fees for table rate based shipping methods Given the store operates on a single channel in "United States" And the store has a product "Bottle of water" which weights 1 kg And the store has a shipping table rate "Weight-based" for currency "USD" - And it has a rate "$5" for shipments up to 5 kg - And it has a rate "$10" for shipments up to 20 kg + And it has a rate "$5.00" for shipments up to 5 kg + And it has a rate "$10.00" for shipments up to 20 kg And the store has "Basic" shipping method using "Weight-based" table rate for "United States" channel And I am a logged in customer diff --git a/spec/EventSubscriber/TableRateDeleteSubscriberSpec.php b/spec/EventSubscriber/TableRateDeleteSubscriberSpec.php index eb718cc..b834056 100644 --- a/spec/EventSubscriber/TableRateDeleteSubscriberSpec.php +++ b/spec/EventSubscriber/TableRateDeleteSubscriberSpec.php @@ -17,46 +17,46 @@ class TableRateDeleteSubscriberSpec extends ObjectBehavior { - function let(ShippingMethodRepositoryInterface $shippingMethodRepository) + public function let(ShippingMethodRepositoryInterface $shippingMethodRepository): void { $this->beConstructedWith($shippingMethodRepository); } - function it_is_initializable() + public function it_is_initializable(): void { $this->shouldHaveType(TableRateDeleteSubscriber::class); } - function it_should_implement_event_subscriber_interface() + public function it_should_implement_event_subscriber_interface(): void { $this->shouldImplement(EventSubscriberInterface::class); } - function it_should_subscribe_to_table_rate_pre_delete_event() + public function it_should_subscribe_to_table_rate_pre_delete_event(): void { self::getSubscribedEvents()->shouldReturn( ['webgriffe.shipping_table_rate.pre_delete' => 'onTableRatePreDelete'] ); } - function it_should_stop_event_if_table_rate_is_already_in_use( + public function it_should_stop_event_if_table_rate_is_already_in_use( ResourceControllerEvent $event, ShippingMethodRepositoryInterface $shippingMethodRepository - ) { + ): void { $tableRate = new ShippingTableRate(); $tableRate->setCode('TABLE_RATE'); $anotherTableRate = new ShippingTableRate(); $anotherTableRate->setCode('ANOTHER_RATE'); $shippingMethod1 = new ShippingMethod(); $shippingMethod1->setCode('METHOD1'); - $shippingMethod1->setConfiguration(['WEB-US' => ['table_rate' => $tableRate]]); + $shippingMethod1->setConfiguration(['WEB-US' => ['table_rate' => 'TABLE_RATE']]); $shippingMethod2 = new ShippingMethod(); $shippingMethod2->setCode('METHOD2'); - $shippingMethod2->setConfiguration(['WEB-US' => ['table_rate' => $anotherTableRate]]); + $shippingMethod2->setConfiguration(['WEB-US' => ['table_rate' => 'ANOTHER_RATE']]); $shippingMethod3 = new ShippingMethod(); $shippingMethod3->setCode('METHOD3'); $shippingMethod3->setConfiguration( - ['WEB-US' => ['table_rate' => $anotherTableRate], 'WEB-EU' => ['table_rate' => $tableRate]] + ['WEB-US' => ['table_rate' => 'ANOTHER_RATE'], 'WEB-EU' => ['table_rate' => 'TABLE_RATE']] ); $shippingMethodRepository ->findBy(['calculator' => TableRateShippingCalculator::TYPE]) @@ -76,11 +76,11 @@ function it_should_stop_event_if_table_rate_is_already_in_use( $this->onTableRatePreDelete($event); } - function it_should_not_stop_event_if_table_rate_is_not_in_use( + public function it_should_not_stop_event_if_table_rate_is_not_in_use( ShippingTableRate $shippingTableRate, ResourceControllerEvent $event, ShippingMethodRepositoryInterface $shippingMethodRepository - ) { + ): void { $event->getSubject()->willReturn($shippingTableRate); $shippingMethodRepository ->findBy(['calculator' => TableRateShippingCalculator::TYPE]) diff --git a/spec/Resolver/TableRateResolverSpec.php b/spec/Resolver/TableRateResolverSpec.php index 74b53a4..575ce5d 100644 --- a/spec/Resolver/TableRateResolverSpec.php +++ b/spec/Resolver/TableRateResolverSpec.php @@ -16,17 +16,17 @@ class TableRateResolverSpec extends ObjectBehavior { - function let(RepositoryInterface $tableRateRepository): void + public function let(RepositoryInterface $tableRateRepository): void { $this->beConstructedWith($tableRateRepository); } - function it_should_implement_table_rate_resolver_interface(): void + public function it_should_implement_table_rate_resolver_interface(): void { $this->shouldImplement(TableRateResolverInterface::class); } - function it_should_resolve_table_rate_from_shipment( + public function it_should_resolve_table_rate_from_shipment( ShipmentInterface $shipment, OrderInterface $order, ChannelInterface $channel, @@ -38,12 +38,12 @@ function it_should_resolve_table_rate_from_shipment( $channel->getCode()->willReturn('CHANNEL_CODE'); $tableRate->getCode()->willReturn('TABLE_RATE_CODE'); $tableRateRepository->findOneBy(['code' => 'TABLE_RATE_CODE'])->willReturn($tableRate); - $calculatorConfig = ['CHANNEL_CODE' => ['table_rate' => $tableRate]]; + $calculatorConfig = ['CHANNEL_CODE' => ['table_rate' => 'TABLE_RATE_CODE']]; $this->resolve($shipment, $calculatorConfig)->shouldReturn($tableRate); } - function it_throws_a_missing_channel_configuration_exception_if_the_order_channel_is_not_configured( + public function it_throws_a_missing_channel_configuration_exception_if_the_order_channel_is_not_configured( ShipmentInterface $shipment, OrderInterface $order, ChannelInterface $channel, diff --git a/src/EventSubscriber/TableRateDeleteSubscriber.php b/src/EventSubscriber/TableRateDeleteSubscriber.php index 9c72fe9..4e6fed9 100644 --- a/src/EventSubscriber/TableRateDeleteSubscriber.php +++ b/src/EventSubscriber/TableRateDeleteSubscriber.php @@ -33,9 +33,9 @@ public function onTableRatePreDelete(ResourceControllerEvent $event): void /** @var ShippingMethod $shippingMethod */ foreach ($shippingMethods as $shippingMethod) { foreach ($shippingMethod->getConfiguration() as $channelConfiguration) { - /** @var ShippingTableRate|null $channelTableRate */ - $channelTableRate = $channelConfiguration['table_rate'] ?? null; - if ($channelTableRate !== null && $channelTableRate->getCode() === $shippingTableRate->getCode()) { + /** @var string|null $channelTableRateCode */ + $channelTableRateCode = $channelConfiguration['table_rate'] ?? null; + if ($channelTableRateCode !== null && $channelTableRateCode === $shippingTableRate->getCode()) { $foundMethods[] = $shippingMethod->getCode(); } } diff --git a/src/Form/Type/Shipping/Calculator/TableRateConfigurationType.php b/src/Form/Type/Shipping/Calculator/TableRateConfigurationType.php index 262af7d..1b0b29d 100644 --- a/src/Form/Type/Shipping/Calculator/TableRateConfigurationType.php +++ b/src/Form/Type/Shipping/Calculator/TableRateConfigurationType.php @@ -6,15 +6,24 @@ use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; +use Sylius\Component\Resource\Repository\RepositoryInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\DataMapperInterface; +use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Validator\Constraints\NotBlank; use Webgriffe\SyliusTableRateShippingPlugin\Entity\ShippingTableRate; -final class TableRateConfigurationType extends AbstractType +final class TableRateConfigurationType extends AbstractType implements DataMapperInterface { + public function __construct( + private RepositoryInterface $tableRateRepository, + ) { + } + public const TABLE_RATE_FIELD_NAME = 'table_rate'; public function buildForm(FormBuilderInterface $builder, array $options): void @@ -26,7 +35,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void EntityType::class, [ 'label' => $messagesNamespace . 'table_rate.label', - 'placeholder' => '' . $messagesNamespace . 'table_rate.placeholder', + 'placeholder' => $messagesNamespace . 'table_rate.placeholder', 'class' => ShippingTableRate::class, 'query_builder' => function (EntityRepository $entityRepository) use ($currency): QueryBuilder { return $entityRepository @@ -38,8 +47,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'choice_label' => 'name', 'choice_value' => 'code', 'constraints' => [new NotBlank(['groups' => ['sylius']])], - ] - ); + ], + )->setDataMapper($this); } public function configureOptions(OptionsResolver $resolver): void @@ -54,4 +63,55 @@ public function getBlockPrefix(): string { return 'webgriffe_sylius_table_rate_shipping_plugin_calculator_table_rate'; } + + /** + * @psalm-suppress MoreSpecificImplementedParamType + * @psalm-suppress PossiblyInvalidArgument + * @psalm-suppress UnnecessaryVarAnnotation + */ + public function mapDataToForms(mixed $viewData, \Traversable $forms): void + { + // there is no data yet, so nothing to prepopulate + if (null === $viewData) { + return; + } + + // invalid data type + if (!is_array($viewData)) { + throw new UnexpectedTypeException($viewData, 'array'); + } + + /** @var FormInterface[] $forms */ + $forms = iterator_to_array($forms); + + if (!array_key_exists(self::TABLE_RATE_FIELD_NAME, $viewData)) { + return; + } + + // initialize form field values + $forms['table_rate']->setData($this->tableRateRepository->findOneBy(['code' => $viewData[self::TABLE_RATE_FIELD_NAME]])); + } + + /** + * @psalm-suppress MoreSpecificImplementedParamType + * @psalm-suppress PossiblyInvalidArgument + * @psalm-suppress UnnecessaryVarAnnotation + */ + public function mapFormsToData(\Traversable $forms, mixed &$viewData): void + { + /** @var FormInterface[] $forms */ + $forms = iterator_to_array($forms); + + // as data is passed by reference, overriding it will change it in + // the form object as well + // beware of type inconsistency, see caution below + $tableRateSelected = $forms[self::TABLE_RATE_FIELD_NAME]->getData(); + if (!$tableRateSelected instanceof ShippingTableRate) { + $viewData = []; + + return; + } + + $viewData = [self::TABLE_RATE_FIELD_NAME => $tableRateSelected->getCode()]; + } } diff --git a/src/Resolver/TableRateResolver.php b/src/Resolver/TableRateResolver.php index 28af63f..b6baf5f 100644 --- a/src/Resolver/TableRateResolver.php +++ b/src/Resolver/TableRateResolver.php @@ -29,7 +29,7 @@ public function resolve(ShipmentInterface $shipment, array $calculatorConfig): S $channel = $order->getChannel(); if (null === $channel) { throw new \RuntimeException( - 'Cannot resolve a table rate, there\'s no channel for this shipment\'s order.' + 'Cannot resolve a table rate, there\'s no channel for this shipment\'s order.', ); } $channelCode = $channel->getCode(); @@ -40,8 +40,8 @@ public function resolve(ShipmentInterface $shipment, array $calculatorConfig): S throw new MissingChannelConfigurationException( sprintf( 'This shipment has no configuration for channel "%s".', - $channel->getName() - ) + $channel->getName(), + ), ); } @@ -49,14 +49,14 @@ public function resolve(ShipmentInterface $shipment, array $calculatorConfig): S sprintf( 'Shipping method "%s" has no configuration for channel "%s".', $shippingMethod->getName(), - $channel->getName() - ) + $channel->getName(), + ), ); } - /** @var ShippingTableRate $tableRate */ - $tableRate = $calculatorConfig[$channelCode][TableRateConfigurationType::TABLE_RATE_FIELD_NAME]; - $tableRate = $this->tableRateRepository->findOneBy(['code' => $tableRate->getCode()]); + /** @var string $tableRateCode */ + $tableRateCode = $calculatorConfig[$channelCode][TableRateConfigurationType::TABLE_RATE_FIELD_NAME]; + $tableRate = $this->tableRateRepository->findOneBy(['code' => $tableRateCode]); Assert::isInstanceOf($tableRate, ShippingTableRate::class); return $tableRate; diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 18b6271..652f45f 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -36,6 +36,8 @@ services: - { name: form.type } Webgriffe\SyliusTableRateShippingPlugin\Form\Type\Shipping\Calculator\TableRateConfigurationType: + arguments: + - '@webgriffe.repository.shipping_table_rate' tags: - { name: form.type } diff --git a/tests/Application/config/routes/sylius_shop.yaml b/tests/Application/config/routes/sylius_shop.yaml index 92eeae0..fae46cb 100644 --- a/tests/Application/config/routes/sylius_shop.yaml +++ b/tests/Application/config/routes/sylius_shop.yaml @@ -11,4 +11,4 @@ sylius_shop_default_locale: path: / methods: [GET] defaults: - _controller: sylius.controller.shop.locale_switch:switchAction + _controller: sylius.controller.shop.locale_switch::switchAction diff --git a/tests/Behat/Context/Setup/ShippingTableRateContext.php b/tests/Behat/Context/Setup/ShippingTableRateContext.php index e51873f..579563a 100644 --- a/tests/Behat/Context/Setup/ShippingTableRateContext.php +++ b/tests/Behat/Context/Setup/ShippingTableRateContext.php @@ -89,7 +89,7 @@ public function theStoreHasShippingMethodUsingTableRateForChannel( 'zone' => $this->getShippingZone(), 'calculator' => [ 'type' => TableRateShippingCalculator::TYPE, - 'configuration' => [$channel->getCode() => ['table_rate' => $shippingTableRate]], + 'configuration' => [$channel->getCode() => [TableRateShippingCalculator::TYPE => $shippingTableRate->getCode()]], ], 'channels' => [$channel], ]); diff --git a/tests/Behat/Context/Ui/ManagingShippingMethodsWithTableRateContext.php b/tests/Behat/Context/Ui/ManagingShippingMethodsWithTableRateContext.php index 4a059d1..c6f4805 100644 --- a/tests/Behat/Context/Ui/ManagingShippingMethodsWithTableRateContext.php +++ b/tests/Behat/Context/Ui/ManagingShippingMethodsWithTableRateContext.php @@ -23,7 +23,7 @@ public function __construct(private UpdatePageInterface $updatePage) public function iShouldBeAbleToChooseOnlyTheTableRateForTheChannel( ShippingTableRate $shippingTableRate, ChannelInterface $channel - ) { + ): void { /** @var NodeElement[] $options */ $options = $this->updatePage->getTableRateOptions($channel->getCode()); Assert::count($options, 1);