From 695c1a04522d0ee972d896f8efe90b09da9bd356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Wed, 22 Mar 2023 08:35:09 +0100 Subject: [PATCH 01/11] Add Event dispatcher provider --- src/Bundle/Resources/config/services/state.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Bundle/Resources/config/services/state.xml b/src/Bundle/Resources/config/services/state.xml index c88a90673..7aaba1e35 100644 --- a/src/Bundle/Resources/config/services/state.xml +++ b/src/Bundle/Resources/config/services/state.xml @@ -13,6 +13,24 @@ + + + + + + + + + + + + + + From 4bb7ff0f40ad2938b0eb3076a37443a84858ae8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 30 Mar 2023 08:58:25 +0200 Subject: [PATCH 02/11] Flash helper with plural name --- .../Symfony/Session/Flash/FlashHelper.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Component/Symfony/Session/Flash/FlashHelper.php b/src/Component/Symfony/Session/Flash/FlashHelper.php index 4a5d8b79d..b6cecf67c 100644 --- a/src/Component/Symfony/Session/Flash/FlashHelper.php +++ b/src/Component/Symfony/Session/Flash/FlashHelper.php @@ -101,6 +101,27 @@ private function addFlash(string $message, string $type, Context $context): void $flashBag->add($type, $message); } + private function buildMessage(Operation $operation, string $type): string + { + $resource = $operation->getResource(); + Assert::notNull($resource); + + $specifyKey = sprintf('%s.%s.%s', $resource->getApplicationName() ?? '', $resource->getName() ?? '', $operation->getShortName() ?? ''); + $defaultKey = sprintf('sylius.resource.%s', $operation->getShortName() ?? ''); + + $parameters = $this->getTranslationParameters($operation); + + if (!$this->translator instanceof TranslatorBagInterface) { + return $this->translator->trans($defaultKey, $parameters, 'flashes'); + } + + if ($this->translator->getCatalogue()->has($specifyKey, 'flashes')) { + return $this->translator->trans($specifyKey, $parameters, 'flashes'); + } + + return $this->translator->trans($defaultKey, $parameters, 'flashes'); + } + private function getTranslationParameters(Operation $operation): array { $resource = $operation->getResource(); From 0322a5b99a63444111e93f8fe52a329a4e62e227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 1 Jun 2023 08:58:04 +0200 Subject: [PATCH 03/11] Bulk update --- .../Resources/config/services/routing.xml | 8 +- .../grid/bulk_action/accept.html.twig | 14 ++ src/Component/Metadata/BulkUpdate.php | 117 ++++++++++ ...irectResourceMetadataCollectionFactory.php | 14 +- .../Symfony/EventListener/FormListener.php | 2 + .../Symfony/Routing/RedirectHandler.php | 7 +- .../EventListener/FormListenerSpec.php | 215 +++++++++++++----- .../BulkOperationRoutePathFactorySpec.php | 8 + .../Factory/OperationRouteFactorySpec.php | 26 +++ .../Symfony/Routing/RedirectHandlerSpec.php | 16 ++ .../config/packages/test/sylius_grid.yaml | 1 + .../src/Subscription/Entity/Subscription.php | 5 + .../Subscription/Grid/SubscriptionGrid.php | 10 + .../Tests/Controller/SubscriptionUiTest.php | 17 ++ .../bulk_action/apply_transition.html.twig | 15 ++ .../grid/bulk_action/delete.html.twig | 1 + 16 files changed, 411 insertions(+), 65 deletions(-) create mode 100644 src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig create mode 100644 src/Component/Metadata/BulkUpdate.php create mode 100644 tests/Application/templates/grid/bulk_action/apply_transition.html.twig diff --git a/src/Bundle/Resources/config/services/routing.xml b/src/Bundle/Resources/config/services/routing.xml index 7ddd6bf14..4d15f1f12 100644 --- a/src/Bundle/Resources/config/services/routing.xml +++ b/src/Bundle/Resources/config/services/routing.xml @@ -63,16 +63,16 @@ - - diff --git a/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig b/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig new file mode 100644 index 000000000..646a3b17b --- /dev/null +++ b/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig @@ -0,0 +1,14 @@ +{% set path = options.link.url|default(path(options.link.route|default(grid.requestConfiguration.getRouteName('bulk_accept')), options.link.parameters|default({}))) %} + +
+ + + + + {% for resource in grid.data %} + + {% endfor %} +
+ diff --git a/src/Component/Metadata/BulkUpdate.php b/src/Component/Metadata/BulkUpdate.php new file mode 100644 index 000000000..bf3556525 --- /dev/null +++ b/src/Component/Metadata/BulkUpdate.php @@ -0,0 +1,117 @@ +stateMachineComponent; + } + + public function withStateMachineComponent(?string $stateMachineComponent): self + { + $self = clone $this; + $self->stateMachineComponent = $stateMachineComponent; + + return $self; + } + + public function getStateMachineTransition(): ?string + { + return $this->stateMachineTransition; + } + + public function withStateMachineTransition(string $stateMachineTransition): self + { + $self = clone $this; + $self->stateMachineTransition = $stateMachineTransition; + + return $self; + } + + public function getStateMachineGraph(): ?string + { + return $this->stateMachineGraph; + } + + public function withStateMachineGraph(string $stateMachineGraph): self + { + $self = clone $this; + $self->stateMachineGraph = $stateMachineGraph; + + return $self; + } +} diff --git a/src/Component/Metadata/Resource/Factory/RedirectResourceMetadataCollectionFactory.php b/src/Component/Metadata/Resource/Factory/RedirectResourceMetadataCollectionFactory.php index 110bca64d..b0a7d7a71 100644 --- a/src/Component/Metadata/Resource/Factory/RedirectResourceMetadataCollectionFactory.php +++ b/src/Component/Metadata/Resource/Factory/RedirectResourceMetadataCollectionFactory.php @@ -13,6 +13,7 @@ namespace Sylius\Component\Resource\Metadata\Resource\Factory; +use Sylius\Component\Resource\Metadata\BulkOperationInterface; use Sylius\Component\Resource\Metadata\CreateOperationInterface; use Sylius\Component\Resource\Metadata\DeleteOperationInterface; use Sylius\Component\Resource\Metadata\HttpOperation; @@ -65,7 +66,18 @@ private function addDefaults(ResourceMetadata $resource, HttpOperation $operatio return $operation; } - if ($operation instanceof CreateOperationInterface || $operation instanceof UpdateOperationInterface) { + if ($operation instanceof BulkOperationInterface) { + $newOperation = $this->setRedirectIfRouteExists($resource, $operation, 'index'); + + if (null !== $newOperation) { + return $newOperation; + } + } + + if ( + $operation instanceof CreateOperationInterface || + $operation instanceof UpdateOperationInterface + ) { $newOperation = $this->setRedirectIfRouteExists($resource, $operation, 'show'); if (null !== $newOperation) { diff --git a/src/Component/Symfony/EventListener/FormListener.php b/src/Component/Symfony/EventListener/FormListener.php index 614a3b40e..f4b871674 100644 --- a/src/Component/Symfony/EventListener/FormListener.php +++ b/src/Component/Symfony/EventListener/FormListener.php @@ -14,6 +14,7 @@ namespace Sylius\Component\Resource\Symfony\EventListener; use Sylius\Component\Resource\Context\Initiator\RequestContextInitiatorInterface; +use Sylius\Component\Resource\Metadata\BulkOperationInterface; use Sylius\Component\Resource\Metadata\CreateOperationInterface; use Sylius\Component\Resource\Metadata\Operation\HttpOperationInitiatorInterface; use Sylius\Component\Resource\Metadata\UpdateOperationInterface; @@ -42,6 +43,7 @@ public function onKernelView(ViewEvent $event): void if ( $controllerResult instanceof Response || + $operation instanceof BulkOperationInterface || !($operation instanceof CreateOperationInterface || $operation instanceof UpdateOperationInterface) || 'html' !== $format || null == $operation->getFormType() diff --git a/src/Component/Symfony/Routing/RedirectHandler.php b/src/Component/Symfony/Routing/RedirectHandler.php index 0ff90de49..1186d9379 100644 --- a/src/Component/Symfony/Routing/RedirectHandler.php +++ b/src/Component/Symfony/Routing/RedirectHandler.php @@ -13,6 +13,7 @@ namespace Sylius\Component\Resource\Symfony\Routing; +use Sylius\Component\Resource\Metadata\BulkOperationInterface; use Sylius\Component\Resource\Metadata\DeleteOperationInterface; use Sylius\Component\Resource\Metadata\HttpOperation; use Sylius\Component\Resource\Metadata\Resource; @@ -69,7 +70,11 @@ private function getRouteArguments(mixed $data, HttpOperation $operation, Reques $redirectArguments = $operation->getRedirectArguments() ?? []; - if ([] === $redirectArguments && !$operation instanceof DeleteOperationInterface) { + if ( + [] === $redirectArguments && + !$operation instanceof DeleteOperationInterface && + !$operation instanceof BulkOperationInterface + ) { $identifier = $resource->getIdentifier() ?? 'id'; $redirectArguments[$identifier] = 'resource.' . $identifier; diff --git a/src/Component/spec/Symfony/EventListener/FormListenerSpec.php b/src/Component/spec/Symfony/EventListener/FormListenerSpec.php index 4898f8312..792356229 100644 --- a/src/Component/spec/Symfony/EventListener/FormListenerSpec.php +++ b/src/Component/spec/Symfony/EventListener/FormListenerSpec.php @@ -14,162 +14,259 @@ namespace spec\Sylius\Component\Resource\Symfony\EventListener; use PhpSpec\ObjectBehavior; -use Sylius\Component\Resource\Metadata\HttpOperation; +use Sylius\Component\Resource\Context\Context; +use Sylius\Component\Resource\Context\Initiator\RequestContextInitiatorInterface; +use Sylius\Component\Resource\Metadata\BulkUpdate; +use Sylius\Component\Resource\Metadata\Create; +use Sylius\Component\Resource\Metadata\MetadataInterface; use Sylius\Component\Resource\Metadata\Operation\HttpOperationInitiatorInterface; -use Sylius\Component\Resource\Symfony\EventListener\SerializeListener; +use Sylius\Component\Resource\Metadata\Operations; +use Sylius\Component\Resource\Metadata\RegistryInterface; +use Sylius\Component\Resource\Metadata\Show; +use Sylius\Component\Resource\Symfony\EventListener\FormListener; +use Sylius\Component\Resource\Symfony\Form\Factory\FormFactoryInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\Serializer\SerializerInterface; -use Webmozart\Assert\Assert; -final class SerializeListenerSpec extends ObjectBehavior +final class FormListenerSpec extends ObjectBehavior { function let( HttpOperationInitiatorInterface $operationInitiator, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + RegistryInterface $resourceRegistry, + MetadataInterface $metadata, + FormFactoryInterface $formFactory, ): void { - $this->beConstructedWith($operationInitiator, $serializer); + $this->beConstructedWith($operationInitiator, $contextInitiator, $formFactory); } function it_is_initializable(): void { - $this->shouldHaveType(SerializeListener::class); + $this->shouldHaveType(FormListener::class); } - function it_serializes_data_to_the_requested_format( + function it_handles_forms( HttpKernelInterface $kernel, Request $request, - \stdClass $data, + ParameterBag $attributes, HttpOperationInitiatorInterface $operationInitiator, - HttpOperation $operation, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + FormFactoryInterface $formFactory, + FormInterface $form, ): void { $event = new ViewEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $data->getWrappedObject(), + ['foo' => 'fighters'], ); + $request->attributes = $attributes; + $request->getRequestFormat()->willReturn('html'); + + $attributes->get('_route')->willReturn('app_dummy_show'); + $attributes->all('_sylius')->willReturn(['resource' => 'app.dummy']); + + $operation = new Create(formType: 'App\Type\DummyType'); + $operationInitiator->initializeOperation($request)->willReturn($operation); - $request->getRequestFormat()->willReturn('json'); + $operations = new Operations(); + $operations->add('app_dummy_show', $operation); - $serializer->serialize($data, 'json', [])->willReturn('serialized_data')->shouldBeCalled(); + $context = new Context(); + $contextInitiator->initializeContext($request)->willReturn($context); - $this->onKernelView($event); + $formFactory->create($operation, $context, ['foo' => 'fighters']) + ->willReturn($form) + ->shouldBeCalled() + ; - Assert::eq($event->getControllerResult(), 'serialized_data'); + $form->handleRequest($request)->willReturn($form)->shouldBeCalled(); + + $attributes->set('form', $form)->shouldBeCalled(); + + $this->onKernelView($event); } - function it_serializes_data_to_the_requested_format_with_normalization_context( + function it_does_nothing_when_controller_result_is_a_response( HttpKernelInterface $kernel, Request $request, - \stdClass $data, + ParameterBag $attributes, HttpOperationInitiatorInterface $operationInitiator, - HttpOperation $operation, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + FormFactoryInterface $formFactory, + FormInterface $form, + Response $response, ): void { $event = new ViewEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $data->getWrappedObject(), + $response->getWrappedObject(), ); + $request->attributes = $attributes; + $request->getRequestFormat()->willReturn('html'); + + $attributes->get('_route')->willReturn('app_dummy_show'); + $attributes->all('_sylius')->willReturn(['resource' => 'app.dummy']); + + $operation = new Create(formType: 'App\Type\DummyType'); + $operationInitiator->initializeOperation($request)->willReturn($operation); - $request->getRequestFormat()->willReturn('json'); + $operations = new Operations(); + $operations->add('app_dummy_show', $operation); - $operation->getNormalizationContext()->willReturn(['groups' => ['dummy:read']]); + $context = new Context(); + $contextInitiator->initializeContext($request)->willReturn($context); - $serializer->serialize($data, 'json', ['groups' => ['dummy:read']])->willReturn('serialized_data')->shouldBeCalled(); + $formFactory->create($operation, $context, ['foo' => 'fighters']) + ->willReturn($form) + ->shouldNotBeCalled() + ; - $this->onKernelView($event); + $form->handleRequest($request)->willReturn($form)->shouldNotBeCalled(); - Assert::eq($event->getControllerResult(), 'serialized_data'); + $attributes->set('form', $form)->shouldNotBeCalled(); + + $this->onKernelView($event); } - function it_does_nothing_when_operation_is_null( + function it_does_nothing_when_operation_has_no_form_type( HttpKernelInterface $kernel, Request $request, - \stdClass $data, + ParameterBag $attributes, HttpOperationInitiatorInterface $operationInitiator, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + FormFactoryInterface $formFactory, + FormInterface $form, ): void { $event = new ViewEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $data->getWrappedObject(), + ['foo' => 'fighters'], ); - $operationInitiator->initializeOperation($request)->willReturn(null); + $request->attributes = $attributes; + $request->getRequestFormat()->willReturn('html'); - $request->getRequestFormat()->willReturn('json'); + $attributes->get('_route')->willReturn('app_dummy_show'); + $attributes->all('_sylius')->willReturn(['resource' => 'app.dummy']); - $serializer->serialize($data, 'json')->willReturn('serialized_data')->shouldNotBeCalled(); + $operation = new Create(formType: null); - $this->onKernelView($event); + $operationInitiator->initializeOperation($request)->willReturn($operation); + + $operations = new Operations(); + $operations->add('app_dummy_show', $operation); + + $context = new Context(); + $contextInitiator->initializeContext($request)->willReturn($context); + + $formFactory->create($operation, $context, ['foo' => 'fighters']) + ->willReturn($form) + ->shouldNotBeCalled() + ; + + $form->handleRequest($request)->willReturn($form)->shouldNotBeCalled(); + + $attributes->set('form', $form)->shouldNotBeCalled(); - Assert::eq($event->getControllerResult(), $data->getWrappedObject()); + $this->onKernelView($event); } - function it_does_nothing_when_format_is_html( + function it_does_nothing_when_operation_is_not_a_create_or_update( HttpKernelInterface $kernel, Request $request, - \stdClass $data, + ParameterBag $attributes, HttpOperationInitiatorInterface $operationInitiator, - HttpOperation $operation, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + FormFactoryInterface $formFactory, + FormInterface $form, ): void { $event = new ViewEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $data->getWrappedObject(), + ['foo' => 'fighters'], ); + $request->attributes = $attributes; + $request->getRequestFormat()->willReturn('html'); + + $attributes->get('_route')->willReturn('app_dummy_show'); + $attributes->all('_sylius')->willReturn(['resource' => 'app.dummy']); + + $operation = new Show(formType: 'App\Type\DummyType'); + $operationInitiator->initializeOperation($request)->willReturn($operation); - $request->getRequestFormat()->willReturn('html'); + $operations = new Operations(); + $operations->add('app_dummy_show', $operation); - $serializer->serialize($data, 'json', [])->willReturn('serialized_data')->shouldNotBeCalled(); + $context = new Context(); + $contextInitiator->initializeContext($request)->willReturn($context); - $this->onKernelView($event); + $formFactory->create($operation, $context, ['foo' => 'fighters']) + ->willReturn($form) + ->shouldNotBeCalled() + ; + + $form->handleRequest($request)->willReturn($form)->shouldNotBeCalled(); - Assert::eq($event->getControllerResult(), $data->getWrappedObject()); + $attributes->set('form', $form)->shouldNotBeCalled(); + + $this->onKernelView($event); } - function it_throws_an_exception_when_serializer_is_not_available( + function it_does_nothing_when_operation_is_a_bulk_update( HttpKernelInterface $kernel, Request $request, - \stdClass $data, + ParameterBag $attributes, HttpOperationInitiatorInterface $operationInitiator, - HttpOperation $operation, - SerializerInterface $serializer, + RequestContextInitiatorInterface $contextInitiator, + FormFactoryInterface $formFactory, + FormInterface $form, ): void { - $this->beConstructedWith($operationInitiator, null); - $event = new ViewEvent( $kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, - $data->getWrappedObject(), + ['foo' => 'fighters'], ); + $request->attributes = $attributes; + $request->getRequestFormat()->willReturn('html'); + + $attributes->get('_route')->willReturn('app_dummy_show'); + $attributes->all('_sylius')->willReturn(['resource' => 'app.dummy']); + + $operation = new BulkUpdate(formType: 'App\Type\DummyType'); + $operationInitiator->initializeOperation($request)->willReturn($operation); - $request->getRequestFormat()->willReturn('json', []); + $operations = new Operations(); + $operations->add('app_dummy_show', $operation); - $serializer->serialize($data, 'json')->willReturn('serialized_data')->shouldNotBeCalled(); + $context = new Context(); + $contextInitiator->initializeContext($request)->willReturn($context); - $this->shouldThrow(new \LogicException('You can not use the "json" format if the Serializer is not available. Try running "composer require symfony/serializer".')) - ->during( - 'onKernelView', - [$event], - ) + $formFactory->create($operation, $context, ['foo' => 'fighters']) + ->willReturn($form) + ->shouldNotBeCalled() ; + + $form->handleRequest($request)->willReturn($form)->shouldNotBeCalled(); + + $attributes->set('form', $form)->shouldNotBeCalled(); + + $this->onKernelView($event); } } diff --git a/src/Component/spec/Symfony/Routing/Factory/BulkOperationRoutePathFactorySpec.php b/src/Component/spec/Symfony/Routing/Factory/BulkOperationRoutePathFactorySpec.php index f3fa3db05..cb660f35c 100644 --- a/src/Component/spec/Symfony/Routing/Factory/BulkOperationRoutePathFactorySpec.php +++ b/src/Component/spec/Symfony/Routing/Factory/BulkOperationRoutePathFactorySpec.php @@ -15,6 +15,7 @@ use PhpSpec\ObjectBehavior; use Sylius\Component\Resource\Metadata\BulkDelete; +use Sylius\Component\Resource\Metadata\BulkUpdate; use Sylius\Component\Resource\Symfony\Routing\Factory\BulkOperationRoutePathFactory; use Sylius\Component\Resource\Symfony\Routing\Factory\OperationRoutePathFactoryInterface; @@ -36,4 +37,11 @@ function it_generates_route_path_for_bulk_delete_operations(): void $this->createRoutePath($operation, '/dummies')->shouldReturn('/dummies/bulk_delete'); } + + function it_generates_route_path_for_bulk_update_operations(): void + { + $operation = new BulkUpdate(); + + $this->createRoutePath($operation, '/dummies')->shouldReturn('/dummies/bulk_update'); + } } diff --git a/src/Component/spec/Symfony/Routing/Factory/OperationRouteFactorySpec.php b/src/Component/spec/Symfony/Routing/Factory/OperationRouteFactorySpec.php index e1cedac92..86faa7ba8 100644 --- a/src/Component/spec/Symfony/Routing/Factory/OperationRouteFactorySpec.php +++ b/src/Component/spec/Symfony/Routing/Factory/OperationRouteFactorySpec.php @@ -17,6 +17,7 @@ use Prophecy\Argument; use Sylius\Component\Resource\Action\PlaceHolderAction; use Sylius\Component\Resource\Metadata\BulkDelete; +use Sylius\Component\Resource\Metadata\BulkUpdate; use Sylius\Component\Resource\Metadata\Create; use Sylius\Component\Resource\Metadata\Delete; use Sylius\Component\Resource\Metadata\HttpOperation; @@ -190,6 +191,31 @@ function it_generates_bulk_delete_routes( ]); } + function it_generates_bulk_update_routes( + OperationRoutePathFactoryInterface $routePathFactory, + ): void { + $operation = new BulkUpdate(); + + $metadata = Metadata::fromAliasAndConfiguration('app.dummy', ['driver' => 'dummy_driver']); + + $routePathFactory->createRoutePath($operation, 'dummies')->willReturn('dummies/bulk_update')->shouldBeCalled(); + + $route = $this->create( + $metadata, + new Resource('app.dummy'), + $operation, + ); + + $route->getPath()->shouldReturn('/dummies/bulk_update'); + $route->getMethods()->shouldReturn(['PUT', 'PATCH']); + $route->getDefaults()->shouldReturn([ + '_controller' => PlaceHolderAction::class, + '_sylius' => [ + 'resource' => 'app.dummy', + ], + ]); + } + function it_generates_custom_operations_routes( OperationRoutePathFactoryInterface $routePathFactory, ): void { diff --git a/src/Component/spec/Symfony/Routing/RedirectHandlerSpec.php b/src/Component/spec/Symfony/Routing/RedirectHandlerSpec.php index dff322979..2324ca146 100644 --- a/src/Component/spec/Symfony/Routing/RedirectHandlerSpec.php +++ b/src/Component/spec/Symfony/Routing/RedirectHandlerSpec.php @@ -15,6 +15,7 @@ use PhpSpec\ObjectBehavior; use Prophecy\Argument; +use Sylius\Component\Resource\Metadata\BulkUpdate; use Sylius\Component\Resource\Metadata\Create; use Sylius\Component\Resource\Metadata\Delete; use Sylius\Component\Resource\Metadata\Resource; @@ -134,6 +135,21 @@ function it_redirects_to_resource_without_arguments_after_delete_operation_by_de $this->redirectToResource($data, $operation, $request); } + function it_redirects_to_resource_without_arguments_after_bulk_operation_by_default( + \stdClass $data, + Request $request, + RouterInterface $router, + ): void { + $data->id = 'xyz'; + $operation = new BulkUpdate(redirectToRoute: 'app_dummy_index'); + $resource = new Resource(alias: 'app.book'); + $operation = $operation->withResource($resource); + + $router->generate('app_dummy_index', [])->willReturn('/dummies')->shouldBeCalled(); + + $this->redirectToResource($data, $operation, $request); + } + function it_redirects_to_route( \stdClass $data, RouterInterface $router, diff --git a/tests/Application/config/packages/test/sylius_grid.yaml b/tests/Application/config/packages/test/sylius_grid.yaml index 5f32e2125..7184f8cdb 100644 --- a/tests/Application/config/packages/test/sylius_grid.yaml +++ b/tests/Application/config/packages/test/sylius_grid.yaml @@ -6,4 +6,5 @@ sylius_grid: show: 'grid/action/show.html.twig' update: 'grid/action/update.html.twig' bulk_action: + apply_transition: 'grid/bulk_action/apply_transition.html.twig' delete: 'grid/bulk_action/delete.html.twig' diff --git a/tests/Application/src/Subscription/Entity/Subscription.php b/tests/Application/src/Subscription/Entity/Subscription.php index 8af2cc342..0d68249a9 100644 --- a/tests/Application/src/Subscription/Entity/Subscription.php +++ b/tests/Application/src/Subscription/Entity/Subscription.php @@ -19,6 +19,7 @@ use Sylius\Component\Resource\Metadata\Api; use Sylius\Component\Resource\Metadata\ApplyStateMachineTransition; use Sylius\Component\Resource\Metadata\BulkDelete; +use Sylius\Component\Resource\Metadata\BulkUpdate; use Sylius\Component\Resource\Metadata\Create; use Sylius\Component\Resource\Metadata\Delete; use Sylius\Component\Resource\Metadata\Index; @@ -41,6 +42,10 @@ #[BulkDelete] #[ApplyStateMachineTransition(stateMachineTransition: 'accept')] #[ApplyStateMachineTransition(stateMachineTransition: 'reject')] +#[BulkUpdate( + shortName: 'bulk_accept', + stateMachineTransition: 'accept', +)] #[Delete] #[Show( template: 'subscription/show.html.twig', diff --git a/tests/Application/src/Subscription/Grid/SubscriptionGrid.php b/tests/Application/src/Subscription/Grid/SubscriptionGrid.php index 849812d9c..00fcf90c2 100644 --- a/tests/Application/src/Subscription/Grid/SubscriptionGrid.php +++ b/tests/Application/src/Subscription/Grid/SubscriptionGrid.php @@ -71,6 +71,16 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void ->addActionGroup( BulkActionGroup::create( DeleteAction::create(), + Action::create('accept', 'apply_transition') + ->setLabel('Bulk accept') + ->setOptions([ + 'link' => [ + 'route' => 'app_admin_subscription_bulk_accept', + ], + 'class' => 'green', + 'transition' => 'accept', + 'graph' => 'subscription', + ]), ), ) ; diff --git a/tests/Application/src/Tests/Controller/SubscriptionUiTest.php b/tests/Application/src/Tests/Controller/SubscriptionUiTest.php index dc3d34eef..d8bbbdf42 100644 --- a/tests/Application/src/Tests/Controller/SubscriptionUiTest.php +++ b/tests/Application/src/Tests/Controller/SubscriptionUiTest.php @@ -177,6 +177,23 @@ public function it_allows_accepting_a_subscription(): void $this->assertSame('accepted', $subscription->getState()); } + /** @test */ + public function it_allows_accepting_multiple_subscription(): void + { + $this->loadFixturesFromFile('subscriptions.yml'); + + $this->client->request('GET', '/admin/subscriptions'); + $this->client->submitForm('Bulk accept'); + + $this->assertResponseRedirects(null, expectedCode: Response::HTTP_FOUND); + + /** @var Subscription $subscription */ + $subscription = static::getContainer()->get('app.repository.subscription')->findOneBy(['email' => 'marty.mcfly@bttf.com']); + + $this->assertNotNull($subscription); + $this->assertSame('accepted', $subscription->getState()); + } + protected function buildMatcher(): Matcher { return $this->matcherFactory->createMatcher(new VoidBacktrace()); diff --git a/tests/Application/templates/grid/bulk_action/apply_transition.html.twig b/tests/Application/templates/grid/bulk_action/apply_transition.html.twig new file mode 100644 index 000000000..a2996eda0 --- /dev/null +++ b/tests/Application/templates/grid/bulk_action/apply_transition.html.twig @@ -0,0 +1,15 @@ +{% set labeled = true %} +{% set message = action.label %} +{% set path = options.link.url|default(path(options.link.route|default(grid.requestConfiguration.getRouteName('bulk_update')), options.link.parameters|default({}))) %} + +
+ + + + + {% for resource in grid.data %} + + {% endfor %} +
diff --git a/tests/Application/templates/grid/bulk_action/delete.html.twig b/tests/Application/templates/grid/bulk_action/delete.html.twig index bfa9becc4..5b041f979 100644 --- a/tests/Application/templates/grid/bulk_action/delete.html.twig +++ b/tests/Application/templates/grid/bulk_action/delete.html.twig @@ -11,3 +11,4 @@ {% endfor %} + From 8935446c7b3cbc337c9e9af658aa572bfad1e97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 1 Jun 2023 09:44:23 +0200 Subject: [PATCH 04/11] Configure state machine resource metadata collection factory --- .../Resources/config/services/metadata.xml | 21 ++- ...butesResourceMetadataCollectionFactory.php | 13 -- ...chineResourceMetadataCollectionFactory.php | 81 +++++++++ ...sResourceMetadataCollectionFactorySpec.php | 85 +--------- ...eResourceMetadataCollectionFactorySpec.php | 154 ++++++++++++++++++ 5 files changed, 251 insertions(+), 103 deletions(-) create mode 100644 src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php create mode 100644 src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php diff --git a/src/Bundle/Resources/config/services/metadata.xml b/src/Bundle/Resources/config/services/metadata.xml index 144cc6dcc..d459b73bd 100644 --- a/src/Bundle/Resources/config/services/metadata.xml +++ b/src/Bundle/Resources/config/services/metadata.xml @@ -20,18 +20,18 @@ - %sylius.state_machine_component.default% - - + + %sylius.state_machine_component.default% %sylius.resource.settings% + + + + + diff --git a/src/Component/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php b/src/Component/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php index 7aa7eb90a..08bd93806 100644 --- a/src/Component/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php +++ b/src/Component/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactory.php @@ -21,7 +21,6 @@ use Sylius\Component\Resource\Metadata\RegistryInterface; use Sylius\Component\Resource\Metadata\Resource as ResourceMetadata; use Sylius\Component\Resource\Metadata\Resource\ResourceMetadataCollection; -use Sylius\Component\Resource\Metadata\StateMachineAwareOperationInterface; use Sylius\Component\Resource\Reflection\ClassReflection; use Sylius\Component\Resource\Symfony\Request\State\Provider; use Sylius\Component\Resource\Symfony\Request\State\Responder; @@ -32,7 +31,6 @@ final class AttributesResourceMetadataCollectionFactory implements ResourceMetad public function __construct( private RegistryInterface $resourceRegistry, private OperationRouteNameFactory $operationRouteNameFactory, - private ?string $defaultStateMachineComponent, ) { } @@ -184,17 +182,6 @@ private function getOperationWithDefaults(ResourceMetadata $resource, Operation $formOptions = $this->buildFormOptions($operation, $resourceConfiguration); $operation = $operation->withFormOptions($formOptions); - if ( - $operation instanceof StateMachineAwareOperationInterface && - null === $operation->getStateMachineComponent() && - method_exists($resourceConfiguration, 'getStateMachineComponent') - ) { - $stateMachineComponent = $resourceConfiguration->getStateMachineComponent() ?? $this->defaultStateMachineComponent; - - /** @var Operation $operation */ - $operation = $operation->withStateMachineComponent($stateMachineComponent); - } - if ($operation instanceof HttpOperation) { if (null === $operation->getRoutePrefix()) { $operation = $operation->withRoutePrefix($resource->getRoutePrefix() ?? null); diff --git a/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php new file mode 100644 index 000000000..225f89c56 --- /dev/null +++ b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php @@ -0,0 +1,81 @@ +decorated->create($resourceClass); + + /** @var ResourceMetadata $resource */ + foreach ($resourceCollectionMetadata->getIterator() as $i => $resource) { + $resourceConfiguration = $this->resourceRegistry->get($resource->getAlias() ?? ''); + $operations = $resource->getOperations() ?? new Operations(); + + /** @var Operation $operation */ + foreach ($operations as $operation) { + /** @var string $key */ + $key = $operation->getName(); + + $operations->add($key, $this->addDefaults($resourceConfiguration, $operation)); + } + + $resource = $resource->withOperations($operations); + + $resourceCollectionMetadata[$i] = $resource; + } + + return $resourceCollectionMetadata; + } + + private function addDefaults(MetadataInterface $resourceConfiguration, Operation $operation): Operation + { + if ( + $operation instanceof StateMachineAwareOperationInterface && + null === $operation->getStateMachineComponent() && + method_exists($resourceConfiguration, 'getStateMachineComponent') + ) { + $stateMachineComponent = $resourceConfiguration->getStateMachineComponent() ?? $this->defaultStateMachineComponent; + + /** @var Operation $operation */ + $operation = $operation->withStateMachineComponent($stateMachineComponent); + + if ( + null !== $operation->getStateMachineTransition() && + null === $operation->getProcessor() + ) { + $operation = $operation->withProcessor(ApplyStateMachineTransitionProcessor::class); + } + } + + return $operation; + } +} diff --git a/src/Component/spec/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactorySpec.php b/src/Component/spec/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactorySpec.php index 3fe66d894..1dbbd6971 100644 --- a/src/Component/spec/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactorySpec.php +++ b/src/Component/spec/Metadata/Resource/Factory/AttributesResourceMetadataCollectionFactorySpec.php @@ -50,7 +50,7 @@ final class AttributesResourceMetadataCollectionFactorySpec extends ObjectBehavi { function let(RegistryInterface $resourceRegistry): void { - $this->beConstructedWith($resourceRegistry, new OperationRouteNameFactory(), 'symfony'); + $this->beConstructedWith($resourceRegistry, new OperationRouteNameFactory()); } function it_is_initializable(): void @@ -643,89 +643,6 @@ function it_creates_resource_metadata_with_route_prefix(RegistryInterface $resou $operation->getRoutePrefix()->shouldReturn('/admin'); } - function it_creates_resource_metadata_with_configured_state_machine_component(RegistryInterface $resourceRegistry): void - { - $resourceRegistry->get('app.dummy')->willReturn(Metadata::fromAliasAndConfiguration('app.dummy', [ - 'driver' => 'dummy_driver', - 'state_machine_component' => 'winzou', - 'classes' => [ - 'model' => 'App\Dummy', - 'form' => 'App\Form', - ], - ])); - - $metadataCollection = $this->create(DummyResourceWithRoutePrefix::class); - $metadataCollection->shouldHaveType(ResourceMetadataCollection::class); - - $resource = $metadataCollection->getIterator()->current(); - $resource->shouldHaveType(Resource::class); - $resource->getAlias()->shouldReturn('app.dummy'); - - $operations = $resource->getOperations(); - $operations->shouldHaveType(Operations::class); - - $operations->count()->shouldReturn(4); - $operations->has('app_dummy_create')->shouldReturn(true); - $operations->has('app_dummy_update')->shouldReturn(true); - $operations->has('app_dummy_index')->shouldReturn(true); - $operations->has('app_dummy_show')->shouldReturn(true); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_create'); - $operation->shouldHaveType(Create::class); - $operation->getStateMachineComponent()->shouldReturn('winzou'); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_update'); - $operation->shouldHaveType(Update::class); - $operation->getStateMachineComponent()->shouldReturn('winzou'); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_index'); - $operation->shouldHaveType(Index::class); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_show'); - $operation->shouldHaveType(Show::class); - } - - function it_creates_resource_metadata_with_default_state_machine_component(RegistryInterface $resourceRegistry): void - { - $resourceRegistry->get('app.dummy')->willReturn(Metadata::fromAliasAndConfiguration('app.dummy', [ - 'driver' => 'dummy_driver', - 'classes' => [ - 'model' => 'App\Dummy', - 'form' => 'App\Form', - ], - ])); - - $metadataCollection = $this->create(DummyResourceWithRoutePrefix::class); - $metadataCollection->shouldHaveType(ResourceMetadataCollection::class); - - $resource = $metadataCollection->getIterator()->current(); - $resource->shouldHaveType(Resource::class); - $resource->getAlias()->shouldReturn('app.dummy'); - - $operations = $resource->getOperations(); - $operations->shouldHaveType(Operations::class); - - $operations->count()->shouldReturn(4); - $operations->has('app_dummy_create')->shouldReturn(true); - $operations->has('app_dummy_update')->shouldReturn(true); - $operations->has('app_dummy_index')->shouldReturn(true); - $operations->has('app_dummy_show')->shouldReturn(true); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_create'); - $operation->shouldHaveType(Create::class); - $operation->getStateMachineComponent()->shouldReturn('symfony'); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_update'); - $operation->shouldHaveType(Update::class); - $operation->getStateMachineComponent()->shouldReturn('symfony'); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_index'); - $operation->shouldHaveType(Index::class); - - $operation = $metadataCollection->getOperation('app.dummy', 'app_dummy_show'); - $operation->shouldHaveType(Show::class); - } - function it_creates_resource_metadata_with_normalization_context(RegistryInterface $resourceRegistry): void { $resourceRegistry->get('app.dummy')->willReturn(Metadata::fromAliasAndConfiguration('app.dummy', [ diff --git a/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php b/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php new file mode 100644 index 000000000..7dc9afcf9 --- /dev/null +++ b/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php @@ -0,0 +1,154 @@ +beConstructedWith($resourceRegistry, $decorated, null); + } + + function it_is_initializable(): void + { + $this->shouldHaveType(StateMachineResourceMetadataCollectionFactory::class); + } + + function it_sets_the_default_state_machine_component_from_settings( + RegistryInterface $resourceRegistry, + ResourceMetadataCollectionFactoryInterface $decorated, + MetadataInterface $resourceConfiguration, + ): void { + $this->beConstructedWith($resourceRegistry, $decorated, 'symfony'); + + $resource = new Resource(alias: 'app.book', name: 'book', applicationName: 'app'); + + $create = (new Create(name: 'app_book_create'))->withResource($resource); + + $resource = $resource->withOperations(new Operations([ + $create->getName() => $create, + ])); + + $resourceMetadataCollection = new ResourceMetadataCollection(); + $resourceMetadataCollection[] = $resource; + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.book')->willReturn($resourceConfiguration); + + $resourceConfiguration->getStateMachineComponent()->willReturn(null); + + $resourceMetadataCollection = $this->create('App\Resource'); + + $create = $resourceMetadataCollection->getOperation('app.book', 'app_book_create'); + $create->getStateMachineComponent()->shouldReturn('symfony'); + } + + function it_sets_the_default_state_machine_component_from_resource_configuration( + RegistryInterface $resourceRegistry, + ResourceMetadataCollectionFactoryInterface $decorated, + MetadataInterface $resourceConfiguration, + ): void { + $resource = new Resource(alias: 'app.book', name: 'book', applicationName: 'app'); + + $create = (new Create(name: 'app_book_create'))->withResource($resource); + + $resource = $resource->withOperations(new Operations([ + $create->getName() => $create, + ])); + + $resourceMetadataCollection = new ResourceMetadataCollection(); + $resourceMetadataCollection[] = $resource; + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.book')->willReturn($resourceConfiguration); + + $resourceConfiguration->getStateMachineComponent()->willReturn('symfony'); + + $resourceMetadataCollection = $this->create('App\Resource'); + + $create = $resourceMetadataCollection->getOperation('app.book', 'app_book_create'); + $create->getStateMachineComponent()->shouldReturn('symfony'); + } + + function it_sets_the_configured_state_machine_component_from_operation( + RegistryInterface $resourceRegistry, + ResourceMetadataCollectionFactoryInterface $decorated, + MetadataInterface $resourceConfiguration, + ): void { + $resource = new Resource(alias: 'app.book', name: 'book', applicationName: 'app'); + + $create = (new Create(name: 'app_book_create', stateMachineComponent: 'winzou'))->withResource($resource); + + $resource = $resource->withOperations(new Operations([ + $create->getName() => $create, + ])); + + $resourceMetadataCollection = new ResourceMetadataCollection(); + $resourceMetadataCollection[] = $resource; + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.book')->willReturn($resourceConfiguration); + + $resourceConfiguration->getStateMachineComponent()->willReturn('symfony'); + + $resourceMetadataCollection = $this->create('App\Resource'); + + $create = $resourceMetadataCollection->getOperation('app.book', 'app_book_create'); + $create->getStateMachineComponent()->shouldReturn('winzou'); + } + + function it_configures_apply_state_machine_transition_processor_if_operation_has_a_transition( + RegistryInterface $resourceRegistry, + ResourceMetadataCollectionFactoryInterface $decorated, + MetadataInterface $resourceConfiguration, + ): void { + $resource = new Resource(alias: 'app.book', name: 'book', applicationName: 'app'); + + $create = (new Create(name: 'app_book_create', stateMachineTransition: 'publish'))->withResource($resource); + + $resource = $resource->withOperations(new Operations([ + $create->getName() => $create, + ])); + + $resourceMetadataCollection = new ResourceMetadataCollection(); + $resourceMetadataCollection[] = $resource; + + $decorated->create('App\Resource')->willReturn($resourceMetadataCollection); + + $resourceRegistry->get('app.book')->willReturn($resourceConfiguration); + + $resourceConfiguration->getStateMachineComponent()->willReturn('symfony'); + + $resourceMetadataCollection = $this->create('App\Resource'); + + $create = $resourceMetadataCollection->getOperation('app.book', 'app_book_create'); + $create->getProcessor()->shouldReturn(ApplyStateMachineTransitionProcessor::class); + } +} From 75135ebfba424cb9cbcc1fd74d20d726f7a0fbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 1 Jun 2023 09:53:27 +0200 Subject: [PATCH 05/11] Fix Psalm error --- ...achineResourceMetadataCollectionFactory.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php index 225f89c56..9d4ebeeda 100644 --- a/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php +++ b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php @@ -58,8 +58,11 @@ public function create(string $resourceClass): ResourceMetadataCollection private function addDefaults(MetadataInterface $resourceConfiguration, Operation $operation): Operation { + if (!$operation instanceof StateMachineAwareOperationInterface) { + return $operation; + } + if ( - $operation instanceof StateMachineAwareOperationInterface && null === $operation->getStateMachineComponent() && method_exists($resourceConfiguration, 'getStateMachineComponent') ) { @@ -67,13 +70,14 @@ private function addDefaults(MetadataInterface $resourceConfiguration, Operation /** @var Operation $operation */ $operation = $operation->withStateMachineComponent($stateMachineComponent); + } - if ( - null !== $operation->getStateMachineTransition() && - null === $operation->getProcessor() - ) { - $operation = $operation->withProcessor(ApplyStateMachineTransitionProcessor::class); - } + if ( + method_exists($operation, 'getStateMachineTransition') && + null !== $operation->getStateMachineTransition() && + null === $operation->getProcessor() + ) { + $operation = $operation->withProcessor(ApplyStateMachineTransitionProcessor::class); } return $operation; From 864dfe65c2a1e6dfaa7d71a4a31f734d8d03aafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 1 Jun 2023 10:54:01 +0200 Subject: [PATCH 06/11] Remove processor on apply state machine transition --- src/Component/Metadata/ApplyStateMachineTransition.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Component/Metadata/ApplyStateMachineTransition.php b/src/Component/Metadata/ApplyStateMachineTransition.php index 278cf7307..1974d3a8a 100644 --- a/src/Component/Metadata/ApplyStateMachineTransition.php +++ b/src/Component/Metadata/ApplyStateMachineTransition.php @@ -13,8 +13,6 @@ namespace Sylius\Component\Resource\Metadata; -use Sylius\Component\Resource\StateMachine\State\ApplyStateMachineTransitionProcessor; - /** * @experimental */ @@ -52,7 +50,7 @@ public function __construct( shortName: $shortName ?? $stateMachineTransition ?? 'apply_state_machine_transition', name: $name, provider: $provider, - processor: $processor ?? ApplyStateMachineTransitionProcessor::class, + processor: $processor, responder: $responder, repository: $repository, repositoryMethod: $repositoryMethod, From 7a72f9edc9a1850c05f2654407c49d59c3decdc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 22 Jun 2023 09:25:51 +0200 Subject: [PATCH 07/11] Fix coding standard --- src/Component/Metadata/BulkUpdate.php | 2 +- .../Factory/StateMachineResourceMetadataCollectionFactory.php | 2 +- .../StateMachineResourceMetadataCollectionFactorySpec.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Component/Metadata/BulkUpdate.php b/src/Component/Metadata/BulkUpdate.php index bf3556525..e7a0f292b 100644 --- a/src/Component/Metadata/BulkUpdate.php +++ b/src/Component/Metadata/BulkUpdate.php @@ -3,7 +3,7 @@ /* * This file is part of the Sylius package. * - * (c) Paweł Jędrzejewski + * (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. diff --git a/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php index 9d4ebeeda..4bcd436a1 100644 --- a/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php +++ b/src/Component/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactory.php @@ -3,7 +3,7 @@ /* * This file is part of the Sylius package. * - * (c) Paweł Jędrzejewski + * (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. diff --git a/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php b/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php index 7dc9afcf9..f61e18b25 100644 --- a/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php +++ b/src/Component/spec/Metadata/Resource/Factory/StateMachineResourceMetadataCollectionFactorySpec.php @@ -3,7 +3,7 @@ /* * This file is part of the Sylius package. * - * (c) Paweł Jędrzejewski + * (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. From 82e10a6db4bc7590216532e26126bd381e3e136e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 22 Jun 2023 09:28:17 +0200 Subject: [PATCH 08/11] Fix flash helper unused code --- .../Symfony/Session/Flash/FlashHelper.php | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/Component/Symfony/Session/Flash/FlashHelper.php b/src/Component/Symfony/Session/Flash/FlashHelper.php index b6cecf67c..4a5d8b79d 100644 --- a/src/Component/Symfony/Session/Flash/FlashHelper.php +++ b/src/Component/Symfony/Session/Flash/FlashHelper.php @@ -101,27 +101,6 @@ private function addFlash(string $message, string $type, Context $context): void $flashBag->add($type, $message); } - private function buildMessage(Operation $operation, string $type): string - { - $resource = $operation->getResource(); - Assert::notNull($resource); - - $specifyKey = sprintf('%s.%s.%s', $resource->getApplicationName() ?? '', $resource->getName() ?? '', $operation->getShortName() ?? ''); - $defaultKey = sprintf('sylius.resource.%s', $operation->getShortName() ?? ''); - - $parameters = $this->getTranslationParameters($operation); - - if (!$this->translator instanceof TranslatorBagInterface) { - return $this->translator->trans($defaultKey, $parameters, 'flashes'); - } - - if ($this->translator->getCatalogue()->has($specifyKey, 'flashes')) { - return $this->translator->trans($specifyKey, $parameters, 'flashes'); - } - - return $this->translator->trans($defaultKey, $parameters, 'flashes'); - } - private function getTranslationParameters(Operation $operation): array { $resource = $operation->getResource(); From 2e34e82402480e87bbfd0676b24934516877dc83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 22 Jun 2023 10:43:49 +0200 Subject: [PATCH 09/11] Remove extra blank lines --- .../templates/subscription/grid/bulk_action/accept.html.twig | 1 - tests/Application/templates/grid/bulk_action/delete.html.twig | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig b/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig index 646a3b17b..1d3137d6a 100644 --- a/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig +++ b/src/Bundle/test/templates/subscription/grid/bulk_action/accept.html.twig @@ -11,4 +11,3 @@ {% endfor %} - diff --git a/tests/Application/templates/grid/bulk_action/delete.html.twig b/tests/Application/templates/grid/bulk_action/delete.html.twig index 5b041f979..bfa9becc4 100644 --- a/tests/Application/templates/grid/bulk_action/delete.html.twig +++ b/tests/Application/templates/grid/bulk_action/delete.html.twig @@ -11,4 +11,3 @@ {% endfor %} - From ec94944a56ec995b519542f8e54ab8c69baa11b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 22 Jun 2023 10:52:14 +0200 Subject: [PATCH 10/11] Improve testing with multiple subscriptions --- .../Tests/Controller/SubscriptionUiTest.php | 19 +++++++++++++++---- .../Tests/DataFixtures/ORM/subscriptions.yml | 3 +++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/Application/src/Tests/Controller/SubscriptionUiTest.php b/tests/Application/src/Tests/Controller/SubscriptionUiTest.php index d8bbbdf42..ccdcb93ff 100644 --- a/tests/Application/src/Tests/Controller/SubscriptionUiTest.php +++ b/tests/Application/src/Tests/Controller/SubscriptionUiTest.php @@ -56,6 +56,11 @@ public function it_allows_browsing_subscriptions(): void $this->assertStringContainsString(sprintf('Show', $subscriptions['subscription_doc']->getId()), $content); $this->assertStringContainsString(sprintf('Edit', $subscriptions['subscription_doc']->getId()), $content); $this->assertStringContainsString(sprintf('
', $subscriptions['subscription_doc']->getId()), $content); + + $this->assertStringContainsString('biff.tannen@bttf.com', $content); + $this->assertStringContainsString(sprintf('Show', $subscriptions['subscription_biff']->getId()), $content); + $this->assertStringContainsString(sprintf('Edit', $subscriptions['subscription_biff']->getId()), $content); + $this->assertStringContainsString(sprintf('', $subscriptions['subscription_biff']->getId()), $content); } /** @test */ @@ -187,11 +192,17 @@ public function it_allows_accepting_multiple_subscription(): void $this->assertResponseRedirects(null, expectedCode: Response::HTTP_FOUND); - /** @var Subscription $subscription */ - $subscription = static::getContainer()->get('app.repository.subscription')->findOneBy(['email' => 'marty.mcfly@bttf.com']); + /** @var Subscription $firstSubscription */ + $firstSubscription = static::getContainer()->get('app.repository.subscription')->findOneBy(['email' => 'marty.mcfly@bttf.com']); - $this->assertNotNull($subscription); - $this->assertSame('accepted', $subscription->getState()); + /** @var Subscription $secondSubscription */ + $secondSubscription = static::getContainer()->get('app.repository.subscription')->findOneBy(['email' => 'doc.brown@bttf.com']); + + $this->assertNotNull($firstSubscription); + $this->assertSame('accepted', $firstSubscription->getState()); + + $this->assertNotNull($secondSubscription); + $this->assertSame('accepted', $secondSubscription->getState()); } protected function buildMatcher(): Matcher diff --git a/tests/Application/src/Tests/DataFixtures/ORM/subscriptions.yml b/tests/Application/src/Tests/DataFixtures/ORM/subscriptions.yml index 079cc63e7..0818fcf5f 100644 --- a/tests/Application/src/Tests/DataFixtures/ORM/subscriptions.yml +++ b/tests/Application/src/Tests/DataFixtures/ORM/subscriptions.yml @@ -3,3 +3,6 @@ App\Subscription\Entity\Subscription: email: 'marty.mcfly@bttf.com' subscription_doc: email: 'doc.brown@bttf.com' + subscription_biff: + email: 'biff.tannen@bttf.com' + state: accepted From af51e898963330334108b0772c58fc18d30965ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Fr=C3=A9mont?= Date: Thu, 22 Jun 2023 11:05:51 +0200 Subject: [PATCH 11/11] Fix PHPUnit tests --- .../src/Tests/Responses/subscriptions/index_response.json | 6 +++++- .../src/Tests/Responses/subscriptions/index_response.xml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/Application/src/Tests/Responses/subscriptions/index_response.json b/tests/Application/src/Tests/Responses/subscriptions/index_response.json index dd0f5667c..c18dd6d07 100644 --- a/tests/Application/src/Tests/Responses/subscriptions/index_response.json +++ b/tests/Application/src/Tests/Responses/subscriptions/index_response.json @@ -7,6 +7,10 @@ { "state": "new", "email": "doc.brown@bttf.com" + }, + { + "state": "accepted", + "email": "biff.tannen@bttf.com" } ], "pagination": { @@ -14,7 +18,7 @@ "has_previous_page": false, "has_next_page": false, "per_page": 10, - "total_items": 2, + "total_items": 3, "total_pages": 1 } } diff --git a/tests/Application/src/Tests/Responses/subscriptions/index_response.xml b/tests/Application/src/Tests/Responses/subscriptions/index_response.xml index 1617f6b78..d109f4616 100644 --- a/tests/Application/src/Tests/Responses/subscriptions/index_response.xml +++ b/tests/Application/src/Tests/Responses/subscriptions/index_response.xml @@ -8,12 +8,16 @@ new doc.brown@bttf.com + + accepted + biff.tannen@bttf.com + 1 0 0 10 - 2 + 3 1