Merge branch '2.0' into api-platform-3

* 2.0:
  [ShipmentBundle] Add symfony workflow configuration for Shipment
  [CoreBundle] Add Shipment transition listeners
  [CoreBundle] Add symfony workflow configuration for Shipment
  Fix failing phpspec scenario on Symfony 6.3.5 and above
  Fix failing phpspec scenario on Symfony 6.3.5 and above
  Fix failing phpspec scenario on Symfony 6.3.5 and above
  Services definition fix after review
  Fixes after review
  [Bunnyshell] Bump the PHP version to 8.2 in the php Dockerfile
  [ECS] Apply ecs fixes
  [ShippingBundle] Change deprecated Calendar class
  [Maintenance] Deprecate using `parentId` in TaxonSlugController
  Add newline to align with other public method
This commit is contained in:
Grzegorz Sadowski 2023-10-06 09:25:17 +02:00
commit 3a110eaa56
No known key found for this signature in database
GPG key ID: EF87FF4E6E3BD364
23 changed files with 357 additions and 38 deletions

View file

@ -1,10 +1,10 @@
# the different stages of this Dockerfile are meant to be built into separate images
# https://docs.docker.com/compose/compose-file/#target
ARG PHP_VERSION=8.1
ARG NODE_VERSION=16
ARG ALPINE_VERSION=3.15
ARG COMPOSER_VERSION=2.4
ARG PHP_VERSION=8.2
ARG NODE_VERSION=18
ARG ALPINE_VERSION=3.18
ARG COMPOSER_VERSION=2.6
ARG PHP_EXTENSION_INSTALLER_VERSION=latest
FROM composer:${COMPOSER_VERSION} AS composer

View file

@ -38,9 +38,10 @@ parameters:
- '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/'
- '/Class "Sylius\\Bundle\\CoreBundle\\Fixture\\PaymentFixture" not found/'
- '/Class Symfony\\Component\\Clock\\Clock not found\./'
- '/Class Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken constructor invoked with 4 parameters\, 2\-3 required./'
- '/Method Symfony\\Component\\Serializer\\Normalizer\\NormalizerInterface\:\:supportsNormalization\(\) invoked with 3 parameters\, 1\-2 required\./'
- '/(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
- '/Symfony\\Component\\Serializer\\NameConverter\\NameConverterInterface::normalize\(\) invoked with 2 parameters, 1 required./'
- '/Class "Sylius\\Bundle\\CoreBundle\\Fixture\\PaymentFixture" not found/'

View file

@ -265,6 +265,7 @@
</TooManyArguments>
<UndefinedClass>
<errorLevel type="info">
<referencedClass name="Symfony\Component\Clock\Clock" /> <!-- introduced in Symfony 6.2 -->
<referencedClass name="Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface" />
</errorLevel>
</UndefinedClass>

View file

@ -17,6 +17,7 @@ use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\ApiBundle\Command\Checkout\CompleteOrder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\DelayedMessageHandlingException;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
@ -42,7 +43,13 @@ final class MessengerDataPersisterSpec extends ObjectBehavior
$completeOrder->setOrderTokenValue('ORDERTOKEN');
$envelope = new Envelope($completeOrder);
$decoratedDataPersister->persist($envelope, [])->willThrow(new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')]));
if (version_compare(Kernel::VERSION, '6.3.5', '>=')) {
$exception = new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')], $envelope);
} else {
$exception = new DelayedMessageHandlingException([new \RuntimeException('Delayed message exception')]);
}
$decoratedDataPersister->persist($envelope, [])->willThrow($exception);
$this->shouldThrow(new \RuntimeException('Delayed message exception'))->during('persist', [$envelope, []]);
}

View file

@ -26,10 +26,8 @@ final class AfterOrderShippedListener
public function onOrderShippingCompleted(CompletedEvent $event): void
{
Assert::isInstanceOf($event->getSubject(), OrderInterface::class);
/** @var OrderInterface $order */
$order = $event->getSubject();
Assert::isInstanceOf($order, OrderInterface::class);
$this->orderStateResolver->resolve($order);
}

View file

@ -0,0 +1,34 @@
<?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\Bundle\CoreBundle\EventListener\Workflow\Shipment;
use Sylius\Bundle\ShippingBundle\Assigner\ShippingDateAssignerInterface;
use Sylius\Component\Core\Model\ShipmentInterface;
use Symfony\Component\Workflow\Event\TransitionEvent;
use Webmozart\Assert\Assert;
final class AssignShippingDateListener
{
public function __construct(private ShippingDateAssignerInterface $shippingDateAssigner)
{
}
public function __invoke(TransitionEvent $event): void
{
$shipment = $event->getSubject();
Assert::isInstanceOf($shipment, ShipmentInterface::class);
$this->shippingDateAssigner->assign($shipment);
}
}

View file

@ -0,0 +1,38 @@
<?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\Bundle\CoreBundle\EventListener\Workflow\Shipment;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShipmentInterface;
use Sylius\Component\Order\StateResolver\StateResolverInterface;
use Symfony\Component\Workflow\Event\CompletedEvent;
use Webmozart\Assert\Assert;
final class ResolveOrderShipmentStateListener
{
public function __construct(private StateResolverInterface $orderStateResolver)
{
}
public function __invoke(CompletedEvent $event): void
{
$shipment = $event->getSubject();
Assert::isInstanceOf($shipment, ShipmentInterface::class);
$order = $shipment->getOrder();
Assert::isInstanceOf($order, OrderInterface::class);
$this->orderStateResolver->resolve($order);
}
}

View file

@ -4,7 +4,7 @@ framework:
type: state_machine
marking_store:
type: method
property: ShippingState
property: shippingState
supports:
- Sylius\Component\Core\Model\OrderInterface
initial_marking: !php/const Sylius\Component\Core\OrderShippingStates::STATE_CART

View file

@ -0,0 +1,25 @@
framework:
workflows:
!php/const Sylius\Component\Shipping\ShipmentTransitions::GRAPH:
type: state_machine
marking_store:
type: method
property: state
supports:
- Sylius\Component\Core\Model\ShipmentInterface
initial_marking: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
places:
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_SHIPPED
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CANCELLED
transitions:
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_CREATE:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_SHIP:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_SHIPPED
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_CANCEL:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CANCELLED

View file

@ -42,7 +42,6 @@
<import resource="services/taxation.xml" />
<import resource="services/templating.xml" />
<import resource="services/validators.xml" />
<import resource="services/workflow.xml" />
</imports>
<parameters>

View file

@ -12,6 +12,10 @@
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="listeners/workflow/*.xml" />
</imports>
<services>
<defaults public="true" />

View file

@ -16,7 +16,7 @@
<defaults public="false" />
<service id="Sylius\Bundle\CoreBundle\EventListener\Workflow\OrderShipping\AfterOrderShippedListener">
<argument type="service" id="sylius.state_resolver.order_shipping" />
<argument type="service" id="sylius.state_resolver.order" />
<tag name="kernel.event_listener"
event="workflow.sylius_order_shipping.completed.ship"
method="onOrderShippingCompleted"

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<defaults public="false" />
<service id="Sylius\Bundle\CoreBundle\EventListener\Workflow\Shipment\ResolveOrderShipmentStateListener">
<argument type="service" id="sylius.state_resolver.order_shipping" />
<tag name="kernel.event_listener"
event="workflow.sylius_shipment.completed.ship"
priority="-100"
/>
</service>
<service id="Sylius\Bundle\CoreBundle\EventListener\Workflow\Shipment\AssignShippingDateListener">
<argument type="service" id="sylius.shipping_date_assigner" />
<tag name="kernel.event_listener"
event="workflow.sylius_shipment.transition.ship"
priority="-100"
/>
</service>
</services>
</container>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<imports>
<import resource="workflow/*.xml" />
</imports>
</container>

View file

@ -0,0 +1,66 @@
<?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\Bundle\CoreBundle\Tests\Functional\StateMachine;
use PHPUnit\Framework\MockObject\MockObject;
use Sylius\Bundle\CoreBundle\StateMachine\StateMachineInterface;
use Sylius\Component\Core\Model\Order;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\Shipment;
use Sylius\Component\Core\Model\ShipmentInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
final class ShipmentWorkflowTest extends KernelTestCase
{
/** @var ShipmentInterface|MockObject */
protected ShipmentInterface $shipment;
/** @var OrderInterface|MockObject */
protected OrderInterface $order;
public function setUp(): void
{
parent::setUp();
$this->order = new Order();
$this->shipment = new Shipment();
$this->shipment->setOrder($this->order);
}
/**
* @test
*
* @dataProvider availableTransitionsFromReadyState
*/
public function it_applies_all_available_transitions_for_create_state(string $transition, string $expectedStatus): void
{
$stateMachine = $this->getStateMachine();
$stateMachine->apply($this->order, 'sylius_order_shipping', 'request_shipping');
$stateMachine->apply($this->shipment, 'sylius_shipment', 'create');
$stateMachine->apply($this->shipment, 'sylius_shipment', $transition);
$this->assertSame($expectedStatus, $this->shipment->getState());
}
public function availableTransitionsFromReadyState(): iterable
{
yield ['cancel', 'cancelled'];
yield ['ship', 'shipped'];
}
private function getStateMachine(): StateMachineInterface
{
return self::getContainer()->get('sylius.state_machine.adapter.symfony_workflow');
}
}

View file

@ -35,9 +35,7 @@ final class OrderShippingWorkflowTest extends KernelTestCase
$this->assertSame($expectedStatus, $subject->getShippingState());
}
/**
* @test
*/
/** @test */
public function it_applies_ship_transition_if_order_is_partially_shipped(): void
{
$stateMachine = $this->getStateMachine();

View file

@ -28,10 +28,13 @@ final class AfterOrderShippedListenerSpec extends ObjectBehavior
function it_throws_an_exception_on_non_supported_subject(\stdClass $callback): void
{
$this->shouldThrow(\InvalidArgumentException::class)->during('onOrderShippingCompleted', [new CompletedEvent($callback->getWrappedObject(), new Marking())]);
$this
->shouldThrow(\InvalidArgumentException::class)
->during('onOrderShippingCompleted', [new CompletedEvent($callback->getWrappedObject(), new Marking())])
;
}
function it_resolves_orders_after_order_being_shipped(
function it_resolves_order_state_after_order_being_shipped(
StateResolverInterface $stateResolver,
): void {
$order = new Order();

View file

@ -0,0 +1,47 @@
<?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 spec\Sylius\Bundle\CoreBundle\EventListener\Workflow\Shipment;
use PhpSpec\ObjectBehavior;
use Sylius\Bundle\ShippingBundle\Assigner\ShippingDateAssignerInterface;
use Sylius\Component\Core\Model\Shipment;
use Symfony\Component\Workflow\Event\TransitionEvent;
use Symfony\Component\Workflow\Marking;
final class AssignShippingDateListenerSpec extends ObjectBehavior
{
function let(ShippingDateAssignerInterface $shippingDateAssigner): void
{
$this->beConstructedWith($shippingDateAssigner);
}
function it_throws_an_exception_on_non_supported_subject(\stdClass $subject): void
{
$this
->shouldThrow(\InvalidArgumentException::class)
->during('__invoke', [new TransitionEvent($subject->getWrappedObject(), new Marking())])
;
}
function it_resolves_order_state_after_order_being_shipped(
ShippingDateAssignerInterface $shippingDateAssigner,
): void {
$shipment = new Shipment();
$event = new TransitionEvent($shipment, new Marking());
$shippingDateAssigner->assign($shipment)->shouldBeCalled();
$this->__invoke($event);
}
}

View file

@ -0,0 +1,51 @@
<?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 spec\Sylius\Bundle\CoreBundle\EventListener\Workflow\Shipment;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Model\Order;
use Sylius\Component\Core\Model\Shipment;
use Sylius\Component\Order\StateResolver\StateResolverInterface;
use Symfony\Component\Workflow\Event\CompletedEvent;
use Symfony\Component\Workflow\Marking;
final class ResolveOrderShipmentStateListenerSpec extends ObjectBehavior
{
function let(StateResolverInterface $stateResolver): void
{
$this->beConstructedWith($stateResolver);
}
function it_throws_an_exception_on_non_supported_subject(\stdClass $subject): void
{
$this
->shouldThrow(\InvalidArgumentException::class)
->during('__invoke', [new CompletedEvent($subject->getWrappedObject(), new Marking())])
;
}
function it_resolves_order_shipment_state_after_order_being_shipped(
StateResolverInterface $stateResolver,
): void {
$shipment = new Shipment();
$order = new Order();
$shipment->setOrder($order);
$event = new CompletedEvent($shipment, new Marking());
$stateResolver->resolve($order)->shouldBeCalled();
$this->__invoke($event);
}
}

View file

@ -24,7 +24,7 @@ trigger_deprecation(
);
/**
* @deprecated since Sylius 1.11 and will be removed in Sylius 2.0. Use {@see \Sylius\Calendar\Provider\Calendar} instead.
* @deprecated since Sylius 1.13 and will be removed in Sylius 2.0. Use {@see 'Symfony\Component\Clock\Clock'} instead.
*/
final class Calendar implements DateTimeProvider
{

View file

@ -0,0 +1,25 @@
framework:
workflows:
!php/const Sylius\Component\Shipping\ShipmentTransitions::GRAPH:
type: state_machine
marking_store:
type: method
property: shippingState
supports:
- Sylius\Component\Shipping\Model\ShipmentInterface
initial_marking: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
places:
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_SHIPPED
- !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CANCELLED
transitions:
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_CREATE:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CART
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_SHIP:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_SHIPPED
!php/const Sylius\Component\Shipping\ShipmentTransitions::TRANSITION_CANCEL:
from: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_READY
to: !php/const Sylius\Component\Shipping\Model\ShipmentInterface::STATE_CANCELLED

View file

@ -62,6 +62,12 @@ final class TaxonSlugController
$parentId = $request->query->get('parentId');
if (null !== $parentId) {
trigger_deprecation(
'sylius/taxonomy-bundle',
'1.13',
'Using "parentId" for slug generation is deprecated and will not be possible in 2.0. Use "parentCode" instead.',
);
return $this->taxonRepository->find($parentId);
}

View file

@ -35,6 +35,7 @@ final class OrderModifier implements OrderModifierInterface
public function removeFromOrder(OrderInterface $cart, OrderItemInterface $item): void
{
$cart->removeItem($item);
$this->orderProcessor->process($cart);
}