diff --git a/src/Bundle/spec/Controller/DisabledAuthorizationCheckerSpec.php b/src/Bundle/spec/Controller/DisabledAuthorizationCheckerSpec.php deleted file mode 100644 index 6a8d07a9f..000000000 --- a/src/Bundle/spec/Controller/DisabledAuthorizationCheckerSpec.php +++ /dev/null @@ -1,33 +0,0 @@ -shouldImplement(AuthorizationCheckerInterface::class); - } - - function it_always_returns_true(RequestConfiguration $requestConfiguration): void - { - $this->isGranted($requestConfiguration, 'create')->shouldReturn(true); - $this->isGranted($requestConfiguration, 'update')->shouldReturn(true); - $this->isGranted($requestConfiguration, 'custom')->shouldReturn(true); - } -} diff --git a/src/Bundle/spec/Controller/EventDispatcherSpec.php b/src/Bundle/spec/Controller/EventDispatcherSpec.php deleted file mode 100644 index e690f350f..000000000 --- a/src/Bundle/spec/Controller/EventDispatcherSpec.php +++ /dev/null @@ -1,150 +0,0 @@ -beConstructedWith($eventDispatcher); - } - - function it_implements_event_dispatcher_interface(): void - { - $this->shouldImplement(ControllerEventDispatcherInterface::class); - } - - function it_dispatches_appropriate_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn(null); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.show')->shouldBeCalled(); - - $this->dispatch(ResourceActions::SHOW, $requestConfiguration, $resource)->shouldHaveType(ResourceControllerEvent::class); - } - - function it_dispatches_appropriate_custom_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn('register'); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.register')->shouldBeCalled(); - - $this->dispatch(ResourceActions::CREATE, $requestConfiguration, $resource)->shouldHaveType(ResourceControllerEvent::class); - } - - function it_dispatches_event_for_a_collection_of_resources( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - Collection $resources, - ): void { - $requestConfiguration->getEvent()->willReturn('register'); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.register')->shouldBeCalled(); - - $this->dispatchMultiple(ResourceActions::CREATE, $requestConfiguration, $resources)->shouldHaveType(ResourceControllerEvent::class); - } - - function it_dispatches_appropriate_pre_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn(null); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.pre_create')->shouldBeCalled(); - - $this->dispatchPreEvent(ResourceActions::CREATE, $requestConfiguration, $resource); - } - - function it_dispatches_appropriate_custom_pre_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn('register'); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.pre_register')->shouldBeCalled(); - - $this->dispatchPreEvent(ResourceActions::CREATE, $requestConfiguration, $resource); - } - - function it_dispatches_appropriate_post_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn(null); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.post_create')->shouldBeCalled(); - - $this->dispatchPostEvent(ResourceActions::CREATE, $requestConfiguration, $resource); - } - - function it_dispatches_appropriate_custom_post_event_for_a_resource( - RequestConfiguration $requestConfiguration, - MetadataInterface $metadata, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource, - ): void { - $requestConfiguration->getEvent()->willReturn('register'); - $requestConfiguration->getMetadata()->willReturn($metadata); - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $eventDispatcher->dispatch(Argument::type(ResourceControllerEvent::class), 'sylius.product.post_register')->shouldBeCalled(); - - $this->dispatchPostEvent(ResourceActions::CREATE, $requestConfiguration, $resource)->shouldHaveType(ResourceControllerEvent::class); - } -} diff --git a/src/Bundle/spec/Controller/FlashHelperSpec.php b/src/Bundle/spec/Controller/FlashHelperSpec.php deleted file mode 100644 index f951280b2..000000000 --- a/src/Bundle/spec/Controller/FlashHelperSpec.php +++ /dev/null @@ -1,273 +0,0 @@ -beConstructedWith($requestStack, $translator, 'en'); - - return; - } - - $this->beConstructedWith($session, $translator, 'en'); - } - - function it_implements_flash_helper_interface(): void - { - $this->shouldImplement(FlashHelperInterface::class); - } - - function it_adds_resource_message_by_default( - RequestStack $requestStack, - SessionInterface $session, - TranslatorBagInterface $translator, - MessageCatalogueInterface $messageCatalogue, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getHumanizedName()->willReturn('product'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $translator->getCatalogue('en')->willReturn($messageCatalogue); - $messageCatalogue->has('sylius.product.create', 'flashes')->willReturn(false); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add( - 'success', - [ - 'message' => 'sylius.resource.create', - 'parameters' => ['%resource%' => 'Product'], - ], - )->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, ResourceActions::CREATE, $resource); - } - - function it_adds_resource_message_when_catalogue_is_unavailable_and_given_message_cannot_be_translated( - RequestStack $requestStack, - SessionInterface $session, - TranslatorInterface $translator, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $parameters = ['%resource%' => 'Product']; - - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getHumanizedName()->willReturn('product'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $translator->trans('sylius.product.create', $parameters, 'flashes')->willReturn('sylius.product.create'); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add( - 'success', - [ - 'message' => 'sylius.resource.create', - 'parameters' => $parameters, - ], - )->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, ResourceActions::CREATE, $resource); - } - - function it_adds_resource_message_when_catalogue_is_unavailable_and_given_message_can_be_translated( - RequestStack $requestStack, - SessionInterface $session, - TranslatorInterface $translator, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $parameters = ['%resource%' => 'Spoon']; - - $metadata->getApplicationName()->willReturn('app'); - $metadata->getHumanizedName()->willReturn('spoon'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage(ResourceActions::CREATE) - ->willReturn('%resource% is the best cutlery of them all!') - ; - - $translator->trans('%resource% is the best cutlery of them all!', $parameters, 'flashes') - ->willReturn('Spoon is the best cutlery of them all!') - ; - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add( - 'success', - [ - 'message' => '%resource% is the best cutlery of them all!', - 'parameters' => $parameters, - ], - )->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, ResourceActions::CREATE, $resource); - } - - function it_adds_resource_message_if_message_was_not_found_in_the_catalogue( - RequestStack $requestStack, - SessionInterface $session, - TranslatorBagInterface $translator, - MessageCatalogueInterface $messageCatalogue, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getHumanizedName()->willReturn('product'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $translator->getCatalogue('en')->willReturn($messageCatalogue); - - $messageCatalogue->has('sylius.product.create', 'flashes')->willReturn(false); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add( - 'success', - [ - 'message' => 'sylius.resource.create', - 'parameters' => ['%resource%' => 'Product'], - ], - )->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, ResourceActions::CREATE, $resource); - } - - function it_adds_overwritten_message( - RequestStack $requestStack, - SessionInterface $session, - TranslatorBagInterface $translator, - MessageCatalogueInterface $messageCatalogue, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getHumanizedName()->willReturn('product'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $translator->getCatalogue('en')->willReturn($messageCatalogue); - - $messageCatalogue->has('sylius.product.create', 'flashes')->willReturn(true); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add('success', 'sylius.product.create')->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, ResourceActions::CREATE, $resource); - } - - function it_adds_custom_message( - RequestStack $requestStack, - SessionInterface $session, - TranslatorBagInterface $translator, - MessageCatalogueInterface $messageCatalogue, - FlashBagInterface $flashBag, - MetadataInterface $metadata, - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - ): void { - $metadata->getApplicationName()->willReturn('app'); - $metadata->getHumanizedName()->willReturn('book'); - - $requestConfiguration->getMetadata()->willReturn($metadata); - $requestConfiguration->getFlashMessage('send')->willReturn('app.book.send'); - - $translator->getCatalogue('en')->willReturn($messageCatalogue); - - $messageCatalogue->has('app.book.send', 'flashes')->willReturn(true); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - $flashBag->add('success', 'app.book.send')->shouldBeCalled(); - - $this->addSuccessFlash($requestConfiguration, 'send', $resource); - } - - function it_adds_message_from_event( - RequestStack $requestStack, - SessionInterface $session, - FlashBagInterface $flashBag, - RequestConfiguration $requestConfiguration, - ResourceControllerEvent $event, - ): void { - $event->getMessage()->willReturn('sylius.channel.cannot_be_deleted'); - $event->getMessageType()->willReturn(ResourceControllerEvent::TYPE_WARNING); - $event->getMessageParameters()->willReturn(['%name%' => 'Germany Sylius Webshop']); - - if (method_exists(RequestStack::class, 'getSession')) { - $requestStack->getSession()->willReturn($session)->shouldBeCalled(); - } - $session->getBag('flashes')->willReturn($flashBag); - - $flashBag->add( - ResourceControllerEvent::TYPE_WARNING, - [ - 'message' => 'sylius.channel.cannot_be_deleted', - 'parameters' => ['%name%' => 'Germany Sylius Webshop'], - ], - )->shouldBeCalled(); - - $this->addFlashFromEvent($requestConfiguration, $event); - } -} diff --git a/src/Bundle/spec/Controller/NewResourceFactorySpec.php b/src/Bundle/spec/Controller/NewResourceFactorySpec.php deleted file mode 100644 index 00ae92269..000000000 --- a/src/Bundle/spec/Controller/NewResourceFactorySpec.php +++ /dev/null @@ -1,68 +0,0 @@ -shouldImplement(NewResourceFactoryInterface::class); - } - - function it_calls_create_new_by_default_if_no_custom_method_configured( - RequestConfiguration $requestConfiguration, - FactoryInterface $factory, - ResourceInterface $resource, - ): void { - $requestConfiguration->getFactoryMethod()->willReturn(null); - - $factory->createNew()->willReturn($resource); - - $this->create($requestConfiguration, $factory)->shouldReturn($resource); - } - - function it_calls_proper_factory_methods_based_on_configuration( - RequestConfiguration $requestConfiguration, - FactoryInterface $factory, - ResourceInterface $resource, - ): void { - $requestConfiguration->getFactoryMethod()->willReturn('createNew'); - $requestConfiguration->getFactoryArguments()->willReturn(['00032']); - - $factory->createNew('00032')->willReturn($resource); - - $this->create($requestConfiguration, $factory)->shouldReturn($resource); - } - - function it_calls_proper_service_based_on_configuration( - RequestConfiguration $requestConfiguration, - FactoryInterface $factory, - FactoryInterface $customFactory, - ResourceInterface $resource, - ): void { - $requestConfiguration->getFactoryMethod()->willReturn([$customFactory, 'createNew']); - $requestConfiguration->getFactoryArguments()->willReturn(['foo', 'bar']); - - $customFactory->createNew('foo', 'bar')->willReturn($resource); - $factory->createNew()->shouldNotBeCalled(); - - $this->create($requestConfiguration, $factory)->shouldReturn($resource); - } -} diff --git a/src/Bundle/spec/Controller/ParametersParserSpec.php b/src/Bundle/spec/Controller/ParametersParserSpec.php deleted file mode 100644 index 8da5ba950..000000000 --- a/src/Bundle/spec/Controller/ParametersParserSpec.php +++ /dev/null @@ -1,206 +0,0 @@ -beConstructedWith(new Container(), new ExpressionLanguage()); - } - - function it_implements_parameters_parser_interface(): void - { - $this->shouldImplement(ParametersParserInterface::class); - } - - function it_parses_string_parameters(): void - { - $request = new Request(); - $request->request->set('string', 'Lorem ipsum'); - - $this - ->parseRequestValues(['nested' => ['string' => '$string']], $request) - ->shouldReturn(['nested' => ['string' => 'Lorem ipsum']]) - ; - } - - function it_parses_boolean_parameters(): void - { - $request = new Request(); - $request->request->set('boolean', true); - - $this - ->parseRequestValues(['nested' => ['boolean' => '$boolean']], $request) - ->shouldReturn(['nested' => ['boolean' => true]]) - ; - } - - function it_parses_array_parameters(): void - { - $request = new Request(); - $request->request->set('array', ['foo' => 'bar']); - - $this - ->parseRequestValues(['nested' => ['array' => '$array']], $request) - ->shouldReturn(['nested' => ['array' => ['foo' => 'bar']]]) - ; - } - - function it_parses_string_parameter_and_casts_it_into_int(): void - { - $request = new Request(); - $request->request->set('int', '5'); - - $this - ->parseRequestValues(['nested' => ['int' => '!!int $int']], $request) - ->shouldReturn(['nested' => ['int' => 5]]) - ; - } - - function it_parses_string_parameter_and_casts_it_into_float(): void - { - $request = new Request(); - $request->request->set('float', '5.4'); - - $this - ->parseRequestValues(['nested' => ['float' => '!!float $float']], $request) - ->shouldReturn(['nested' => ['float' => 5.4]]) - ; - } - - function it_throws_exception_if_string_parameter_is_going_to_be_casted_into_invalid_type() - { - $request = new Request(); - $request->request->set('int', 5); - - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('parseRequestValues', [['nested' => ['int' => '!!invalid $int']], $request]) - ; - } - - function it_throws_exception_if_invalid_typecast_is_provided() - { - $request = new Request(); - $request->request->set('int', 5); - - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('parseRequestValues', [['nested' => ['int' => '!!!int $int']], $request]) - ; - - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('parseRequestValues', [['nested' => ['int' => '!!int!! $int']], $request]) - ; - } - - function it_parses_string_parameter_and_casts_it_into_bool(): void - { - $request = new Request(); - $request->request->set('bool0', '0'); - $request->request->set('bool1', '1'); - - $this - ->parseRequestValues(['nested' => ['bool' => '!!bool $bool0']], $request) - ->shouldReturn(['nested' => ['bool' => false]]) - ; - - $this - ->parseRequestValues(['nested' => ['bool' => '!!bool $bool1']], $request) - ->shouldReturn(['nested' => ['bool' => true]]) - ; - } - - function it_parses_an_expression_and_casts_it_into_a_given_type(): void - { - $request = new Request(); - - $this - ->parseRequestValues(['nested' => ['cast' => '!!int expr:"5"']], $request) - ->shouldReturn(['nested' => ['cast' => 5]]) - ; - } - - function it_parses_an_expression_with_spaces_and_casts_it_into_a_given_type(): void - { - $request = new Request(); - - $this - ->parseRequestValues(['nested' => ['cast' => '!!int expr:"5" + "5"']], $request) - ->shouldReturn(['nested' => ['cast' => 10]]) - ; - } - - function it_parses_expressions(): void - { - $request = new Request(); - - $this - ->parseRequestValues(['nested' => ['boolean' => 'expr:"foo" in ["foo", "bar"]']], $request) - ->shouldReturn(['nested' => ['boolean' => true]]) - ; - } - - function it_parses_expressions_with_string_parameters(): void - { - $request = new Request(); - $request->request->set('string', 'lorem ipsum'); - - $this - ->parseRequestValues(['expression' => 'expr:$string === "lorem ipsum"'], $request) - ->shouldReturn(['expression' => true]) - ; - } - - function it_parses_expressions_with_scalar_parameters(): void - { - $request = new Request(); - $request->request->set('number', 6); - - $this - ->parseRequestValues(['expression' => 'expr:$number === 6'], $request) - ->shouldReturn(['expression' => true]) - ; - } - - function it_throws_an_exception_if_array_parameter_is_injected_into_expression(): void - { - $request = new Request(); - $request->request->set('array', ['foo', 'bar']); - - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('parseRequestValues', [['expression' => 'expr:"foo" in $array'], $request]) - ; - } - - function it_throws_an_exception_if_object_parameter_is_injected_into_expression(\Stringable $object): void - { - $request = new Request(); - $request->request->set('object', $object->getWrappedObject()); - - $this - ->shouldThrow(\InvalidArgumentException::class) - ->during('parseRequestValues', [['expression' => 'expr:$object.callMethod()'], $request]) - ; - } -} diff --git a/src/Bundle/spec/Controller/ParametersSpec.php b/src/Bundle/spec/Controller/ParametersSpec.php deleted file mode 100644 index 13e98c222..000000000 --- a/src/Bundle/spec/Controller/ParametersSpec.php +++ /dev/null @@ -1,49 +0,0 @@ -replace([]); - } - - function it_has_parameters(): void - { - $this->replace([ - 'criteria' => 'criteria', - 'paginate' => 'paginate', - ]); - - $this->all()->shouldReturn([ - 'criteria' => 'criteria', - 'paginate' => 'paginate', - ]); - } - - function it_gets_a_single_parameter_and_supports_default_value(): void - { - $this->replace([ - 'criteria' => 'criteria', - 'paginate' => 'paginate', - ]); - - $this->get('criteria')->shouldReturn('criteria'); - $this->get('sorting')->shouldReturn(null); - $this->get('sorting', 'default')->shouldReturn('default'); - } -} diff --git a/src/Bundle/spec/Controller/RedirectHandlerSpec.php b/src/Bundle/spec/Controller/RedirectHandlerSpec.php deleted file mode 100644 index 3630d2673..000000000 --- a/src/Bundle/spec/Controller/RedirectHandlerSpec.php +++ /dev/null @@ -1,128 +0,0 @@ -beConstructedWith($router); - } - - function it_implements_redirect_handler_interface(): void - { - $this->shouldImplement(RedirectHandlerInterface::class); - } - - function it_redirects_to_resource( - RouterInterface $router, - RequestConfiguration $configuration, - ResourceInterface $resource, - ): void { - $configuration->getRedirectParameters($resource)->willReturn([]); - $configuration->getRedirectRoute('show')->willReturn('my_route'); - - $router->generate('my_route', [])->shouldBeCalled()->willReturn('http://test.com'); - - $configuration->getRedirectHash()->willReturn(null); - $configuration->isHeaderRedirection()->willReturn(false); - - $this->redirectToResource($configuration, $resource)->shouldHaveType(RedirectResponse::class); - } - - function it_fallbacks_to_index_route_if_show_does_not_exist( - RouterInterface $router, - RequestConfiguration $configuration, - ResourceInterface $resource, - ): void { - $configuration->getRedirectParameters($resource)->willReturn([]); - $configuration->getRedirectRoute('show')->willReturn('app_resource_show'); - $configuration->getRedirectRoute('index')->willReturn('app_resource_index'); - - $router->generate('app_resource_show', [])->shouldBeCalled()->willThrow(RouteNotFoundException::class); - $router->generate('app_resource_index', [])->shouldBeCalled()->willReturn('http://test.com'); - - $configuration->getRedirectHash()->willReturn(null); - $configuration->isHeaderRedirection()->willReturn(false); - - $this->redirectToResource($configuration, $resource)->shouldHaveType(RedirectResponse::class); - } - - function it_redirects_to_index( - RouterInterface $router, - RequestConfiguration $configuration, - ResourceInterface $resource, - ): void { - $configuration->getRedirectRoute('index')->willReturn('my_route'); - $configuration->getRedirectParameters($resource)->willReturn([]); - - $router->generate('my_route', [])->willReturn('http://myurl.com'); - - $configuration->getRedirectHash()->willReturn(null); - $configuration->isHeaderRedirection()->willReturn(false); - - $this->redirectToIndex($configuration, $resource)->shouldHaveType(RedirectResponse::class); - } - - function it_redirects_to_route(RouterInterface $router, RequestConfiguration $configuration): void - { - $router->generate('route', ['parameter' => 'value'])->willReturn('http://myurl.com'); - - $this - ->redirectToRoute($configuration, 'route', ['parameter' => 'value']) - ->shouldHaveType(RedirectResponse::class) - ; - } - - function it_redirects(RequestConfiguration $configuration): void - { - $configuration->getRedirectHash()->willReturn(null); - $configuration->isHeaderRedirection()->willReturn(false); - - $this->redirect($configuration, 'http://myurl.com')->shouldHaveType(RedirectResponse::class); - } - - function it_redirect_to_referer(RequestConfiguration $configuration, Request $request, HeaderBag $bag): void - { - $request->headers = $bag; - - $bag->get('referer')->willReturn('http://myurl.com'); - - $configuration->getRequest()->willReturn($request); - $configuration->getRedirectHash()->willReturn(null); - $configuration->getRedirectReferer()->willReturn('http://myurl.com'); - $configuration->isHeaderRedirection()->willReturn(false); - - $this->redirectToReferer($configuration)->shouldHaveType(RedirectResponse::class); - } - - function it_redirects_with_header(RequestConfiguration $configuration): void - { - $configuration->getRedirectHash()->willReturn(null); - $configuration->isHeaderRedirection()->willReturn(true); - - $this->redirect($configuration, 'http://myurl.com')->shouldHaveType(Response::class); - } -} diff --git a/src/Bundle/spec/Controller/RequestConfigurationFactorySpec.php b/src/Bundle/spec/Controller/RequestConfigurationFactorySpec.php deleted file mode 100644 index 9909f4a60..000000000 --- a/src/Bundle/spec/Controller/RequestConfigurationFactorySpec.php +++ /dev/null @@ -1,286 +0,0 @@ -beConstructedWith($parametersParser, RequestConfiguration::class); - } - - function it_implements_request_configuration_factory_interface(): void - { - $this->shouldImplement(RequestConfigurationFactoryInterface::class); - } - - function it_creates_configuration_from_resource_metadata_and_request( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $headersBag->all('Accept')->willReturn([]); - - $attributesBag->get('_sylius', [])->willReturn(['template' => ':Product:show.html.twig']); - $parametersParser - ->parseRequestValues(['template' => ':Product:show.html.twig'], $request) - ->willReturn(['template' => ':Product:list.html.twig']) - ; - - $this->create($metadata, $request)->shouldHaveType(RequestConfiguration::class); - } - - function it_creates_configuration_without_default_settings( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $headersBag->all('Accept')->willReturn([]); - - $attributesBag->get('_sylius', [])->willReturn(['template' => ':Product:list.html.twig']); - $parametersParser - ->parseRequestValues(['template' => ':Product:list.html.twig'], $request) - ->willReturn(['template' => ':Product:list.html.twig']) - ; - - $this->create($metadata, $request)->isSortable()->shouldReturn(false); - } - - function it_creates_configuration_for_serialization_group_from_single_header( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $attributesBag->get('_sylius', [])->willReturn([ - 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], - ]); - $headersBag->all('Accept')->willReturn(['groups=Default,Detailed']); - - $parametersParser - ->parseRequestValues( - [ - 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], - 'serialization_groups' => ['Default', 'Detailed'], - ], - $request, - ) - ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) - ; - - $this->create($metadata, $request)->getSerializationGroups()->shouldReturn(['Default', 'Detailed']); - } - - function it_creates_configuration_for_serialization_group_from_multiple_headers( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $attributesBag->get('_sylius', [])->willReturn([ - 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], - ]); - $headersBag->all('Accept')->willReturn(['application/json', 'groups=Default,Detailed']); - - $parametersParser - ->parseRequestValues( - [ - 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], - 'serialization_groups' => ['Default', 'Detailed'], - ], - $request, - ) - ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) - ; - - $this->create($metadata, $request)->getSerializationGroups()->shouldReturn(['Default', 'Detailed']); - } - - function it_creates_configuration_using_only_those_serialization_groups_that_are_allowed( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $attributesBag->get('_sylius', [])->willReturn([ - 'allowed_serialization_groups' => ['Default'], - ]); - $headersBag->all('Accept')->willReturn(['application/json', 'groups=Default,Detailed']); - - $parametersParser - ->parseRequestValues( - [ - 'allowed_serialization_groups' => ['Default'], - 'serialization_groups' => ['Default'], - ], - $request, - ) - ->willReturn(['serialization_groups' => ['Default']]) - ; - - $this->create($metadata, $request)->getSerializationGroups()->shouldReturn(['Default']); - } - - function it_creates_configuration_using_only_those_serialization_groups_that_are_allowed_or_defined_as_default( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $attributesBag->get('_sylius', [])->willReturn([ - 'allowed_serialization_groups' => ['Default'], - 'serialization_groups' => ['Detailed'], - ]); - $headersBag->all('Accept')->willReturn(['application/json', 'groups=Default,Detailed,Other']); - - $parametersParser - ->parseRequestValues( - [ - 'allowed_serialization_groups' => ['Default'], - 'serialization_groups' => ['Default', 'Detailed'], - ], - $request, - ) - ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) - ; - - $this->create($metadata, $request)->getSerializationGroups()->shouldReturn(['Default', 'Detailed']); - } - - function it_creates_configuration_using_only_those_serialization_groups_that_are_defined_as_default( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $attributesBag->get('_sylius', [])->willReturn([ - 'serialization_groups' => ['Detailed'], - ]); - $headersBag->all('Accept')->willReturn(['application/json', 'groups=Default,Detailed,Other']); - - $parametersParser - ->parseRequestValues(['serialization_groups' => ['Detailed']], $request) - ->willReturn(['serialization_groups' => ['Detailed']]) - ; - - $this->create($metadata, $request)->getSerializationGroups()->shouldReturn(['Detailed']); - } - - function it_creates_configuration_for_serialization_version_from_single_header( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $headersBag->all('Accept')->willReturn(['version=1.0.0']); - - $attributesBag->get('_sylius', [])->willReturn([]); - - $parametersParser - ->parseRequestValues(['serialization_version' => '1.0.0'], $request) - ->willReturn(['template' => ':Product:list.html.twig']) - ; - - $this->create($metadata, $request)->isSortable()->shouldReturn(false); - } - - function it_creates_configuration_for_serialization_version_from_multiple_headers( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $headersBag->all('Accept')->willReturn(['application/xml', 'version=1.0.0']); - - $attributesBag->get('_sylius', [])->willReturn([]); - - $parametersParser - ->parseRequestValues(['serialization_version' => '1.0.0'], $request) - ->willReturn(['template' => ':Product:list.html.twig']) - ; - - $this->create($metadata, $request)->isSortable()->shouldReturn(false); - } - - function it_creates_configuration_with_default_settings( - ParametersParserInterface $parametersParser, - MetadataInterface $metadata, - Request $request, - HeaderBag $headersBag, - ParameterBag $attributesBag, - ): void { - $this->beConstructedWith($parametersParser, RequestConfiguration::class, ['sortable' => true]); - - $request->headers = $headersBag; - $request->attributes = $attributesBag; - - $headersBag->all('Accept')->willReturn([]); - - $attributesBag->get('_sylius', [])->willReturn(['template' => ':Product:list.html.twig']); - - $parametersParser - ->parseRequestValues(['template' => ':Product:list.html.twig', 'sortable' => true], $request) - ->willReturn(['template' => ':Product:list.html.twig', 'sortable' => true]) - ; - - $this->create($metadata, $request)->isSortable()->shouldReturn(true); - } -} diff --git a/src/Bundle/spec/Controller/RequestConfigurationSpec.php b/src/Bundle/spec/Controller/RequestConfigurationSpec.php deleted file mode 100644 index c9e45464b..000000000 --- a/src/Bundle/spec/Controller/RequestConfigurationSpec.php +++ /dev/null @@ -1,636 +0,0 @@ -beConstructedWith($metadata, $request, $parameters); - } - - function it_has_request(Request $request): void - { - $this->getRequest()->shouldReturn($request); - } - - function it_has_metadata(MetadataInterface $metadata): void - { - $this->getMetadata()->shouldReturn($metadata); - } - - function it_has_parameters(Parameters $parameters): void - { - $this->getParameters()->shouldReturn($parameters); - } - - function it_checks_if_its_a_html_request(Request $request): void - { - $request->getRequestFormat()->willReturn('html'); - $this->isHtmlRequest()->shouldReturn(true); - - $request->getRequestFormat()->willReturn('json'); - $this->isHtmlRequest()->shouldReturn(false); - } - - function it_returns_default_template_names(MetadataInterface $metadata): void - { - $metadata->getTemplatesNamespace()->willReturn('@SyliusAdmin/Product'); - - $this->getDefaultTemplate('index.html')->shouldReturn('@SyliusAdmin/Product/index.html.twig'); - $this->getDefaultTemplate('show.html')->shouldReturn('@SyliusAdmin/Product/show.html.twig'); - $this->getDefaultTemplate('create.html')->shouldReturn('@SyliusAdmin/Product/create.html.twig'); - $this->getDefaultTemplate('update.html')->shouldReturn('@SyliusAdmin/Product/update.html.twig'); - $this->getDefaultTemplate('custom.html')->shouldReturn('@SyliusAdmin/Product/custom.html.twig'); - } - - function it_returns_default_template_names_for_a_directory_based_templates(MetadataInterface $metadata): void - { - $metadata->getTemplatesNamespace()->willReturn('book/Backend'); - - $this->getDefaultTemplate('index.html')->shouldReturn('book/Backend/index.html.twig'); - $this->getDefaultTemplate('show.html')->shouldReturn('book/Backend/show.html.twig'); - $this->getDefaultTemplate('create.html')->shouldReturn('book/Backend/create.html.twig'); - $this->getDefaultTemplate('update.html')->shouldReturn('book/Backend/update.html.twig'); - $this->getDefaultTemplate('custom.html')->shouldReturn('book/Backend/custom.html.twig'); - } - - function it_takes_the_custom_template_if_specified(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getTemplatesNamespace()->willReturn('@SyliusAdmin/Product'); - $parameters->get('template', '@SyliusAdmin/Product/foo.html.twig')->willReturn('Product/show.html.twig'); - - $this->getTemplate('foo.html')->shouldReturn('Product/show.html.twig'); - } - - function it_gets_form_type_and_its_options(MetadataInterface $metadata, Parameters $parameters): void - { - $parameters->get('form')->willReturn(['type' => 'sylius_custom_resource']); - $this->getFormType()->shouldReturn('sylius_custom_resource'); - $this->getFormOptions()->shouldReturn([]); - - $parameters->get('form')->willReturn('sylius_custom_resource'); - $this->getFormType()->shouldReturn('sylius_custom_resource'); - $this->getFormOptions()->shouldReturn([]); - - $parameters->get('form')->willReturn(['type' => 'sylius_custom_resource', 'options' => ['key' => 'value']]); - $this->getFormType()->shouldReturn('sylius_custom_resource'); - $this->getFormOptions()->shouldReturn(['key' => 'value']); - - $metadata->getClass('form')->willReturn('\Fully\Qualified\ClassName'); - $parameters->get('form')->willReturn([]); - $this->getFormType()->shouldReturn('\Fully\Qualified\ClassName'); - $this->getFormOptions()->shouldReturn([]); - - $metadata->getClass('form')->willReturn('\Fully\Qualified\ClassName'); - $parameters->get('form')->willReturn(['options' => ['key' => 'value']]); - $this->getFormType()->shouldReturn('\Fully\Qualified\ClassName'); - $this->getFormOptions()->shouldReturn(['key' => 'value']); - } - - function it_generates_form_type_with_array_configuration(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $parameters->get('form')->willReturn(['type' => 'sylius_product', 'options' => ['validation_groups' => ['sylius']]]); - $this->getFormType()->shouldReturn('sylius_product'); - $this->getFormOptions()->shouldReturn(['validation_groups' => ['sylius']]); - } - - function it_generates_route_names(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - $parameters->get('section')->willReturn(null); - - $this->getRouteName('index')->shouldReturn('sylius_product_index'); - $this->getRouteName('show')->shouldReturn('sylius_product_show'); - $this->getRouteName('custom')->shouldReturn('sylius_product_custom'); - - $parameters->get('section')->willReturn('admin'); - $this->getRouteName('index')->shouldReturn('sylius_admin_product_index'); - $this->getRouteName('show')->shouldReturn('sylius_admin_product_show'); - $this->getRouteName('custom')->shouldReturn('sylius_admin_product_custom'); - } - - function it_generates_redirect_referer(Parameters $parameters, Request $request, HeaderBag $bag): void - { - $request->headers = $bag; - $bag->get('referer')->willReturn('http://myurl.com'); - - $parameters->get('redirect')->willReturn(['referer' => 'http://myurl.com']); - - $this->getRedirectReferer()->shouldReturn('http://myurl.com'); - } - - function it_generates_redirect_route(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - $parameters->get('section')->willReturn(null); - - $parameters->get('redirect')->willReturn(null); - $this->getRedirectRoute('index')->shouldReturn('sylius_product_index'); - - $parameters->get('redirect')->willReturn(['route' => 'myRoute']); - $this->getRedirectRoute('show')->shouldReturn('myRoute'); - - $parameters->get('redirect')->willReturn('myRoute'); - $this->getRedirectRoute('custom')->shouldReturn('myRoute'); - } - - function it_takes_section_into_account_when_generating_redirect_route(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - $parameters->get('section')->willReturn('admin'); - - $parameters->get('redirect')->willReturn(null); - $this->getRedirectRoute('index')->shouldReturn('sylius_admin_product_index'); - - $parameters->get('redirect')->willReturn(['route' => 'myRoute']); - $this->getRedirectRoute('show')->shouldReturn('myRoute'); - - $parameters->get('redirect')->willReturn('myRoute'); - $this->getRedirectRoute('custom')->shouldReturn('myRoute'); - } - - function it_returns_array_as_redirect_parameters(Parameters $parameters): void - { - $parameters->get('vars', [])->willReturn([]); - $this->getVars()->shouldReturn([]); - - $parameters->get('redirect')->willReturn(null); - $this->getRedirectParameters()->shouldReturn([]); - - $parameters->get('redirect')->willReturn('string'); - $this->getRedirectParameters()->shouldReturn([]); - - $parameters->get('redirect')->willReturn(['parameters' => []]); - $this->getRedirectParameters()->shouldReturn([]); - - $parameters->get('redirect')->willReturn(['parameters' => ['myParameter']]); - $this->getRedirectParameters()->shouldReturn(['myParameter']); - - $parameters->get('redirect')->willReturn(['parameters' => ['myParameter']]); - $this->getRedirectParameters('resource')->shouldReturn(['myParameter']); - - $invalidExtraParameters = ['redirect' => ['parameters' => 'myValue']]; - $parameters->get('vars', [])->willReturn($invalidExtraParameters); - $this->getVars()->shouldReturn($invalidExtraParameters); - $parameters->get('redirect')->willReturn(['parameters' => ['myParameter']]); - $this->getRedirectParameters('resource')->shouldReturn(['myParameter']); - - $validExtraParameters = ['redirect' => ['parameters' => ['myExtraParameter']]]; - $parameters->get('vars', [])->willReturn($validExtraParameters); - $this->getVars()->shouldReturn($validExtraParameters); - $parameters->get('redirect')->willReturn(['parameters' => ['myParameter']]); - $this->getRedirectParameters('resource')->shouldReturn(['myParameter', 'myExtraParameter']); - } - - function it_checks_if_limit_is_enabled(Parameters $parameters): void - { - $parameters->get('limit', Argument::any())->willReturn(10); - $this->isLimited()->shouldReturn(true); - - $parameters->get('limit', Argument::any())->willReturn(null); - $this->isLimited()->shouldReturn(false); - } - - function it_gets_limit(Parameters $parameters): void - { - $parameters->get('limit', false)->willReturn(true); - $parameters->get('limit', 10)->willReturn(10); - $this->getLimit()->shouldReturn(10); - - $parameters->get('limit', false)->willReturn(false); - $parameters->get('limit', 10)->willReturn(null); - $this->getLimit()->shouldReturn(null); - } - - function it_checks_if_pagination_is_enabled(Parameters $parameters): void - { - $parameters->get('paginate', Argument::any())->willReturn(10); - $this->isPaginated()->shouldReturn(true); - - $parameters->get('paginate', Argument::any())->willReturn(0); - $this->isPaginated()->shouldReturn(true); - - $parameters->get('paginate', Argument::any())->willReturn(null); - $this->isPaginated()->shouldReturn(false); - - $parameters->get('paginate', Argument::any())->willReturn(false); - $this->isPaginated()->shouldReturn(false); - } - - function it_gets_pagination_max_per_page(Parameters $parameters): void - { - $parameters->get('paginate', 10)->willReturn(20); - $this->getPaginationMaxPerPage()->shouldReturn(20); - - $parameters->get('paginate', 10)->willReturn(10); - $this->getPaginationMaxPerPage()->shouldReturn(10); - } - - function it_checks_if_the_resource_is_filterable(Parameters $parameters): void - { - $parameters->get('filterable', Argument::any())->willReturn(true); - $this->isFilterable()->shouldReturn(true); - - $parameters->get('filterable', Argument::any())->willReturn(null); - $this->isFilterable()->shouldReturn(false); - } - - function it_has_no_filterable_parameter(Parameters $parameters): void - { - $defaultCriteria = ['property' => 'myValue']; - - $parameters->get('criteria', Argument::any())->willReturn([]); - $parameters->get('filterable', false)->willReturn(false); - - $this->getCriteria($defaultCriteria)->shouldBeArray(); - $this->getCriteria($defaultCriteria)->shouldHaveCount(1); - } - - function it_has_criteria_parameter( - Parameters $parameters, - Request $request, - ParameterBag $attributesBag, - ): void { - $queryBag = new InputBag(); - $requestBag = new InputBag(); - - $criteria = ['property' => 'myNewValue']; - $request->attributes = $attributesBag; - $request->query = $queryBag; - $request->request = $requestBag; - - $parameters->get('filterable', false)->willReturn(true); - $parameters->get('criteria', Argument::any())->willReturn([]); - - $attributesBag->get('criteria', $request)->willReturn($request); - - $queryBag->set('criteria', $criteria); - - $requestBag->set('criteria', []); - - $this->getCriteria()->shouldReturn($criteria); - } - - function it_has_criteria_parameter_in_request( - Parameters $parameters, - Request $request, - ParameterBag $attributesBag, - ): void { - $queryBag = new InputBag(); - $requestBag = new InputBag(); - - $criteria = ['property' => 'myNewValue']; - $request->attributes = $attributesBag; - $request->query = $queryBag; - $request->request = $requestBag; - - $parameters->get('filterable', false)->willReturn(true); - $parameters->get('criteria', Argument::any())->willReturn([]); - - $attributesBag->get('criteria', $request)->willReturn($request); - - $requestBag->set('criteria', $criteria); - - $this->getCriteria()->shouldReturn($criteria); - } - - function it_allows_to_override_criteria_parameter_in_route( - Parameters $parameters, - Request $request, - ParameterBag $attributesBag, - ): void { - $queryBag = new InputBag(); - $requestBag = new InputBag(); - - $criteria = ['property' => 'myValue']; - $overriddenCriteria = ['other_property' => 'myNewValue']; - $combinedCriteria = ['property' => 'myValue', 'other_property' => 'myNewValue']; - $request->attributes = $attributesBag; - $request->query = $queryBag; - $request->request = $requestBag; - - $parameters->get('filterable', false)->willReturn(true); - $parameters->get('criteria', [])->willReturn($criteria); - - $attributesBag->get('criteria', $request)->willReturn($request); - - $queryBag->set('criteria', $overriddenCriteria); - - $requestBag->set('criteria', []); - - $this->getCriteria()->shouldReturn($combinedCriteria); - - $defaultCriteria = ['slug' => 'foo']; - $combinedDefaultCriteria = ['property' => 'myValue', 'slug' => 'foo', 'other_property' => 'myNewValue']; - - $parameters->get('filterable', false)->willReturn(true); - $parameters->get('criteria', Argument::any())->willReturn($criteria); - $attributesBag->get('criteria', $request)->willReturn($request); - $queryBag->set('criteria', $overriddenCriteria); - $requestBag->set('criteria', []); - - $this->getCriteria($defaultCriteria)->shouldReturn($combinedDefaultCriteria); - - $parameters->get('filterable', false)->willReturn(true); - $parameters->get('criteria', [])->willReturn(['filter' => 'route']); - $attributesBag->get('criteria', $request)->willReturn($request); - $queryBag->set('criteria', ['filter' => 'request']); - $requestBag->set('criteria', []); - - $this->getCriteria(['filter' => 'default'])->shouldReturn(['filter' => 'request']); - } - - function it_checks_if_the_resource_is_sortable(Parameters $parameters): void - { - $parameters->get('sortable', Argument::any())->willReturn(true); - $this->isSortable()->shouldReturn(true); - - $parameters->get('sortable', Argument::any())->willReturn(null); - $this->isSortable()->shouldReturn(false); - } - - function it_has_sorting_parameter( - Parameters $parameters, - Request $request, - ParameterBag $attributesBag, - ): void { - $queryBag = new InputBag(); - $requestBag = new InputBag(); - - $sorting = ['property' => 'asc']; - $request->attributes = $attributesBag; - $request->query = $queryBag; - $request->request = $requestBag; - - $parameters->get('sortable', false)->willReturn(true); - $parameters->get('sorting', Argument::any())->willReturn($sorting); - - $attributesBag->get('sorting', $request)->willReturn($request); - - $queryBag->set('sorting', $sorting); - - $requestBag->set('sorting', []); - - $this->getSorting()->shouldReturn($sorting); - } - - function it_has_no_sortable_parameter(Parameters $parameters): void - { - $defaultSorting = ['property' => 'desc']; - - $parameters->get('sorting', Argument::any())->willReturn([]); - $parameters->get('sortable', false)->willReturn(false); - - $this->getSorting($defaultSorting)->shouldBeArray(); - $this->getSorting($defaultSorting)->shouldHaveCount(1); - } - - function it_allows_to_override_sorting_parameter_in_route( - Parameters $parameters, - Request $request, - ParameterBag $attributesBag, - ): void { - $queryBag = new InputBag(); - $requestBag = new InputBag(); - - $sorting = ['property' => 'desc']; - $overriddenSorting = ['other_property' => 'asc']; - $combinedSorting = ['other_property' => 'asc', 'property' => 'desc']; - $request->attributes = $attributesBag; - $request->query = $queryBag; - $request->request = $requestBag; - - $parameters->get('sortable', false)->willReturn(true); - $parameters->get('sorting', [])->willReturn($sorting); - $attributesBag->get('sorting', $request)->willReturn($request); - $queryBag->set('sorting', $overriddenSorting); - $requestBag->set('sorting', []); - - $this->getSorting()->shouldReturn($combinedSorting); - - $defaultSorting = ['foo' => 'bar']; - $combinedDefaultSorting = ['other_property' => 'asc', 'property' => 'desc', 'foo' => 'bar']; - - $parameters->get('sortable', false)->willReturn(true); - $parameters->get('sorting', Argument::any())->willReturn($sorting); - $attributesBag->get('sorting', $request)->willReturn($request); - $queryBag->set('sorting', $overriddenSorting); - $requestBag->set('sorting', []); - - $this->getSorting($defaultSorting)->shouldReturn($combinedDefaultSorting); - - $parameters->get('sortable', false)->willReturn(true); - $parameters->get('sorting', [])->willReturn(['sort' => 'route']); - $attributesBag->get('sorting', $request)->willReturn($request); - $queryBag->set('sorting', ['sort' => 'request']); - $requestBag->set('sorting', []); - - $this->getSorting(['sort' => 'default'])->shouldReturn(['sort' => 'request']); - } - - function it_has_repository_method_parameter(Parameters $parameters): void - { - $parameters->has('repository')->willReturn(false); - $this->getRepositoryMethod()->shouldReturn(null); - - $parameters->has('repository')->willReturn(true); - $parameters->get('repository')->willReturn(['method' => 'findAllEnabled']); - - $this->getRepositoryMethod()->shouldReturn('findAllEnabled'); - } - - function it_has_repository_arguments_parameter(Parameters $parameters): void - { - $parameters->has('repository')->willReturn(false); - $this->getRepositoryArguments()->shouldReturn([]); - - $repositoryConfiguration = ['arguments' => 'value']; - $parameters->has('repository')->willReturn(true); - $parameters->get('repository')->willReturn($repositoryConfiguration); - - $this->getRepositoryArguments()->shouldReturn(['value']); - - $repositoryConfiguration = ['arguments' => ['foo, bar']]; - $parameters->has('repository')->willReturn(true); - $parameters->get('repository')->willReturn($repositoryConfiguration); - - $this->getRepositoryArguments()->shouldReturn(['foo, bar']); - } - - function it_has_factory_method_parameter(Parameters $parameters): void - { - $parameters->has('factory')->willReturn(false); - $this->getFactoryMethod()->shouldReturn(null); - - $parameters->has('factory')->willReturn(true); - $parameters->get('factory')->willReturn(['method' => 'createForPromotion']); - - $this->getFactoryMethod()->shouldReturn('createForPromotion'); - } - - function it_has_factory_arguments_parameter(Parameters $parameters): void - { - $parameters->has('factory')->willReturn(false); - $this->getFactoryArguments()->shouldReturn([]); - - $factoryConfiguration = ['arguments' => 'value']; - $parameters->has('factory')->willReturn(true); - $parameters->get('factory')->willReturn($factoryConfiguration); - - $this->getFactoryArguments()->shouldReturn(['value']); - - $factoryConfiguration = ['arguments' => ['foo, bar']]; - $parameters->has('factory')->willReturn(true); - $parameters->get('factory')->willReturn($factoryConfiguration); - - $this->getFactoryArguments()->shouldReturn(['foo, bar']); - } - - function it_has_flash_message_parameter(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $parameters->get('flash', 'sylius.product.message')->willReturn('sylius.product.message'); - $this->getFlashMessage('message')->shouldReturn('sylius.product.message'); - - $parameters->get('flash', 'sylius.product.flash')->willReturn('sylius.product.myMessage'); - $this->getFlashMessage('flash')->shouldReturn('sylius.product.myMessage'); - } - - function it_has_sortable_position_parameter(Parameters $parameters): void - { - $parameters->get('sortable_position', 'position')->willReturn('position'); - $this->getSortablePosition()->shouldReturn('position'); - - $parameters->get('sortable_position', 'position')->willReturn('myPosition'); - $this->getSortablePosition()->shouldReturn('myPosition'); - } - - function it_has_permission_unless_defined_as_false_in_parameters(Parameters $parameters): void - { - $parameters->get('permission', false)->willReturn(false); - $this->shouldNotHavePermission(); - - $parameters->get('permission', false)->willReturn('custom_permission'); - $this->shouldHavePermission(); - - $parameters->get('permission', false)->willReturn(false); - $this->shouldNotHavePermission(); - } - - function it_generates_permission_name(MetadataInterface $metadata, Parameters $parameters): void - { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $parameters->get('permission')->willReturn(true); - - $this->getPermission('index')->shouldReturn('sylius.product.index'); - } - - function it_takes_permission_name_from_parameters_if_provided(Parameters $parameters): void - { - $parameters->get('permission')->willReturn('app.sales_order.view_pricing'); - - $this->getPermission('index')->shouldReturn('app.sales_order.view_pricing'); - } - - function it_throws_an_exception_when_permission_is_set_as_false_in_parameters_but_still_trying_to_get_it(Parameters $parameters): void - { - $parameters->get('permission')->willReturn(null); - - $this - ->shouldThrow(\LogicException::class) - ->during('getPermission', ['index']) - ; - } - - function it_has_event_name(Parameters $parameters): void - { - $parameters->get('event')->willReturn('foo'); - $this->getEvent()->shouldReturn('foo'); - } - - function it_has_section(Parameters $parameters): void - { - $parameters->get('section')->willReturn(null); - $this->getSection()->shouldReturn(null); - - $parameters->get('section')->willReturn('admin'); - $this->getSection()->shouldReturn('admin'); - } - - function it_has_vars(Parameters $parameters): void - { - $parameters->get('vars', [])->willReturn(['foo' => 'bar']); - $this->getVars()->shouldReturn(['foo' => 'bar']); - } - - function it_does_not_have_grid_unless_defined_as_in_parameters(Parameters $parameters): void - { - $parameters->has('grid')->willReturn(false); - $this->shouldNotHaveGrid(); - - $parameters->has('grid')->willReturn(true); - $this->shouldHaveGrid(); - - $parameters->has('grid')->willReturn(true); - $parameters->get('grid')->willReturn('sylius_admin_tax_category'); - - $this->getGrid()->shouldReturn('sylius_admin_tax_category'); - } - - function it_throws_an_exception_when_trying_to_retrieve_undefined_grid(Parameters $parameters): void - { - $parameters->has('grid')->willReturn(false); - - $this - ->shouldThrow(\LogicException::class) - ->during('getGrid') - ; - } - - function it_can_have_state_machine_transition(Parameters $parameters): void - { - $parameters->has('state_machine')->willReturn(false); - $this->hasStateMachine()->shouldReturn(false); - - $parameters->has('state_machine')->willReturn(true); - $parameters->get('state_machine')->willReturn([ - 'graph' => 'sylius_product_review_state', - 'transition' => 'approve', - ]); - - $this->hasStateMachine()->shouldReturn(true); - $this->getStateMachineGraph()->shouldReturn('sylius_product_review_state'); - $this->getStateMachineTransition()->shouldReturn('approve'); - } -} diff --git a/src/Bundle/spec/Controller/ResourceControllerSpec.php b/src/Bundle/spec/Controller/ResourceControllerSpec.php deleted file mode 100644 index 270c25110..000000000 --- a/src/Bundle/spec/Controller/ResourceControllerSpec.php +++ /dev/null @@ -1,2807 +0,0 @@ -beConstructedWith( - $metadata, - $requestConfigurationFactory, - $viewHandler, - $repository, - $factory, - $newResourceFactory, - $manager, - $singleResourceProvider, - $resourcesCollectionProvider, - $resourceFormFactory, - $redirectHandler, - $flashHelper, - $authorizationChecker, - $eventDispatcher, - $stateMachine, - $resourceUpdateHandler, - $resourceDeleteHandler, - ); - - $this->setContainer($container); - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_view_a_single_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::SHOW)->willReturn('sylius.product.show'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.show')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('showAction', [$request]) - ; - } - - function it_throws_a_404_exception_if_resource_is_not_found_based_on_configuration( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ): void { - $metadata->getHumanizedName()->willReturn('product'); - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::SHOW)->willReturn('sylius.product.show'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.show')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn(null); - - $this - ->shouldThrow(new NotFoundHttpException('The "product" has not been found')) - ->during('showAction', [$request]) - ; - } - - function it_returns_a_response_for_html_view_of_a_single_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - EventDispatcherInterface $eventDispatcher, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::SHOW)->willReturn('sylius.product.show'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.show')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::SHOW . '.html')->willReturn('@SyliusShop/Product/show.html.twig'); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $resource, - 'product' => $resource, - ]; - - $twig->render('@SyliusShop/Product/show.html.twig', $expectedContext)->willReturn('view'); - - $eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource)->shouldBeCalled(); - - $twig->render('@SyliusShop/Product/show.html.twig', $expectedContext)->shouldBeCalled(); - - $this->showAction($request); - } - - function it_returns_event_response_if_exists_during_show( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - EventDispatcherInterface $eventDispatcher, - ViewHandlerInterface $viewHandler, - ResourceControllerEvent $event, - ResourceInterface $resource, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::SHOW)->willReturn('sylius.product.show'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.show')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource)->willReturn($event); - - $event->getResponse()->willReturn($response); - - $configuration->isHtmlRequest()->shouldNotBeCalled(); - $viewHandler->handle(Argument::any())->shouldNotBeCalled(); - - $this->showAction($request)->shouldReturn($response); - } - - function it_returns_a_response_for_non_html_view_of_single_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ViewHandlerInterface $viewHandler, - EventDispatcherInterface $eventDispatcher, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::SHOW)->willReturn('sylius.product.show'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.show')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $configuration->isHtmlRequest()->willReturn(false); - - $eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource)->shouldBeCalled(); - - $expectedView = View::create($resource); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->showAction($request)->shouldReturn($response); - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_view_an_index_of_resources( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::INDEX)->willReturn('sylius.product.index'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.index')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('indexAction', [$request]) - ; - } - - function it_returns_a_response_for_html_view_of_paginated_resources( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - ResourcesCollectionProviderInterface $resourcesCollectionProvider, - EventDispatcherInterface $eventDispatcher, - ResourceInterface $resource1, - ResourceInterface $resource2, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - $metadata->getPluralName()->willReturn('products'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::INDEX)->willReturn('sylius.product.index'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.index')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::INDEX . '.html')->willReturn('@SyliusShop/Product/index.html.twig'); - $resourcesCollectionProvider->get($configuration, $repository)->willReturn([$resource1, $resource2]); - - $eventDispatcher->dispatchMultiple(ResourceActions::INDEX, $configuration, [$resource1, $resource2])->shouldBeCalled(); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resources' => [$resource1, $resource2], - 'products' => [$resource1, $resource2], - ]; - - $twig->render('@SyliusShop/Product/index.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/index.html.twig', $expectedContext)->shouldBeCalled(); - - $this->indexAction($request); - } - - function it_returns_event_response_if_exists_during_index( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - ResourcesCollectionProviderInterface $resourcesCollectionProvider, - EventDispatcherInterface $eventDispatcher, - ViewHandlerInterface $viewHandler, - ResourceControllerEvent $event, - ResourceInterface $resource1, - ResourceInterface $resource2, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::INDEX)->willReturn('sylius.product.index'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.index')->willReturn(true); - - $configuration->getTemplate(ResourceActions::INDEX . '.html')->willReturn('@SyliusShop/Product/index.html.twig'); - $resourcesCollectionProvider->get($configuration, $repository)->willReturn([$resource1, $resource2]); - - $eventDispatcher->dispatchMultiple(ResourceActions::INDEX, $configuration, [$resource1, $resource2])->willReturn($event); - - $event->getResponse()->willReturn($response); - - $configuration->isHtmlRequest()->shouldNotBeCalled(); - $viewHandler->handle(Argument::any())->shouldNotBeCalled(); - - $this->indexAction($request)->shouldReturn($response); - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_create_a_new_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('createAction', [$request]) - ; - } - - function it_returns_a_html_response_for_creating_new_resource_form( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('POST')->willReturn(false); - $form->createView()->willReturn($formView); - $form->handleRequest($request)->willReturn($form); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $newResource, - 'product' => $newResource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->willReturn('view'); - - $form->handleRequest($request)->shouldBeCalled(); - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->shouldBeCalled(); - - $this->createAction($request); - } - - function it_returns_a_html_response_for_invalid_form_during_resource_creation( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(false); - $form->createView()->willReturn($formView); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $newResource, - 'product' => $newResource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->shouldBeCalled(); - - $this->createAction($request); - } - - function it_returns_a_html_response_for_not_submitted_form_during_resource_creation( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(false); - $form->createView()->willReturn($formView); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $newResource, - 'product' => $newResource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/create.html.twig', $expectedContext)->shouldBeCalled(); - - $this->createAction($request); - } - - function it_returns_a_non_html_response_for_invalid_form_during_resource_creation( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(false); - - $expectedView = View::create($form, 400); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->createAction($request)->shouldReturn($response); - } - - function it_returns_a_non_html_response_for_not_submitted_form_during_resource_creation( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(false); - - $expectedView = View::create($form, 400); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->createAction($request)->shouldReturn($response); - } - - function it_does_not_create_the_resource_and_redirects_to_index_for_html_requests_stopped_via_events( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(true); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - - $event->getResponse()->willReturn(null); - - $repository->add($newResource)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - - $redirectHandler->redirectToIndex($configuration, $newResource)->willReturn($redirectResponse); - - $this->createAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_create_the_resource_and_return_response_for_html_requests_stopped_via_events( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(true); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - - $event->hasResponse()->willReturn(true); - $event->getResponse()->willReturn($response); - - $repository->add($newResource)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - - $this->createAction($request)->shouldReturn($response); - } - - function it_redirects_to_newly_created_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - StateMachineInterface $stateMachine, - Form $form, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - $configuration->hasStateMachine()->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->apply($configuration, $newResource)->shouldBeCalled(); - - $repository->add($newResource)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($postEvent); - - $postEvent->getResponse()->willReturn(null); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource)->shouldBeCalled(); - $redirectHandler->redirectToResource($configuration, $newResource)->willReturn($redirectResponse); - - $this->createAction($request)->shouldReturn($redirectResponse); - } - - function it_uses_response_from_post_create_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - StateMachineInterface $stateMachine, - Form $form, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - $configuration->hasStateMachine()->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->apply($configuration, $newResource)->shouldBeCalled(); - - $repository->add($newResource)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($postEvent); - $flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource)->shouldBeCalled(); - - $postEvent->hasResponse()->willReturn(true); - $postEvent->getResponse()->willReturn($redirectResponse); - - $this->createAction($request)->shouldReturn($redirectResponse); - } - - function it_returns_a_non_html_response_for_correctly_created_resources( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - StateMachineInterface $stateMachine, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - $configuration->hasStateMachine()->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->apply($configuration, $newResource)->shouldBeCalled(); - - $repository->add($newResource)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldBeCalled(); - - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - - $expectedView = View::create($newResource, 201); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->createAction($request)->shouldReturn($response); - } - - function it_does_not_create_the_resource_and_throws_http_exception_for_non_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - RepositoryInterface $repository, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - Form $form, - Request $request, - ResourceControllerEvent $event, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(true); - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($newResource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getMessage()->willReturn('You cannot add a new product right now.'); - $event->getErrorCode()->willReturn(500); - - $repository->add($newResource)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new HttpException(500, 'You cannot add a new product right now.')) - ->during('createAction', [$request]) - ; - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_edit_a_single_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('updateAction', [$request]) - ; - } - - function it_throws_a_404_exception_if_resource_to_update_is_not_found_based_on_configuration( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ): void { - $metadata->getHumanizedName()->willReturn('product'); - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn(null); - - $this - ->shouldThrow(new NotFoundHttpException('The "product" has not been found')) - ->during('updateAction', [$request]) - ; - } - - function it_returns_a_html_response_for_updating_resource_form( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->hasStateMachine()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('GET'); - - $form->handleRequest($request)->willReturn($form); - $form->createView()->willReturn($formView); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $resource, - 'product' => $resource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->shouldBeCalled(); - - $this->updateAction($request); - } - - function it_returns_a_html_response_for_invalid_form_during_resource_update( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(false); - $form->createView()->willReturn($formView); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $resource, - 'product' => $resource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->shouldBeCalled(); - - $this->updateAction($request); - } - - function it_returns_a_html_response_for_not_submitted_form_during_resource_update( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - FormView $formView, - ContainerInterface $container, - Environment $twig, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - $event->getResponse()->willReturn(null); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(false); - $form->createView()->willReturn($formView); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $expectedContext = [ - 'configuration' => $configuration, - 'metadata' => $metadata, - 'resource' => $resource, - 'product' => $resource, - 'form' => $formView, - ]; - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->willReturn('view'); - - $twig->render('@SyliusShop/Product/update.html.twig', $expectedContext)->shouldBeCalled(); - - $this->updateAction($request); - } - - function it_returns_a_non_html_response_for_invalid_form_during_resource_update( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isHtmlRequest()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(true); - $request->getMethod()->willReturn('PATCH'); - - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(false); - - $expectedView = View::create($form, 400); - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->updateAction($request)->shouldReturn($response); - } - - function it_returns_a_non_html_response_for_not_submitted_form_during_resource_update( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isHtmlRequest()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(true); - $request->getMethod()->willReturn('PATCH'); - - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(false); - - $expectedView = View::create($form, 400); - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->updateAction($request)->shouldReturn($response); - } - - function it_does_not_update_the_resource_and_redirects_to_resource_for_html_request_if_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ObjectManager $manager, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - Form $form, - EventDispatcherInterface $eventDispatcher, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - ResourceControllerEvent $event, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getResponse()->willReturn(null); - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - - $manager->flush()->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - - $redirectHandler->redirectToResource($configuration, $resource)->willReturn($redirectResponse); - - $this->updateAction($request)->shouldReturn($redirectResponse); - } - - function it_redirects_to_updated_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - ResourceFormFactoryInterface $resourceFormFactory, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - Form $form, - ResourceControllerEvent $preEvent, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->hasStateMachine()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($preEvent); - $preEvent->isStopped()->willReturn(false); - - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->getResponse()->willReturn(null); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldBeCalled(); - $redirectHandler->redirectToResource($configuration, $resource)->willReturn($redirectResponse); - - $this->updateAction($request)->shouldReturn($redirectResponse); - } - - function it_uses_response_from_post_update_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - ResourceFormFactoryInterface $resourceFormFactory, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - Form $form, - ResourceControllerEvent $preEvent, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->hasStateMachine()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($preEvent); - $preEvent->isStopped()->willReturn(false); - - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->hasResponse()->willReturn(true); - $postEvent->getResponse()->willReturn($redirectResponse); - - $redirectHandler->redirectToResource($configuration, $resource)->shouldNotBeCalled(); - - $this->updateAction($request)->shouldReturn($redirectResponse); - } - - function it_uses_response_from_initialize_create_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RedirectHandlerInterface $redirectHandler, - FactoryInterface $factory, - NewResourceFactoryInterface $newResourceFactory, - ResourceInterface $newResource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $initializeEvent, - Form $form, - ContainerInterface $container, - Environment $twig, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::CREATE)->willReturn('sylius.product.create'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.create')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); - - $newResourceFactory->create($configuration, $factory)->willReturn($newResource); - $resourceFormFactory->create($configuration, $newResource)->willReturn($form); - - $request->isMethod('POST')->willReturn(false); - $form->createView()->shouldNotBeCalled(); - $form->handleRequest($request)->willReturn($form); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource)->willReturn($initializeEvent); - $initializeEvent->hasResponse()->willReturn(true); - $initializeEvent->getResponse()->willReturn($response); - - $eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource)->shouldNotBeCalled(); - $redirectHandler->redirectToResource($configuration, $newResource)->shouldNotBeCalled(); - - $container->has('templating')->willReturn(false); - $container->has('twig')->willReturn(true); - $container->get('twig')->willReturn($twig); - - $twig->render(Argument::cetera())->willReturn('view'); - - $twig->render(Argument::cetera())->shouldNotBeCalled(); - $form->handleRequest($request)->shouldBeCalled(); - - $this->createAction($request); - } - - function it_uses_response_from_initialize_update_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - ResourceFormFactoryInterface $resourceFormFactory, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - Form $form, - ResourceControllerEvent $initializeEvent, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->hasStateMachine()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->getMethod()->willReturn('GET'); - - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(false); - $form->isValid()->willReturn(false); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldNotBeCalled(); - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldNotBeCalled(); - $redirectHandler->redirectToResource($configuration, $resource)->shouldNotBeCalled(); - - $eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($initializeEvent); - $initializeEvent->hasResponse()->willReturn(true); - $initializeEvent->getResponse()->willReturn($response); - - $this->updateAction($request)->shouldReturn($response); - } - - function it_returns_a_non_html_response_for_correctly_updated_resource( - MetadataInterface $metadata, - ParameterBagInterface $parameterBag, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - ResourceFormFactoryInterface $resourceFormFactory, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - ResourceControllerEvent $event, - Form $form, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isHtmlRequest()->willReturn(false); - $configuration->hasStateMachine()->willReturn(false); - - $configuration->getParameters()->willReturn($parameterBag); - $parameterBag->get('return_content', false)->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldBeCalled(); - - $expectedView = View::create(null, 204); - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->updateAction($request)->shouldReturn($response); - } - - function it_does_not_update_the_resource_throws_a_http_exception_for_non_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ObjectManager $manager, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - ResourceFormFactoryInterface $resourceFormFactory, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Form $form, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isHtmlRequest()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getMessage()->willReturn('Cannot update this channel.'); - $event->getErrorCode()->willReturn(500); - - $manager->flush()->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new HttpException(500, 'Cannot update this channel.')) - ->during('updateAction', [$request]) - ; - } - - function it_applies_state_machine_transition_to_updated_resource_if_configured( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - ResourceFormFactoryInterface $resourceFormFactory, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - Form $form, - ResourceControllerEvent $preEvent, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->hasStateMachine()->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->getTemplate(ResourceActions::UPDATE)->willReturn('@SyliusShop/Product/update.html.twig'); - - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resourceFormFactory->create($configuration, $resource)->willReturn($form); - - $request->isMethod('PATCH')->willReturn(false); - $request->getMethod()->willReturn('PUT'); - - $form->handleRequest($request)->willReturn($form); - - $form->isSubmitted()->willReturn(true); - $form->isValid()->willReturn(true); - $form->getData()->willReturn($resource); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($preEvent); - $preEvent->isStopped()->willReturn(false); - - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->getResponse()->willReturn(null); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldBeCalled(); - $redirectHandler->redirectToResource($configuration, $resource)->willReturn($redirectResponse); - - $this->updateAction($request)->shouldReturn($redirectResponse); - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_delete_multiple_resources( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::BULK_DELETE)->willReturn('sylius.product.bulk_delete'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.bulk_delete')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('bulkDeleteAction', [$request]) - ; - } - - function it_deletes_multiple_resources_and_redirects_to_index_for_html_request( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - ResourcesCollectionProviderInterface $resourcesCollectionProvider, - ResourceInterface $firstResource, - ResourceInterface $secondResource, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $firstPreEvent, - ResourceControllerEvent $secondPreEvent, - ResourceControllerEvent $firstPostEvent, - ResourceControllerEvent $secondPostEvent, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::BULK_DELETE)->willReturn('sylius.product.bulk_delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('bulk_delete', 'xyz'))->willReturn(true); - - $eventDispatcher - ->dispatchMultiple(ResourceActions::BULK_DELETE, $configuration, [$firstResource, $secondResource]) - ->shouldBeCalled() - ; - - $authorizationChecker->isGranted($configuration, 'sylius.product.bulk_delete')->willReturn(true); - $resourcesCollectionProvider->get($configuration, $repository)->willReturn([$firstResource, $secondResource]); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher - ->dispatchPreEvent(ResourceActions::DELETE, $configuration, $firstResource) - ->willReturn($firstPreEvent) - ; - $firstPreEvent->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($firstResource, $repository)->shouldBeCalled(); - - $eventDispatcher - ->dispatchPostEvent(ResourceActions::DELETE, $configuration, $firstResource) - ->willReturn($firstPostEvent) - ; - $firstPostEvent->getResponse()->willReturn(null); - - $eventDispatcher - ->dispatchPreEvent(ResourceActions::DELETE, $configuration, $secondResource) - ->willReturn($secondPreEvent) - ; - $secondPreEvent->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($secondResource, $repository)->shouldBeCalled(); - - $eventDispatcher - ->dispatchPostEvent(ResourceActions::DELETE, $configuration, $secondResource) - ->willReturn($secondPostEvent) - ; - $secondPostEvent->getResponse()->willReturn(null); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::BULK_DELETE)->shouldBeCalled(); - - $redirectHandler->redirectToIndex($configuration)->willReturn($redirectResponse); - - $this->bulkDeleteAction($request)->shouldReturn($redirectResponse); - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_delete_a_single_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('deleteAction', [$request]) - ; - } - - function it_throws_a_404_exception_if_resource_for_deletion_is_not_found_based_on_configuration( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ): void { - $metadata->getHumanizedName()->willReturn('product'); - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn(null); - - $this - ->shouldThrow(new NotFoundHttpException('The "product" has not been found')) - ->during('deleteAction', [$request]) - ; - } - - function it_deletes_a_resource_and_redirects_to_index_by_for_html_request( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($resource, $repository)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->getResponse()->willReturn(null); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource)->shouldBeCalled(); - $redirectHandler->redirectToIndex($configuration, $resource)->willReturn($redirectResponse); - - $this->deleteAction($request)->shouldReturn($redirectResponse); - } - - function it_uses_response_from_post_delete_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($resource, $repository)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($postEvent); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource)->shouldBeCalled(); - - $postEvent->hasResponse()->willReturn(true); - $postEvent->getResponse()->willReturn($redirectResponse); - - $this->deleteAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_delete_a_resource_and_redirects_to_index_for_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getResponse()->willReturn(null); - - $resourceDeleteHandler->handle($resource, $repository)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource)->shouldNotBeCalled(); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - $redirectHandler->redirectToIndex($configuration, $resource)->willReturn($redirectResponse); - - $this->deleteAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_delete_a_resource_and_uses_response_from_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - - $event->hasResponse()->willReturn(true); - $event->getResponse()->willReturn($redirectResponse); - - $resourceDeleteHandler->handle($resource, $repository)->shouldNotBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::DELETE, $resource)->shouldNotBeCalled(); - - $redirectHandler->redirectToIndex($configuration, $resource)->shouldNotBeCalled(); - - $this->deleteAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_correctly_delete_a_resource_and_returns_500_for_not_html_response( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($resource, $repository)->willThrow(new DeleteHandlingException()); - - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->shouldNotBeCalled(); - - $expectedView = View::create(null, 500); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->deleteAction($request)->shouldReturn($response); - } - - function it_deletes_a_resource_and_returns_204_for_non_html_requests( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $resourceDeleteHandler->handle($resource, $repository)->shouldBeCalled(); - $eventDispatcher->dispatchPostEvent(ResourceActions::DELETE, $configuration, $resource)->shouldBeCalled(); - - $expectedView = View::create(null, 204); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->deleteAction($request)->shouldReturn($response); - } - - function it_does_not_delete_a_resource_and_throws_http_exception_for_non_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(false); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getMessage()->willReturn('Cannot delete this product.'); - $event->getErrorCode()->willReturn(500); - - $resourceDeleteHandler->handle($resource, $repository)->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - $flashHelper->addFlashFromEvent(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new HttpException(500, 'Cannot delete this product.')) - ->during('deleteAction', [$request]) - ; - } - - function it_throws_a_403_exception_if_csrf_token_is_invalid_during_delete_action( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - ResourceDeleteHandlerInterface $resourceDeleteHandler, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::DELETE)->willReturn('sylius.product.delete'); - $request->request = new InputBag(['_csrf_token' => 'xyz']); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.delete')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - $resource->getId()->willReturn(1); - - $configuration->isHtmlRequest()->willReturn(true); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::DELETE, $configuration, $resource)->willReturn($event); - $event->isStopped()->shouldNotBeCalled(); - - $resourceDeleteHandler->handle($resource, $repository)->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - $flashHelper->addFlashFromEvent(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new HttpException(403, 'Invalid csrf token.')) - ->during('deleteAction', [$request]) - ; - } - - function it_throws_a_403_exception_if_user_is_unauthorized_to_apply_state_machine_transition_on_resource( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - ): void { - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(false); - - $this - ->shouldThrow(new AccessDeniedException()) - ->during('applyStateMachineTransitionAction', [$request]) - ; - } - - function it_throws_a_404_exception_if_resource_is_not_found_when_trying_to_apply_state_machine_transition( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - Request $request, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ): void { - $metadata->getHumanizedName()->willReturn('product'); - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn(null); - - $this - ->shouldThrow(new NotFoundHttpException('The "product" has not been found')) - ->during('applyStateMachineTransitionAction', [$request]) - ; - } - - function it_does_not_apply_state_machine_transition_on_resource_if_not_applicable_and_returns_400_bad_request( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - ObjectManager $objectManager, - StateMachineInterface $stateMachine, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - $request->get('_csrf_token')->willReturn('xyz'); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $resource->getId()->willReturn('1'); - - $configuration->isHtmlRequest()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->can($configuration, $resource)->willReturn(false); - - $stateMachine->apply($configuration, $resource)->shouldNotBeCalled(); - $objectManager->flush()->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - $flashHelper->addFlashFromEvent(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new BadRequestHttpException()) - ->during('applyStateMachineTransitionAction', [$request]) - ; - } - - function it_applies_state_machine_transition_to_resource_and_redirects_for_html_request( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - StateMachineInterface $stateMachine, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - $request->get('_csrf_token')->willReturn('xyz'); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $resource->getId()->willReturn('1'); - - $configuration->isHtmlRequest()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->can($configuration, $resource)->willReturn(true); - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->getResponse()->willReturn(null); - - $redirectHandler->redirectToResource($configuration, $resource)->willReturn($redirectResponse); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($redirectResponse); - } - - function it_uses_response_from_post_apply_state_machine_transition_event_if_defined( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - FlashHelperInterface $flashHelper, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - StateMachineInterface $stateMachine, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - ResourceControllerEvent $event, - ResourceControllerEvent $postEvent, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - $request->get('_csrf_token')->willReturn('xyz'); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $resource->getId()->willReturn('1'); - - $configuration->isHtmlRequest()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->can($configuration, $resource)->willReturn(true); - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($postEvent); - - $postEvent->hasResponse()->willReturn(true); - $postEvent->getResponse()->willReturn($redirectResponse); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_apply_state_machine_transition_on_resource_and_redirects_for_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - StateMachineInterface $stateMachine, - ObjectManager $manager, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - RedirectHandlerInterface $redirectHandler, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - Request $request, - Response $redirectResponse, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - $request->get('_csrf_token')->willReturn('xyz'); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $resource->getId()->willReturn('1'); - - $configuration->isHtmlRequest()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - - $manager->flush()->shouldNotBeCalled(); - $stateMachine->apply($resource)->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldNotBeCalled(); - - $event->getResponse()->willReturn(null); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - $redirectHandler->redirectToResource($configuration, $resource)->willReturn($redirectResponse); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($redirectResponse); - } - - function it_does_not_apply_state_machine_transition_on_resource_and_return_event_response_for_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - StateMachineInterface $stateMachine, - ObjectManager $manager, - RepositoryInterface $repository, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - CsrfTokenManagerInterface $csrfTokenManager, - ContainerInterface $container, - ResourceControllerEvent $event, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(true); - $request->get('_csrf_token')->willReturn('xyz'); - - $container->has('security.csrf.token_manager')->willReturn(true); - $container->get('security.csrf.token_manager')->willReturn($csrfTokenManager); - $csrfTokenManager->isTokenValid(new CsrfToken('1', 'xyz'))->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $resource->getId()->willReturn('1'); - - $configuration->isHtmlRequest()->willReturn(true); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - - $manager->flush()->shouldNotBeCalled(); - $stateMachine->apply($resource)->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldNotBeCalled(); - $flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource)->shouldNotBeCalled(); - - $flashHelper->addFlashFromEvent($configuration, $event)->shouldBeCalled(); - - $event->hasResponse()->willReturn(true); - $event->getResponse()->willReturn($response); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($response); - } - - function it_applies_state_machine_transition_on_resource_and_returns_200_for_non_html_requests( - MetadataInterface $metadata, - ParameterBagInterface $parameterBag, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - StateMachineInterface $stateMachine, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - ResourceControllerEvent $event, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->getParameters()->willReturn($parameterBag); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(false); - - $parameterBag->get('return_content', true)->willReturn(true); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $configuration->isHtmlRequest()->willReturn(false); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->can($configuration, $resource)->willReturn(true); - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldBeCalled(); - - $expectedView = View::create($resource, 200); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($response); - } - - function it_applies_state_machine_transition_on_resource_and_returns_204_for_non_html_requests_if_additional_option_added( - MetadataInterface $metadata, - ParameterBagInterface $parameterBag, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - ViewHandlerInterface $viewHandler, - RepositoryInterface $repository, - ObjectManager $manager, - SingleResourceProviderInterface $singleResourceProvider, - AuthorizationCheckerInterface $authorizationChecker, - EventDispatcherInterface $eventDispatcher, - StateMachineInterface $stateMachine, - ResourceUpdateHandlerInterface $resourceUpdateHandler, - RequestConfiguration $configuration, - ResourceInterface $resource, - ResourceControllerEvent $event, - Request $request, - Response $response, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->getParameters()->willReturn($parameterBag); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(false); - - $parameterBag->get('return_content', true)->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $configuration->isHtmlRequest()->willReturn(false); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(false); - - $stateMachine->can($configuration, $resource)->willReturn(true); - $resourceUpdateHandler->handle($resource, $configuration, $manager)->shouldBeCalled(); - - $eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource)->shouldBeCalled(); - - $expectedView = View::create(null, 204); - - $viewHandler->handle($configuration, Argument::that($this->getViewComparingCallback($expectedView)))->willReturn($response); - - $this->applyStateMachineTransitionAction($request)->shouldReturn($response); - } - - function it_does_not_apply_state_machine_transition_resource_and_throws_http_exception_for_non_html_requests_stopped_via_event( - MetadataInterface $metadata, - RequestConfigurationFactoryInterface $requestConfigurationFactory, - RequestConfiguration $configuration, - AuthorizationCheckerInterface $authorizationChecker, - RepositoryInterface $repository, - ObjectManager $objectManager, - StateMachineInterface $stateMachine, - SingleResourceProviderInterface $singleResourceProvider, - ResourceInterface $resource, - FlashHelperInterface $flashHelper, - EventDispatcherInterface $eventDispatcher, - ResourceControllerEvent $event, - Request $request, - ): void { - $metadata->getApplicationName()->willReturn('sylius'); - $metadata->getName()->willReturn('product'); - - $requestConfigurationFactory->create($metadata, $request)->willReturn($configuration); - $configuration->hasPermission()->willReturn(true); - $configuration->getPermission(ResourceActions::UPDATE)->willReturn('sylius.product.update'); - $configuration->isCsrfProtectionEnabled()->willReturn(false); - - $authorizationChecker->isGranted($configuration, 'sylius.product.update')->willReturn(true); - $singleResourceProvider->get($configuration, $repository)->willReturn($resource); - - $configuration->isHtmlRequest()->willReturn(false); - - $eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource)->willReturn($event); - $event->isStopped()->willReturn(true); - $event->getMessage()->willReturn('Cannot approve this product.'); - $event->getErrorCode()->willReturn(500); - - $stateMachine->apply($configuration, $resource)->shouldNotBeCalled(); - $objectManager->flush()->shouldNotBeCalled(); - - $eventDispatcher->dispatchPostEvent(Argument::any())->shouldNotBeCalled(); - $flashHelper->addSuccessFlash(Argument::any())->shouldNotBeCalled(); - $flashHelper->addFlashFromEvent(Argument::any())->shouldNotBeCalled(); - - $this - ->shouldThrow(new HttpException(500, 'Cannot approve this product.')) - ->during('applyStateMachineTransitionAction', [$request]) - ; - } - - private function getViewComparingCallback(View $expectedView) - { - return function ($value) use ($expectedView) { - if (!$value instanceof View) { - return false; - } - - // Need to unwrap phpspec's Collaborators to ensure proper comparison. - $this->unwrapViewData($expectedView); - $this->nullifyDates($value); - $this->nullifyDates($expectedView); - - return - $expectedView->getStatusCode() === $value->getStatusCode() && - $expectedView->getHeaders() === $value->getHeaders() && - $expectedView->getFormat() === $value->getFormat() && - $expectedView->getData() === $value->getData() - ; - }; - } - - private function unwrapViewData(View $view) - { - $view->setData($this->unwrapIfCollaborator($view->getData())); - } - - private function unwrapIfCollaborator($value) - { - if (null === $value) { - return null; - } - - if ($value instanceof Collaborator) { - return $value->getWrappedObject(); - } - - if (is_array($value)) { - foreach ($value as $key => $childValue) { - $value[$key] = $this->unwrapIfCollaborator($childValue); - } - } - - return $value; - } - - private function nullifyDates(View $view) - { - $headers = $view->getHeaders(); - unset($headers['date']); - $view->setHeaders($headers); - } -} diff --git a/src/Bundle/spec/Controller/ResourceDeleteHandlerSpec.php b/src/Bundle/spec/Controller/ResourceDeleteHandlerSpec.php deleted file mode 100644 index c779e0768..000000000 --- a/src/Bundle/spec/Controller/ResourceDeleteHandlerSpec.php +++ /dev/null @@ -1,34 +0,0 @@ -shouldImplement(ResourceDeleteHandlerInterface::class); - } - - function it_removes_resource_via_repository(RepositoryInterface $repository, ResourceInterface $resource): void - { - $repository->remove($resource)->shouldBeCalled(); - - $this->handle($resource, $repository); - } -} diff --git a/src/Bundle/spec/Controller/ResourceFormFactorySpec.php b/src/Bundle/spec/Controller/ResourceFormFactorySpec.php deleted file mode 100644 index dbf12ae0c..000000000 --- a/src/Bundle/spec/Controller/ResourceFormFactorySpec.php +++ /dev/null @@ -1,63 +0,0 @@ -beConstructedWith($formFactory); - } - - function it_implements_resource_form_factory_interface(): void - { - $this->shouldImplement(ResourceFormFactoryInterface::class); - } - - function it_creates_appropriate_form_based_on_configuration( - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - FormFactoryInterface $formFactory, - FormInterface $form, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getFormType()->willReturn('sylius_product_pricing'); - $requestConfiguration->getFormOptions()->willReturn([]); - $formFactory->create('sylius_product_pricing', $resource, Argument::type('array'))->willReturn($form); - - $this->create($requestConfiguration, $resource)->shouldReturn($form); - } - - function it_creates_form_without_root_name_and_disables_csrf_protection_for_non_html_requests( - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - FormFactoryInterface $formFactory, - FormInterface $form, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(false); - $requestConfiguration->getFormType()->willReturn('sylius_product_api'); - $requestConfiguration->getFormOptions()->willReturn([]); - $formFactory->createNamed('', 'sylius_product_api', $resource, ['csrf_protection' => false])->willReturn($form); - - $this->create($requestConfiguration, $resource)->shouldReturn($form); - } -} diff --git a/src/Bundle/spec/Controller/ResourceUpdateHandlerSpec.php b/src/Bundle/spec/Controller/ResourceUpdateHandlerSpec.php deleted file mode 100644 index ee3784576..000000000 --- a/src/Bundle/spec/Controller/ResourceUpdateHandlerSpec.php +++ /dev/null @@ -1,62 +0,0 @@ -beConstructedWith($stateMachine); - } - - function it_implements_a_resource_update_handler_interface(): void - { - $this->shouldImplement(ResourceUpdateHandlerInterface::class); - } - - function it_applies_a_state_machine_transition( - StateMachineInterface $stateMachine, - ResourceInterface $resource, - RequestConfiguration $configuration, - ObjectManager $manager, - ): void { - $configuration->hasStateMachine()->willReturn(true); - $stateMachine->apply($configuration, $resource)->shouldBeCalled(); - - $manager->flush()->shouldBeCalled(); - - $this->handle($resource, $configuration, $manager); - } - - function it_does_not_apply_a_state_machine_transition( - StateMachineInterface $stateMachine, - ResourceInterface $resource, - RequestConfiguration $configuration, - ObjectManager $manager, - ): void { - $configuration->hasStateMachine()->willReturn(false); - $stateMachine->apply($configuration, $resource)->shouldNotBeCalled(); - - $manager->flush()->shouldBeCalled(); - - $this->handle($resource, $configuration, $manager); - } -} diff --git a/src/Bundle/spec/Controller/ResourcesCollectionProviderSpec.php b/src/Bundle/spec/Controller/ResourcesCollectionProviderSpec.php deleted file mode 100644 index 1b92ead68..000000000 --- a/src/Bundle/spec/Controller/ResourcesCollectionProviderSpec.php +++ /dev/null @@ -1,176 +0,0 @@ -beConstructedWith($resourcesResolver, null); - } - - function it_implements_resources_collection_provider_interface(): void - { - $this->shouldImplement(ResourcesCollectionProviderInterface::class); - } - - function it_returns_resources_resolved_from_repository( - ResourcesResolverInterface $resourcesResolver, - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceInterface $firstResource, - ResourceInterface $secondResource, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - - $resourcesResolver->getResources($requestConfiguration, $repository)->willReturn([$firstResource, $secondResource]); - - $this->get($requestConfiguration, $repository)->shouldReturn([$firstResource, $secondResource]); - } - - function it_handles_Pagerfanta( - ResourcesResolverInterface $resourcesResolver, - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - Pagerfanta $paginator, - Request $request, - ): void { - $queryParameters = new InputBag(); - - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getPaginationMaxPerPage()->willReturn(5); - - $resourcesResolver->getResources($requestConfiguration, $repository)->willReturn($paginator); - - $requestConfiguration->getRequest()->willReturn($request); - $request->query = $queryParameters; - $queryParameters->set('limit', 5); - $queryParameters->set('page', 6); - - $paginator->setMaxPerPage(5)->shouldBeCalled(); - $paginator->setCurrentPage(6)->shouldBeCalled(); - $paginator->getCurrentPageResults()->willReturn([]); - - $this->get($requestConfiguration, $repository)->shouldReturn($paginator); - } - - function it_restricts_max_pagination_limit_based_on_grid_configuration( - ResourcesResolverInterface $resourcesResolver, - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceGridView $gridView, - Grid $grid, - Pagerfanta $paginator, - Request $request, - ): void { - $queryParameters = new InputBag(); - - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getPaginationMaxPerPage()->willReturn(1000); - - $grid->getLimits()->willReturn([10, 20, 99]); - - $gridView->getDefinition()->willReturn($grid); - $gridView->getData()->willReturn($paginator); - - $resourcesResolver->getResources($requestConfiguration, $repository)->willReturn($gridView); - - $requestConfiguration->getRequest()->willReturn($request); - $request->query = $queryParameters; - $queryParameters->set('limit', 1000); - $queryParameters->set('page', 1); - - $paginator->setMaxPerPage(99)->shouldBeCalled(); - $paginator->setCurrentPage(1)->shouldBeCalled(); - $paginator->getCurrentPageResults()->willReturn([]); - - $this->get($requestConfiguration, $repository)->shouldReturn($gridView); - } - - function it_creates_a_paginated_representation_for_pagerfanta_for_non_html_requests( - RepositoryInterface $repository, - MetadataInterface $metadata, - ): void { - if (!class_exists(PagerfantaFactory::class)) { - throw new SkippingException('PagerfantaFactory is not installed.'); - } - - $this->beConstructedWith(new ResourcesResolver(), new PagerfantaFactory()); - - $paginator = new Pagerfanta(new ArrayAdapter([])); - $repository->createPaginator([], [])->willReturn($paginator); - - $request = new Request(); - $request->query = new InputBag(['limit' => 8, 'page' => 1]); - $request->attributes = new ParameterBag(['_format' => 'json', '_route' => 'sylius_product_index', '_route_params' => ['slug' => 'foo-bar']]); - $requestConfiguration = new RequestConfiguration($metadata->getWrappedObject(), $request, new Parameters(['paginate' => true])); - - $this->get($requestConfiguration, $repository)->shouldHaveType(PaginatedRepresentation::class); - } - - function it_handles_resource_grid_view( - ResourcesResolverInterface $resourcesResolver, - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceGridView $resourceGridView, - Grid $grid, - Pagerfanta $paginator, - Request $request, - ): void { - $queryParameters = new InputBag(); - - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getPaginationMaxPerPage()->willReturn(5); - - $resourcesResolver->getResources($requestConfiguration, $repository)->willReturn($resourceGridView); - $resourceGridView->getData()->willReturn($paginator); - - $grid->getLimits()->willReturn([10, 25, 50]); - $resourceGridView->getDefinition()->willReturn($grid); - - $requestConfiguration->getRequest()->willReturn($request); - $request->query = $queryParameters; - $queryParameters->set('limit', 5); - $queryParameters->set('page', 6); - - $paginator->setMaxPerPage(5)->shouldBeCalled(); - $paginator->setCurrentPage(6)->shouldBeCalled(); - $paginator->getCurrentPageResults()->willReturn([]); - - $this->get($requestConfiguration, $repository)->shouldReturn($resourceGridView); - } -} diff --git a/src/Bundle/spec/Controller/ResourcesResolverSpec.php b/src/Bundle/spec/Controller/ResourcesResolverSpec.php deleted file mode 100644 index eb5a09752..000000000 --- a/src/Bundle/spec/Controller/ResourcesResolverSpec.php +++ /dev/null @@ -1,128 +0,0 @@ -shouldImplement(ResourcesResolverInterface::class); - } - - function it_gets_all_resources_if_has_no_criteria( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceInterface $firstResource, - ResourceInterface $secondResource, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getRepositoryMethod(null)->willReturn(null); - - $requestConfiguration->isPaginated()->willReturn(false); - $requestConfiguration->isFilterable()->willReturn(false); - $requestConfiguration->isSortable()->willReturn(false); - $requestConfiguration->getLimit()->willReturn(null); - - $repository->findBy([], [], null)->willReturn([$firstResource, $secondResource]); - - $this->getResources($requestConfiguration, $repository)->shouldReturn([$firstResource, $secondResource]); - } - - function it_finds_resources_by_criteria_if_not_paginated( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceInterface $firstResource, - ResourceInterface $secondResource, - ResourceInterface $thirdResource, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getRepositoryMethod(null)->willReturn(null); - - $requestConfiguration->isPaginated()->willReturn(false); - $requestConfiguration->isFilterable()->willReturn(true); - $requestConfiguration->isSortable()->willReturn(true); - $requestConfiguration->isLimited()->willReturn(true); - $requestConfiguration->getLimit()->willReturn(15); - - $requestConfiguration->getCriteria()->willReturn(['custom' => 'criteria']); - $requestConfiguration->getSorting()->willReturn(['name' => 'desc']); - - $repository->findBy(['custom' => 'criteria'], ['name' => 'desc'], 15)->willReturn([$firstResource, $secondResource, $thirdResource]); - - $this->getResources($requestConfiguration, $repository)->shouldReturn([$firstResource, $secondResource, $thirdResource]); - } - - function it_uses_custom_method_and_arguments_if_specified( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceInterface $firstResource, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getRepositoryMethod()->willReturn('findAll'); - $requestConfiguration->getRepositoryArguments()->willReturn(['foo']); - - $requestConfiguration->isPaginated()->willReturn(false); - $requestConfiguration->isLimited()->willReturn(true); - $requestConfiguration->getLimit()->willReturn(15); - - $repository->findAll('foo')->willReturn([$firstResource]); - - $this->getResources($requestConfiguration, $repository)->shouldReturn([$firstResource]); - } - - function it_uses_custom_repository_if_specified( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - RepositoryInterface $customRepository, - ResourceInterface $firstResource, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getRepositoryMethod()->willReturn([$customRepository, 'findBy']); - $requestConfiguration->getRepositoryArguments()->willReturn([['foo' => true]]); - - $requestConfiguration->isPaginated()->willReturn(false); - $requestConfiguration->isLimited()->willReturn(true); - $requestConfiguration->getLimit()->willReturn(15); - - $customRepository->findBy(['foo' => true])->willReturn([$firstResource]); - - $this->getResources($requestConfiguration, $repository)->shouldReturn([$firstResource]); - } - - function it_creates_paginator_by_default( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - Pagerfanta $paginator, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - - $requestConfiguration->isPaginated()->willReturn(true); - $requestConfiguration->getPaginationMaxPerPage()->willReturn(5); - $requestConfiguration->isLimited()->willReturn(false); - $requestConfiguration->isFilterable()->willReturn(false); - $requestConfiguration->isSortable()->willReturn(false); - - $repository->createPaginator([], [])->willReturn($paginator); - - $this->getResources($requestConfiguration, $repository)->shouldReturn($paginator); - } -} diff --git a/src/Bundle/spec/Controller/SingleResourceProviderSpec.php b/src/Bundle/spec/Controller/SingleResourceProviderSpec.php deleted file mode 100644 index b8dbe69dd..000000000 --- a/src/Bundle/spec/Controller/SingleResourceProviderSpec.php +++ /dev/null @@ -1,174 +0,0 @@ -shouldImplement(SingleResourceProviderInterface::class); - } - - function it_looks_for_specific_resource_with_id_by_default( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ): void { - $requestConfiguration->getCriteria()->willReturn([]); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(true); - $requestAttributes->has('slug')->willReturn(false); - $requestAttributes->get('id')->willReturn(5); - - $repository->find(5)->willReturn(null); - - $this->get($requestConfiguration, $repository)->shouldReturn(null); - } - - function it_can_find_specific_resource_with_id_by_default( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getCriteria()->willReturn([]); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(true); - $requestAttributes->has('slug')->willReturn(false); - $requestAttributes->get('id')->willReturn(3); - - $repository->find(3)->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_can_find_specific_resource_with_slug_by_default( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getCriteria()->willReturn([]); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(false); - $requestAttributes->has('slug')->willReturn(true); - $requestAttributes->get('slug')->willReturn('the-most-awesome-hat'); - - $repository->findOneBy(['slug' => 'the-most-awesome-hat'])->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_can_find_specific_resource_with_custom_criteria( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getCriteria()->willReturn(['request-configuration-criteria' => '1']); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(false); - $requestAttributes->has('slug')->willReturn(false); - - $repository->findOneBy(['request-configuration-criteria' => '1'])->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_can_find_specific_resource_with_merged_custom_criteria( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getCriteria()->willReturn(['request-configuration-criteria' => '1']); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(false); - $requestAttributes->has('slug')->willReturn(true); - $requestAttributes->get('slug')->willReturn('banana'); - - $repository->findOneBy(['slug' => 'banana', 'request-configuration-criteria' => '1'])->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_can_find_specific_resource_with_merged_custom_criteria_overwriting_the_attributes( - RequestConfiguration $requestConfiguration, - Request $request, - ParameterBag $requestAttributes, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getCriteria()->willReturn(['id' => 5]); - $requestConfiguration->getRepositoryMethod()->willReturn(null); - $requestConfiguration->getRequest()->willReturn($request); - $request->attributes = $requestAttributes; - $requestAttributes->has('id')->willReturn(false); - $requestAttributes->has('slug')->willReturn(false); - - $repository->findOneBy(['id' => 5])->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_uses_a_custom_method_if_configured( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getRepositoryMethod()->willReturn('findAll'); - $requestConfiguration->getRepositoryArguments()->willReturn(['foo']); - - $repository->findAll('foo')->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } - - function it_uses_a_custom_repository_if_configured( - RequestConfiguration $requestConfiguration, - RepositoryInterface $repository, - RepositoryInterface $customRepository, - ResourceInterface $resource, - ): void { - $requestConfiguration->getRepositoryMethod()->willReturn([$customRepository, 'findAll']); - $requestConfiguration->getRepositoryArguments()->willReturn(['foo']); - - $customRepository->findAll('foo')->willReturn($resource); - - $this->get($requestConfiguration, $repository)->shouldReturn($resource); - } -} diff --git a/src/Bundle/spec/Controller/StateMachineSpec.php b/src/Bundle/spec/Controller/StateMachineSpec.php deleted file mode 100644 index 8ba703342..000000000 --- a/src/Bundle/spec/Controller/StateMachineSpec.php +++ /dev/null @@ -1,103 +0,0 @@ -beConstructedWith($stateMachineFactory); - } - - function it_implements_state_machine_interface(): void - { - $this->shouldImplement(ResourceStateMachineInterface::class); - } - - function it_throws_an_exception_if_transition_is_not_defined_during_can(RequestConfiguration $requestConfiguration, ResourceInterface $resource): void - { - $requestConfiguration->hasStateMachine()->willReturn(false); - - $this - ->shouldThrow(new \InvalidArgumentException('State machine must be configured to apply transition, check your routing.')) - ->during('can', [$requestConfiguration, $resource]) - ; - } - - function it_throws_an_exception_if_transition_is_not_defined_during_apply(RequestConfiguration $requestConfiguration, ResourceInterface $resource): void - { - $requestConfiguration->hasStateMachine()->willReturn(false); - - $this - ->shouldThrow(new \InvalidArgumentException('State machine must be configured to apply transition, check your routing.')) - ->during('apply', [$requestConfiguration, $resource]) - ; - } - - function it_returns_if_configured_state_machine_can_transition( - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - FactoryInterface $stateMachineFactory, - StateMachineInterface $stateMachine, - ): void { - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineGraph()->willReturn('sylius_product_review_state'); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - - $stateMachineFactory->get($resource, 'sylius_product_review_state')->willReturn($stateMachine); - $stateMachine->can('reject')->willReturn(true); - - $this->can($requestConfiguration, $resource)->shouldReturn(true); - } - - function it_applies_configured_state_machine_transition_without_graph_configuration( - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - FactoryInterface $stateMachineFactory, - StateMachineInterface $stateMachine, - ): void { - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineGraph()->willReturn(null); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - $stateMachineFactory->get($resource, 'default')->willReturn($stateMachine); - - $stateMachineFactory->get($resource, 'default')->shouldBeCalled(); - $stateMachine->apply('reject')->shouldBeCalled(); - - $this->apply($requestConfiguration, $resource); - } - - function it_applies_configured_state_machine_transition_with_graph_configuration( - RequestConfiguration $requestConfiguration, - ResourceInterface $resource, - FactoryInterface $stateMachineFactory, - StateMachineInterface $stateMachine, - ): void { - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineGraph()->willReturn('sylius_product_review_state'); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - - $stateMachineFactory->get($resource, 'sylius_product_review_state')->willReturn($stateMachine); - $stateMachine->apply('reject')->shouldBeCalled(); - - $this->apply($requestConfiguration, $resource); - } -} diff --git a/src/Bundle/spec/Controller/ViewHandlerSpec.php b/src/Bundle/spec/Controller/ViewHandlerSpec.php deleted file mode 100644 index 3b42edb39..000000000 --- a/src/Bundle/spec/Controller/ViewHandlerSpec.php +++ /dev/null @@ -1,68 +0,0 @@ -beConstructedWith($restViewHandler); - } - - function it_implements_view_handler_interface(): void - { - $this->shouldImplement(ViewHandlerInterface::class); - } - - function it_handles_view_normally_for_html_requests( - RequestConfiguration $requestConfiguration, - ConfigurableViewHandlerInterface $restViewHandler, - Response $response, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(true); - $view = View::create(); - - $restViewHandler->handle($view)->willReturn($response); - - $this->handle($requestConfiguration, $view)->shouldReturn($response); - } - - function it_sets_proper_values_for_non_html_requests( - RequestConfiguration $requestConfiguration, - ConfigurableViewHandlerInterface $restViewHandler, - Response $response, - ): void { - $requestConfiguration->isHtmlRequest()->willReturn(false); - $view = View::create(); - $view->setContext(new Context()); - - $requestConfiguration->getSerializationGroups()->willReturn(['Detailed']); - $requestConfiguration->getSerializationVersion()->willReturn('2.0.0'); - - $restViewHandler->setExclusionStrategyGroups(['Detailed'])->shouldBeCalled(); - $restViewHandler->setExclusionStrategyVersion('2.0.0')->shouldBeCalled(); - - $restViewHandler->handle($view)->willReturn($response); - - $this->handle($requestConfiguration, $view)->shouldReturn($response); - } -} diff --git a/src/Bundle/spec/Controller/WorkflowSpec.php b/src/Bundle/spec/Controller/WorkflowSpec.php deleted file mode 100644 index 3096ddef1..000000000 --- a/src/Bundle/spec/Controller/WorkflowSpec.php +++ /dev/null @@ -1,128 +0,0 @@ -beConstructedWith($registry); - } - - function it_is_initializable(): void - { - $this->shouldHaveType(Workflow::class); - } - - function it_implements_state_machine_interface(): void - { - $this->shouldImplement(ResourceStateMachineInterface::class); - } - - function it_throws_an_exception_if_transition_is_not_defined_during_can(RequestConfiguration $requestConfiguration, ResourceInterface $resource): void - { - $requestConfiguration->hasStateMachine()->willReturn(false); - - $this - ->shouldThrow(new \InvalidArgumentException('State machine must be configured to apply transition, check your routing.')) - ->during('can', [$requestConfiguration, $resource]) - ; - } - - function it_throws_an_exception_if_transition_is_not_defined_during_apply(RequestConfiguration $requestConfiguration, ResourceInterface $resource): void - { - $requestConfiguration->hasStateMachine()->willReturn(false); - - $this - ->shouldThrow(new \InvalidArgumentException('State machine must be configured to apply transition, check your routing.')) - ->during('apply', [$requestConfiguration, $resource]) - ; - } - - function it_returns_if_configured_state_machine_can_transition_without_graph_configuration( - RequestConfiguration $requestConfiguration, - Registry $registry, - ResourceInterface $resource, - SymfonyWorkflow $workflow, - ): void { - $requestConfiguration->getStateMachineGraph()->willReturn(null); - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - $registry->get($resource, null)->willReturn($workflow); - $workflow->can($resource, 'reject')->willReturn(true); - - $this->can($requestConfiguration, $resource)->shouldReturn(true); - } - - function it_returns_if_configured_state_machine_can_transition_with_graph_configuration( - RequestConfiguration $requestConfiguration, - Registry $registry, - ResourceInterface $resource, - SymfonyWorkflow $workflow, - ): void { - $requestConfiguration->getStateMachineGraph()->willReturn('pull_request'); - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - $registry->get($resource, 'pull_request')->willReturn($workflow); - $workflow->can($resource, 'reject')->willReturn(true); - - $this->can($requestConfiguration, $resource)->shouldReturn(true); - } - - function it_applies_configured_state_machine_transition_without_graph_configuration( - RequestConfiguration $requestConfiguration, - Registry $registry, - ResourceInterface $resource, - SymfonyWorkflow $workflow, - Marking $marking, - ): void { - $requestConfiguration->getStateMachineGraph()->willReturn(null); - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - $registry->get($resource, null)->willReturn($workflow); - $workflow->apply($resource, 'reject')->willReturn($marking); - - $workflow->apply($resource, 'reject')->shouldBeCalled(); - - $this->apply($requestConfiguration, $resource); - } - - function it_applies_configured_state_machine_transition_with_graph_configuration( - RequestConfiguration $requestConfiguration, - Registry $registry, - ResourceInterface $resource, - SymfonyWorkflow $workflow, - Marking $marking, - ): void { - $requestConfiguration->getStateMachineGraph()->willReturn('pull_request'); - $requestConfiguration->hasStateMachine()->willReturn(true); - $requestConfiguration->getStateMachineTransition()->willReturn('reject'); - $registry->get($resource, 'pull_request')->willReturn($workflow); - $workflow->apply($resource, 'reject')->willReturn($marking); - - $registry->get($resource, 'pull_request')->shouldBeCalled(); - $workflow->apply($resource, 'reject')->shouldBeCalled(); - - $this->apply($requestConfiguration, $resource); - } -} diff --git a/tests/Bundle/Controller/DisabledAuthorizationCheckerTest.php b/tests/Bundle/Controller/DisabledAuthorizationCheckerTest.php new file mode 100644 index 000000000..9144b1fd6 --- /dev/null +++ b/tests/Bundle/Controller/DisabledAuthorizationCheckerTest.php @@ -0,0 +1,44 @@ +disabledAuthorizationChecker = new DisabledAuthorizationChecker(); + } + + public function testImplementsResourceControllerAuthorizationCheckerInterface(): void + { + $this->assertInstanceOf(AuthorizationCheckerInterface::class, $this->disabledAuthorizationChecker); + } + + public function testAlwaysReturnsTrue(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + $this->assertTrue($this->disabledAuthorizationChecker->isGranted($requestConfigurationMock, 'create')); + $this->assertTrue($this->disabledAuthorizationChecker->isGranted($requestConfigurationMock, 'update')); + $this->assertTrue($this->disabledAuthorizationChecker->isGranted($requestConfigurationMock, 'custom')); + } +} diff --git a/tests/Bundle/Controller/EventDispatcherTest.php b/tests/Bundle/Controller/EventDispatcherTest.php new file mode 100644 index 000000000..db8cc979e --- /dev/null +++ b/tests/Bundle/Controller/EventDispatcherTest.php @@ -0,0 +1,151 @@ +eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); + $this->eventDispatcher = new EventDispatcher($this->eventDispatcherMock); + } + + public function testImplementsEventDispatcherInterface(): void + { + $this->assertInstanceOf(ControllerEventDispatcherInterface::class, $this->eventDispatcher); + } + + public function testDispatchesAppropriateEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration(null); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.show'); + + $result = $this->eventDispatcher->dispatch(ResourceActions::SHOW, $requestConfiguration, $resource); + + $this->assertInstanceOf(ResourceControllerEvent::class, $result); + } + + public function testDispatchesAppropriateCustomEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration('register'); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.register'); + + $result = $this->eventDispatcher->dispatch(ResourceActions::CREATE, $requestConfiguration, $resource); + + $this->assertInstanceOf(ResourceControllerEvent::class, $result); + } + + public function testDispatchesEventForACollectionOfResources(): void + { + $requestConfiguration = $this->createRequestConfiguration('register'); + $resources = $this->createMock(Collection::class); + + $this->expectEventDispatched('sylius.product.register'); + + $result = $this->eventDispatcher->dispatchMultiple(ResourceActions::CREATE, $requestConfiguration, $resources); + + $this->assertInstanceOf(ResourceControllerEvent::class, $result); + } + + public function testDispatchesAppropriatePreEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration(null); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.pre_create'); + + $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $requestConfiguration, $resource); + } + + public function testDispatchesAppropriateCustomPreEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration('register'); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.pre_register'); + + $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $requestConfiguration, $resource); + } + + public function testDispatchesAppropriatePostEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration(null); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.post_create'); + + $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $requestConfiguration, $resource); + } + + public function testDispatchesAppropriateCustomPostEventForAResource(): void + { + $requestConfiguration = $this->createRequestConfiguration('register'); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectEventDispatched('sylius.product.post_register'); + + $result = $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $requestConfiguration, $resource); + + $this->assertInstanceOf(ResourceControllerEvent::class, $result); + } + + /** + * @return MockObject&RequestConfiguration + */ + private function createRequestConfiguration(?string $customEvent): MockObject + { + /** @var MockObject&MetadataInterface $metadata */ + $metadata = $this->createMock(MetadataInterface::class); + $metadata->method('getApplicationName')->willReturn('sylius'); + $metadata->method('getName')->willReturn('product'); + + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('getEvent')->willReturn($customEvent); + $requestConfiguration->method('getMetadata')->willReturn($metadata); + + return $requestConfiguration; + } + + private function expectEventDispatched(string $eventName): void + { + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatch') + ->with( + $this->isInstanceOf(ResourceControllerEvent::class), + $eventName, + ); + } +} diff --git a/tests/Bundle/Controller/FlashHelperTest.php b/tests/Bundle/Controller/FlashHelperTest.php new file mode 100644 index 000000000..7db49454a --- /dev/null +++ b/tests/Bundle/Controller/FlashHelperTest.php @@ -0,0 +1,270 @@ +requestStackMock = $this->createMock(RequestStack::class); + $this->sessionMock = $this->createMock(SessionInterface::class); + $this->translatorMock = $this->createMock(TranslatorInterface::class); + if (method_exists(RequestStack::class, 'getSession')) { + $this->flashHelper = new FlashHelper($this->requestStackMock, $this->translatorMock, 'en'); + + return; + } + $this->flashHelper = new FlashHelper($this->sessionMock, $this->translatorMock, 'en'); + } + + public function testImplementsFlashHelperInterface(): void + { + $this->assertInstanceOf(FlashHelperInterface::class, $this->flashHelper); + } + + public function testAddsResourceMessageByDefault(): void + { + /** @var MessageCatalogueInterface|MockObject $messageCatalogueMock */ + $messageCatalogueMock = $this->createMock(MessageCatalogueInterface::class); + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + + $this->translatorMock = $this->createMockForIntersectionOfInterfaces([TranslatorInterface::class, TranslatorBagInterface::class]); + $translator = $this->translatorMock; + assert($translator instanceof TranslatorInterface); + $this->flashHelper = new FlashHelper($this->requestStackMock, $translator, 'en'); + + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->translatorMock->expects($this->once())->method('getCatalogue')->with('en')->willReturn($messageCatalogueMock); + $messageCatalogueMock->expects($this->once())->method('has')->with('sylius.product.create', 'flashes')->willReturn(false); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', [ + 'message' => 'sylius.resource.create', + 'parameters' => ['%resource%' => 'Product'], + ]); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, ResourceActions::CREATE, $resourceMock); + } + + public function testAddsResourceMessageWhenCatalogueIsUnavailableAndGivenMessageCannotBeTranslated(): void + { + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $parameters = ['%resource%' => 'Product']; + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->translatorMock->expects($this->once())->method('trans')->with('sylius.product.create', $parameters, 'flashes')->willReturn('sylius.product.create'); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', [ + 'message' => 'sylius.resource.create', + 'parameters' => $parameters, + ]); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, ResourceActions::CREATE, $resourceMock); + } + + public function testAddsResourceMessageWhenCatalogueIsUnavailableAndGivenMessageCanBeTranslated(): void + { + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $parameters = ['%resource%' => 'Spoon']; + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('spoon'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with(ResourceActions::CREATE) + ->willReturn('%resource% is the best cutlery of them all!') + ; + $this->translatorMock->expects($this->once())->method('trans')->with('%resource% is the best cutlery of them all!', $parameters, 'flashes') + ->willReturn('Spoon is the best cutlery of them all!') + ; + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', [ + 'message' => '%resource% is the best cutlery of them all!', + 'parameters' => $parameters, + ]); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, ResourceActions::CREATE, $resourceMock); + } + + public function testAddsResourceMessageIfMessageWasNotFoundInTheCatalogue(): void + { + /** @var MessageCatalogueInterface|MockObject $messageCatalogueMock */ + $messageCatalogueMock = $this->createMock(MessageCatalogueInterface::class); + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + + /** @var ResourceInterface|MockObject $resourceMock */ + $this->translatorMock = $this->createMockForIntersectionOfInterfaces([TranslatorInterface::class, TranslatorBagInterface::class]); + $translator = $this->translatorMock; + assert($translator instanceof TranslatorInterface); + $this->flashHelper = new FlashHelper($this->requestStackMock, $translator, 'en'); + + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->translatorMock->expects($this->once())->method('getCatalogue')->with('en')->willReturn($messageCatalogueMock); + $messageCatalogueMock->expects($this->once())->method('has')->with('sylius.product.create', 'flashes')->willReturn(false); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', [ + 'message' => 'sylius.resource.create', + 'parameters' => ['%resource%' => 'Product'], + ]); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, ResourceActions::CREATE, $resourceMock); + } + + public function testAddsOverwrittenMessage(): void + { + /** @var MessageCatalogueInterface|MockObject $messageCatalogueMock */ + $messageCatalogueMock = $this->createMock(MessageCatalogueInterface::class); + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + + $this->translatorMock = $this->createMockForIntersectionOfInterfaces([TranslatorInterface::class, TranslatorBagInterface::class]); + $translator = $this->translatorMock; + assert($translator instanceof TranslatorInterface); + $this->flashHelper = new FlashHelper($this->requestStackMock, $translator, 'en'); + + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->translatorMock->expects($this->once())->method('getCatalogue')->with('en')->willReturn($messageCatalogueMock); + $messageCatalogueMock->expects($this->once())->method('has')->with('sylius.product.create', 'flashes')->willReturn(true); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', 'sylius.product.create'); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, ResourceActions::CREATE, $resourceMock); + } + + public function testAddsCustomMessage(): void + { + /** @var MessageCatalogueInterface|MockObject $messageCatalogueMock */ + $messageCatalogueMock = $this->createMock(MessageCatalogueInterface::class); + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + + $this->translatorMock = $this->createMockForIntersectionOfInterfaces([TranslatorInterface::class, TranslatorBagInterface::class]); + $translator = $this->translatorMock; + assert($translator instanceof TranslatorInterface); + $this->flashHelper = new FlashHelper($this->requestStackMock, $translator, 'en'); + + $metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('book'); + $requestConfigurationMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $requestConfigurationMock->expects($this->once())->method('getFlashMessage')->with('send')->willReturn('app.book.send'); + $this->translatorMock->expects($this->once())->method('getCatalogue')->with('en')->willReturn($messageCatalogueMock); + $messageCatalogueMock->expects($this->once())->method('has')->with('app.book.send', 'flashes')->willReturn(true); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with('success', 'app.book.send'); + $this->flashHelper->addSuccessFlash($requestConfigurationMock, 'send', $resourceMock); + } + + public function testAddsMessageFromEvent(): void + { + /** @var FlashBagInterface|MockObject $flashBagMock */ + $flashBagMock = $this->createMock(FlashBagInterface::class); + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + $eventMock->expects($this->once())->method('getMessage')->willReturn('sylius.channel.cannot_be_deleted'); + $eventMock->expects($this->once())->method('getMessageType')->willReturn(ResourceControllerEvent::TYPE_WARNING); + $eventMock->expects($this->once())->method('getMessageParameters')->willReturn(['%name%' => 'Germany Sylius Webshop']); + if (method_exists(RequestStack::class, 'getSession')) { + $this->requestStackMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); + } + $this->sessionMock->expects($this->once())->method('getBag')->with('flashes')->willReturn($flashBagMock); + $flashBagMock->expects($this->once())->method('add')->with(ResourceControllerEvent::TYPE_WARNING, [ + 'message' => 'sylius.channel.cannot_be_deleted', + 'parameters' => ['%name%' => 'Germany Sylius Webshop'], + ]); + $this->flashHelper->addFlashFromEvent($requestConfigurationMock, $eventMock); + } +} diff --git a/tests/Bundle/Controller/NewResourceFactoryTest.php b/tests/Bundle/Controller/NewResourceFactoryTest.php new file mode 100644 index 000000000..8505fa350 --- /dev/null +++ b/tests/Bundle/Controller/NewResourceFactoryTest.php @@ -0,0 +1,108 @@ +newResourceFactory = new NewResourceFactory(); + } + + public function testImplementsNewResourceFactoryInterface(): void + { + $this->assertInstanceOf(NewResourceFactoryInterface::class, $this->newResourceFactory); + } + + public function testCallsCreateNewByDefaultIfNoCustomMethodConfigured(): void + { + $requestConfiguration = $this->createRequestConfiguration(null, []); + $factory = $this->createMock(FactoryInterface::class); + $resource = $this->createMock(ResourceInterface::class); + + $factory + ->expects($this->once()) + ->method('createNew') + ->willReturn($resource); + + $result = $this->newResourceFactory->create($requestConfiguration, $factory); + + $this->assertSame($resource, $result); + } + + public function testCallsProperFactoryMethodsBasedOnConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration('createNew', ['00032']); + $factory = $this->createMock(FactoryInterface::class); + $resource = $this->createMock(ResourceInterface::class); + + $factory + ->expects($this->once()) + ->method('createNew') + ->with('00032') + ->willReturn($resource); + + $result = $this->newResourceFactory->create($requestConfiguration, $factory); + + $this->assertSame($resource, $result); + } + + public function testCallsProperServiceBasedOnConfiguration(): void + { + $customFactory = $this->createMock(FactoryInterface::class); + $requestConfiguration = $this->createRequestConfiguration([$customFactory, 'createNew'], ['foo', 'bar']); + $factory = $this->createMock(FactoryInterface::class); + $resource = $this->createMock(ResourceInterface::class); + + $customFactory + ->expects($this->once()) + ->method('createNew') + ->with('foo', 'bar') + ->willReturn($resource); + + $factory + ->expects($this->never()) + ->method('createNew'); + + $result = $this->newResourceFactory->create($requestConfiguration, $factory); + + $this->assertSame($resource, $result); + } + + /** + * @param string|array|null $factoryMethod + * @param array $factoryArguments + * + * @return MockObject&RequestConfiguration + */ + private function createRequestConfiguration(string|array|null $factoryMethod, array $factoryArguments): MockObject + { + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('getFactoryMethod')->willReturn($factoryMethod); + $requestConfiguration->method('getFactoryArguments')->willReturn($factoryArguments); + + return $requestConfiguration; + } +} diff --git a/tests/Bundle/Controller/ParametersParserTest.php b/tests/Bundle/Controller/ParametersParserTest.php new file mode 100644 index 000000000..ba6993b45 --- /dev/null +++ b/tests/Bundle/Controller/ParametersParserTest.php @@ -0,0 +1,184 @@ +parametersParser = new ParametersParser(new Container(), new ExpressionLanguage()); + } + + public function testImplementsParametersParserInterface(): void + { + $this->assertInstanceOf(ParametersParserInterface::class, $this->parametersParser); + } + + public function testParsesStringParameters(): void + { + $request = new Request(); + $request->request->set('string', 'Lorem ipsum'); + + $this->assertSame(['nested' => ['string' => 'Lorem ipsum']], $this->parametersParser + ->parseRequestValues(['nested' => ['string' => '$string']], $request)) + ; + } + + public function testParsesBooleanParameters(): void + { + $request = new Request(); + $request->request->set('boolean', true); + + $this->assertSame(['nested' => ['boolean' => true]], $this->parametersParser + ->parseRequestValues(['nested' => ['boolean' => '$boolean']], $request)) + ; + } + + public function testParsesArrayParameters(): void + { + $request = new Request(); + $request->request->set('array', ['foo' => 'bar']); + + $this->assertSame(['nested' => ['array' => ['foo' => 'bar']]], $this->parametersParser + ->parseRequestValues(['nested' => ['array' => '$array']], $request)) + ; + } + + public function testParsesStringParameterAndCastsItIntoInt(): void + { + $request = new Request(); + $request->request->set('int', '5'); + + $this->assertSame(['nested' => ['int' => 5]], $this->parametersParser + ->parseRequestValues(['nested' => ['int' => '!!int $int']], $request)) + ; + } + + public function testParsesStringParameterAndCastsItIntoFloat(): void + { + $request = new Request(); + $request->request->set('float', '5.4'); + + $this->assertSame(['nested' => ['float' => 5.4]], $this->parametersParser + ->parseRequestValues(['nested' => ['float' => '!!float $float']], $request)) + ; + } + + public function testThrowsExceptionIfStringParameterIsGoingToBeCastedIntoInvalidType(): void + { + $request = new Request(); + $request->request->set('int', 5); + $this->expectException(\InvalidArgumentException::class); + $this->parametersParser->parseRequestValues(['nested' => ['int' => '!!invalid $int']], $request); + } + + public function testThrowsExceptionIfInvalidTypecastIsProvided(): void + { + $request = new Request(); + $request->request->set('int', 5); + + $this->expectException(\InvalidArgumentException::class); + + $this->parametersParser->parseRequestValues(['nested' => ['int' => '!!int!! $int']], $request); + } + + public function testParsesStringParameterAndCastsItIntoBool(): void + { + $request = new Request(); + $request->request->set('bool0', '0'); + $request->request->set('bool1', '1'); + + $this->assertSame(['nested' => ['bool' => false]], $this->parametersParser + ->parseRequestValues(['nested' => ['bool' => '!!bool $bool0']], $request)) + ; + + $this->assertSame(['nested' => ['bool' => true]], $this->parametersParser + ->parseRequestValues(['nested' => ['bool' => '!!bool $bool1']], $request)) + ; + } + + public function testParsesAnExpressionAndCastsItIntoAGivenType(): void + { + $request = new Request(); + + $this->assertSame(['nested' => ['cast' => 5]], $this->parametersParser + ->parseRequestValues(['nested' => ['cast' => '!!int expr:"5"']], $request)) + ; + } + + public function testParsesAnExpressionWithSpacesAndCastsItIntoAGivenType(): void + { + $request = new Request(); + + $this->assertSame(['nested' => ['cast' => 10]], $this->parametersParser + ->parseRequestValues(['nested' => ['cast' => '!!int expr:"5" + "5"']], $request)) + ; + } + + public function testParsesExpressions(): void + { + $request = new Request(); + + $this->assertSame(['nested' => ['boolean' => true]], $this->parametersParser + ->parseRequestValues(['nested' => ['boolean' => 'expr:"foo" in ["foo", "bar"]']], $request)) + ; + } + + public function testParsesExpressionsWithStringParameters(): void + { + $request = new Request(); + $request->request->set('string', 'lorem ipsum'); + + $this->assertSame(['expression' => true], $this->parametersParser + ->parseRequestValues(['expression' => 'expr:$string === "lorem ipsum"'], $request)) + ; + } + + public function testParsesExpressionsWithScalarParameters(): void + { + $request = new Request(); + $request->request->set('number', 6); + + $this->assertSame(['expression' => true], $this->parametersParser + ->parseRequestValues(['expression' => 'expr:$number === 6'], $request)) + ; + } + + public function testThrowsAnExceptionIfArrayParameterIsInjectedIntoExpression(): void + { + $request = new Request(); + $request->request->set('array', ['foo', 'bar']); + $this->expectException(\InvalidArgumentException::class); + $this->parametersParser->parseRequestValues(['expression' => 'expr:"foo" in $array'], $request); + } + + public function testThrowsAnExceptionIfObjectParameterIsInjectedIntoExpression(): void + { + /** @var array|bool|float|int|string|null $objectMock */ + $objectMock = $this->createMock(\Stringable::class); + $request = new Request(); + $request->request->set('object', $objectMock); + $this->expectException(\InvalidArgumentException::class); + $this->parametersParser->parseRequestValues(['expression' => 'expr:$object.callMethod()'], $request); + } +} diff --git a/tests/Bundle/Controller/ParametersTest.php b/tests/Bundle/Controller/ParametersTest.php new file mode 100644 index 000000000..d07b5b265 --- /dev/null +++ b/tests/Bundle/Controller/ParametersTest.php @@ -0,0 +1,58 @@ +parameters = new Parameters(); + } + + public function testHasMutableParameters(): void + { + $this->parameters->replace(); + $this->assertSame([], $this->parameters->all()); + } + + public function testHasParameters(): void + { + $this->parameters->replace([ + 'criteria' => 'criteria', + 'paginate' => 'paginate', + ]); + + $this->assertSame([ + 'criteria' => 'criteria', + 'paginate' => 'paginate', + ], $this->parameters->all()); + } + + public function testGetsASingleParameterAndSupportsDefaultValue(): void + { + $this->parameters->replace([ + 'criteria' => 'criteria', + 'paginate' => 'paginate', + ]); + + $this->assertSame('criteria', $this->parameters->get('criteria')); + $this->assertNull($this->parameters->get('sorting')); + $this->assertSame('default', $this->parameters->get('sorting', 'default')); + } +} diff --git a/tests/Bundle/Controller/RedirectHandlerTest.php b/tests/Bundle/Controller/RedirectHandlerTest.php new file mode 100644 index 000000000..51493c779 --- /dev/null +++ b/tests/Bundle/Controller/RedirectHandlerTest.php @@ -0,0 +1,161 @@ +router = $this->createMock(RouterInterface::class); + $this->redirectHandler = new RedirectHandler($this->router); + $this->configuration = $this->createMock(RequestConfiguration::class); + $this->resource = $this->createMock(ResourceInterface::class); + } + + public function test_it_redirects_to_show_route(): void + { + $this->configuration + ->method('getRedirectRoute') + ->with('show') + ->willReturn('app_resource_show'); + + $this->configuration + ->method('getRedirectParameters') + ->willReturn(['id' => 1]); + + $this->router + ->method('generate') + ->with('app_resource_show', ['id' => 1]) + ->willReturn('/resource/1'); + + $response = $this->redirectHandler->redirectToResource($this->configuration, $this->resource); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/resource/1', $response->getTargetUrl()); + } + + public function test_it_falls_back_to_index_if_show_route_is_not_found(): void + { + $this->configuration + ->method('getRedirectRoute') + ->willReturnMap([ + ['show', 'app_resource_show'], + ['index', 'app_resource_index'], + ]); + + $this->configuration + ->method('getRedirectParameters') + ->willReturn([]); + + $this->router + ->method('generate') + ->willReturnCallback(function (string $route) { + if ($route === 'app_resource_show') { + throw new RouteNotFoundException(); + } + + return '/resource/'; + }); + + $response = $this->redirectHandler->redirectToResource($this->configuration, $this->resource); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/resource/', $response->getTargetUrl()); + } + + public function test_it_redirects_to_index(): void + { + $this->configuration + ->method('getRedirectRoute') + ->with('index') + ->willReturn('app_resource_index'); + + $this->configuration + ->method('getRedirectParameters') + ->willReturn([]); + + $this->router + ->method('generate') + ->with('app_resource_index', []) + ->willReturn('/resource/'); + + $response = $this->redirectHandler->redirectToIndex($this->configuration); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/resource/', $response->getTargetUrl()); + } + + public function test_it_redirects_to_referer(): void + { + $this->configuration + ->method('getRedirectReferer') + ->willReturn('/previous-page'); + + $response = $this->redirectHandler->redirectToRoute($this->configuration, 'referer'); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/previous-page', $response->getTargetUrl()); + } + + public function test_it_returns_header_redirection(): void + { + $this->configuration + ->method('isHeaderRedirection') + ->willReturn(true); + + $this->configuration + ->method('getRedirectHash') + ->willReturn('#hash'); + + $response = $this->redirectHandler->redirect($this->configuration, '/resource/1'); + + $this->assertInstanceOf(Response::class, $response); + $this->assertEquals('', $response->getContent()); + $this->assertEquals('/resource/1#hash', $response->headers->get('X-SYLIUS-LOCATION')); + } + + public function test_it_returns_standard_redirect_response(): void + { + $this->configuration + ->method('isHeaderRedirection') + ->willReturn(false); + + $this->configuration + ->method('getRedirectHash') + ->willReturn('#hash'); + + $response = $this->redirectHandler->redirect($this->configuration, '/resource/1'); + + $this->assertInstanceOf(RedirectResponse::class, $response); + $this->assertEquals('/resource/1#hash', $response->getTargetUrl()); + } +} diff --git a/tests/Bundle/Controller/RequestConfigurationFactoryTest.php b/tests/Bundle/Controller/RequestConfigurationFactoryTest.php new file mode 100644 index 000000000..521721a1d --- /dev/null +++ b/tests/Bundle/Controller/RequestConfigurationFactoryTest.php @@ -0,0 +1,268 @@ +parametersParserMock = $this->createMock(ParametersParserInterface::class); + $this->requestConfigurationFactory = new RequestConfigurationFactory($this->parametersParserMock, RequestConfiguration::class); + } + + public function testImplementsRequestConfigurationFactoryInterface(): void + { + $this->assertInstanceOf(RequestConfigurationFactoryInterface::class, $this->requestConfigurationFactory); + } + + public function testCreatesConfigurationFromResourceMetadataAndRequest(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn([]); + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn(['template' => ':Product:show.html.twig']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['template' => ':Product:show.html.twig'], $requestMock) + ->willReturn(['template' => ':Product:list.html.twig']) + ; + $this->assertInstanceOf(RequestConfiguration::class, $this->requestConfigurationFactory->create($metadataMock, $requestMock)); + } + + public function testCreatesConfigurationWithoutDefaultSettings(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn([]); + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn(['template' => ':Product:list.html.twig']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['template' => ':Product:list.html.twig'], $requestMock) + ->willReturn(['template' => ':Product:list.html.twig']) + ; + $this->assertFalse($this->requestConfigurationFactory->create($metadataMock, $requestMock)->isSortable()); + } + + public function testCreatesConfigurationForSerializationGroupFromSingleHeader(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([ + 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], + ]); + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['groups=Default,Detailed']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with([ + 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], + 'serialization_groups' => ['Default', 'Detailed'], + ], $requestMock) + ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) + ; + $this->assertSame(['Default', 'Detailed'], $this->requestConfigurationFactory->create($metadataMock, $requestMock)->getSerializationGroups()); + } + + public function testCreatesConfigurationForSerializationGroupFromMultipleHeaders(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([ + 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], + ]); + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['application/json', 'groups=Default,Detailed']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with([ + 'allowed_serialization_groups' => ['Default', 'Detailed', 'Other'], + 'serialization_groups' => ['Default', 'Detailed'], + ], $requestMock) + ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) + ; + $this->assertSame(['Default', 'Detailed'], $this->requestConfigurationFactory->create($metadataMock, $requestMock)->getSerializationGroups()); + } + + public function testCreatesConfigurationUsingOnlyThoseSerializationGroupsThatAreAllowed(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([ + 'allowed_serialization_groups' => ['Default'], + ]); + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['application/json', 'groups=Default,Detailed']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with([ + 'allowed_serialization_groups' => ['Default'], + 'serialization_groups' => ['Default'], + ], $requestMock) + ->willReturn(['serialization_groups' => ['Default']]) + ; + $this->assertSame(['Default'], $this->requestConfigurationFactory->create($metadataMock, $requestMock)->getSerializationGroups()); + } + + public function testCreatesConfigurationUsingOnlyThoseSerializationGroupsThatAreAllowedOrDefinedAsDefault(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([ + 'allowed_serialization_groups' => ['Default'], + 'serialization_groups' => ['Detailed'], + ]); + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['application/json', 'groups=Default,Detailed,Other']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with([ + 'allowed_serialization_groups' => ['Default'], + 'serialization_groups' => ['Default', 'Detailed'], + ], $requestMock) + ->willReturn(['serialization_groups' => ['Default', 'Detailed']]) + ; + $this->assertSame(['Default', 'Detailed'], $this->requestConfigurationFactory->create($metadataMock, $requestMock)->getSerializationGroups()); + } + + public function testCreatesConfigurationUsingOnlyThoseSerializationGroupsThatAreDefinedAsDefault(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([ + 'serialization_groups' => ['Detailed'], + ]); + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['application/json', 'groups=Default,Detailed,Other']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['serialization_groups' => ['Detailed']], $requestMock) + ->willReturn(['serialization_groups' => ['Detailed']]) + ; + $this->assertSame(['Detailed'], $this->requestConfigurationFactory->create($metadataMock, $requestMock)->getSerializationGroups()); + } + + public function testCreatesConfigurationForSerializationVersionFromSingleHeader(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['version=1.0.0']); + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([]); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['serialization_version' => '1.0.0'], $requestMock) + ->willReturn(['template' => ':Product:list.html.twig']) + ; + $this->assertFalse($this->requestConfigurationFactory->create($metadataMock, $requestMock)->isSortable()); + } + + public function testCreatesConfigurationForSerializationVersionFromMultipleHeaders(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn(['application/xml', 'version=1.0.0']); + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn([]); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['serialization_version' => '1.0.0'], $requestMock) + ->willReturn(['template' => ':Product:list.html.twig']) + ; + $this->assertFalse($this->requestConfigurationFactory->create($metadataMock, $requestMock)->isSortable()); + } + + public function testCreatesConfigurationWithDefaultSettings(): void + { + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var HeaderBag|MockObject $headersBagMock */ + $headersBagMock = $this->createMock(HeaderBag::class); + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $this->requestConfigurationFactory = new RequestConfigurationFactory($this->parametersParserMock, RequestConfiguration::class, ['sortable' => true]); + $requestMock->headers = $headersBagMock; + $requestMock->attributes = $attributesBagMock; + $headersBagMock->expects($this->any())->method('all')->with('Accept')->willReturn([]); + $attributesBagMock->expects($this->once())->method('get')->with('_sylius', [])->willReturn(['template' => ':Product:list.html.twig']); + $this->parametersParserMock->expects($this->once())->method('parseRequestValues')->with(['template' => ':Product:list.html.twig', 'sortable' => true], $requestMock) + ->willReturn(['template' => ':Product:list.html.twig', 'sortable' => true]) + ; + $this->assertTrue($this->requestConfigurationFactory->create($metadataMock, $requestMock)->isSortable()); + } +} diff --git a/tests/Bundle/Controller/RequestConfigurationTest.php b/tests/Bundle/Controller/RequestConfigurationTest.php new file mode 100644 index 000000000..59ce52057 --- /dev/null +++ b/tests/Bundle/Controller/RequestConfigurationTest.php @@ -0,0 +1,1007 @@ +metadataMock = $this->createMock(MetadataInterface::class); + $this->requestMock = $this->createMock(Request::class); + $this->parametersMock = $this->createMock(Parameters::class); + $this->requestConfiguration = new RequestConfiguration($this->metadataMock, $this->requestMock, $this->parametersMock); + } + + public function testHasRequest(): void + { + $this->assertSame($this->requestMock, $this->requestConfiguration->getRequest()); + } + + public function testHasMetadata(): void + { + $this->assertSame($this->metadataMock, $this->requestConfiguration->getMetadata()); + } + + public function testHasParameters(): void + { + $this->assertSame($this->parametersMock, $this->requestConfiguration->getParameters()); + } + + public function testChecksIfItsAHtmlRequest(): void + { + $this->requestMock->expects($this->once())->method('getRequestFormat')->willReturn('html'); + $this->assertTrue($this->requestConfiguration->isHtmlRequest()); + } + + public function testChecksIfItsNotAHtmlRequest(): void + { + $this->requestMock->expects($this->once())->method('getRequestFormat')->willReturn('json'); + $this->assertFalse($this->requestConfiguration->isHtmlRequest()); + } + + public function testReturnsDefaultTemplateNames(): void + { + $this->metadataMock->expects($this->exactly(5))->method('getTemplatesNamespace')->willReturn('@SyliusAdmin/Product'); + $this->assertSame('@SyliusAdmin/Product/index.html.twig', $this->requestConfiguration->getDefaultTemplate('index.html')); + $this->assertSame('@SyliusAdmin/Product/show.html.twig', $this->requestConfiguration->getDefaultTemplate('show.html')); + $this->assertSame('@SyliusAdmin/Product/create.html.twig', $this->requestConfiguration->getDefaultTemplate('create.html')); + $this->assertSame('@SyliusAdmin/Product/update.html.twig', $this->requestConfiguration->getDefaultTemplate('update.html')); + $this->assertSame('@SyliusAdmin/Product/custom.html.twig', $this->requestConfiguration->getDefaultTemplate('custom.html')); + } + + public function testReturnsDefaultTemplateNamesForADirectoryBasedTemplates(): void + { + $this->metadataMock->expects($this->exactly(5))->method('getTemplatesNamespace')->willReturn('book/Backend'); + $this->assertSame('book/Backend/index.html.twig', $this->requestConfiguration->getDefaultTemplate('index.html')); + $this->assertSame('book/Backend/show.html.twig', $this->requestConfiguration->getDefaultTemplate('show.html')); + $this->assertSame('book/Backend/create.html.twig', $this->requestConfiguration->getDefaultTemplate('create.html')); + $this->assertSame('book/Backend/update.html.twig', $this->requestConfiguration->getDefaultTemplate('update.html')); + $this->assertSame('book/Backend/custom.html.twig', $this->requestConfiguration->getDefaultTemplate('custom.html')); + } + + public function testTakesTheCustomTemplateIfSpecified(): void + { + $this->metadataMock->expects($this->once())->method('getTemplatesNamespace')->willReturn('@SyliusAdmin/Product'); + $this->parametersMock->expects($this->once())->method('get')->with('template', '@SyliusAdmin/Product/foo.html.twig')->willReturn('Product/show.html.twig'); + $this->assertSame('Product/show.html.twig', $this->requestConfiguration->getTemplate('foo.html')); + } + + public function testFormTypeAndOptionsArrayWithTypeOnly(): void + { + $this->parametersMock->method('get')->willReturn(['type' => 'sylius_custom_resource']); + + $this->assertSame('sylius_custom_resource', $this->requestConfiguration->getFormType()); + $this->assertSame([], $this->requestConfiguration->getFormOptions()); + } + + public function testFormTypeAndOptionsString(): void + { + $this->parametersMock->method('get')->willReturn('sylius_custom_resource'); + + $this->assertSame('sylius_custom_resource', $this->requestConfiguration->getFormType()); + $this->assertSame([], $this->requestConfiguration->getFormOptions()); + } + + public function testFormTypeAndOptionsArrayWithTypeAndOptions(): void + { + $this->parametersMock->method('get')->willReturn([ + 'type' => 'sylius_custom_resource', + 'options' => ['key' => 'value'], + ]); + + $this->assertSame('sylius_custom_resource', $this->requestConfiguration->getFormType()); + $this->assertSame(['key' => 'value'], $this->requestConfiguration->getFormOptions()); + } + + public function testFormTypeAndOptionsFallbackToMetadataWhenEmpty(): void + { + $this->parametersMock->method('get')->willReturn([]); + $this->metadataMock->method('getClass')->with('form')->willReturn('\Fully\Qualified\ClassName'); + + $this->assertSame('\Fully\Qualified\ClassName', $this->requestConfiguration->getFormType()); + $this->assertSame([], $this->requestConfiguration->getFormOptions()); + } + + public function testFormTypeAndOptionsFallbackToMetadataWithOptionsOnly(): void + { + $this->parametersMock->method('get')->willReturn(['options' => ['key' => 'value']]); + $this->metadataMock->method('getClass')->with('form')->willReturn('\Fully\Qualified\ClassName'); + + $this->assertSame('\Fully\Qualified\ClassName', $this->requestConfiguration->getFormType()); + $this->assertSame(['key' => 'value'], $this->requestConfiguration->getFormOptions()); + } + + public function testGeneratesFormTypeWithArrayConfiguration(): void + { + $this->parametersMock->expects($this->exactly(2))->method('get')->with('form')->willReturn(['type' => 'sylius_product', 'options' => ['validation_groups' => ['sylius']]]); + $this->assertSame('sylius_product', $this->requestConfiguration->getFormType()); + $this->assertSame(['validation_groups' => ['sylius']], $this->requestConfiguration->getFormOptions()); + } + + public function testGeneratesRouteNamesWithoutSection(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock->method('get')->with('section')->willReturn(null); + $this->assertSame('sylius_product_index', $this->requestConfiguration->getRouteName('index')); + $this->assertSame('sylius_product_show', $this->requestConfiguration->getRouteName('show')); + $this->assertSame('sylius_product_custom', $this->requestConfiguration->getRouteName('custom')); + } + + public function testGeneratesRouteNamesWithSection(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock->method('get')->with('section')->willReturn('admin'); + $this->assertSame('sylius_admin_product_index', $this->requestConfiguration->getRouteName('index')); + $this->assertSame('sylius_admin_product_show', $this->requestConfiguration->getRouteName('show')); + $this->assertSame('sylius_admin_product_custom', $this->requestConfiguration->getRouteName('custom')); + } + + public function testGeneratesRedirectReferer(): void + { + /** @var HeaderBag|MockObject $bagMock */ + $bagMock = $this->createMock(HeaderBag::class); + $this->requestMock->headers = $bagMock; + $bagMock->expects($this->once())->method('get')->with('referer')->willReturn('http://myurl.com'); + $this->parametersMock->expects($this->once())->method('get')->with('redirect')->willReturn(['referer' => 'http://myurl.com']); + $this->assertSame('http://myurl.com', $this->requestConfiguration->getRedirectReferer()); + } + + public function testGeneratesRedirectRouteWithoutRedirect(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['section', null, null], + ['redirect', null, null], + ]); + $this->assertSame('sylius_product_index', $this->requestConfiguration->getRedirectRoute('index')); + } + + public function testGeneratesRedirectRouteWithRedirectAsArray(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['section', null, null], + ['redirect', null, ['route' => 'myRoute']], + ]); + $this->assertSame('myRoute', $this->requestConfiguration->getRedirectRoute('show')); + } + + public function testGeneratesRedirectRouteWithRedirectAsString(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['section', null, null], + ['redirect', null, 'myRoute'], + ]); + $this->assertSame('myRoute', $this->requestConfiguration->getRedirectRoute('custom')); + } + + public function testRedirectRouteUsesSection(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock->method('get')->willReturnMap([ + ['section', null, 'admin'], + ['redirect', null, null], + ]); + + $this->assertSame('sylius_admin_product_index', $this->requestConfiguration->getRedirectRoute('index')); + } + + public function testRedirectRouteOverriddenWithArray(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock->method('get')->with('redirect')->willReturn(['route' => 'myRoute']); + $this->assertSame('myRoute', $this->requestConfiguration->getRedirectRoute('show')); + } + + public function testRedirectRouteOverriddenWithString(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + $this->parametersMock->method('get')->with('redirect')->willReturn('myRoute'); + $this->assertSame('myRoute', $this->requestConfiguration->getRedirectRoute('custom')); + } + + public function testReturnsEmptyRedirectParametersWhenRedirectIsNull(): void + { + $this->parametersMock->method('get')->willReturnMap([ + ['vars', [], []], + ['redirect', null, null], + ]); + + $this->assertSame([], $this->requestConfiguration->getVars()); + $this->assertSame([], $this->requestConfiguration->getRedirectParameters()); + } + + public function testReturnsEmptyRedirectParametersWhenRedirectIsString(): void + { + $this->parametersMock->method('get')->willReturn(['redirect' => 'string']); + + $this->assertSame([], $this->requestConfiguration->getRedirectParameters()); + } + + public function testReturnsEmptyRedirectParametersWhenRedirectHasEmptyArray(): void + { + $this->parametersMock->method('get')->willReturn(['redirect' => ['parameters' => []]]); + + $this->assertSame([], $this->requestConfiguration->getRedirectParameters()); + } + + public function testReturnsRedirectParametersWhenPresent(): void + { + $this->parametersMock->method('get')->willReturn(['redirect' => ['parameters' => ['myParameter']]]); + + $this->assertSame(['myParameter'], $this->requestConfiguration->getRedirectParameters()); + } + + public function testMergesExtraVarsWithRedirectParameters(): void + { + $extraVars = ['redirect' => ['parameters' => ['myExtraParameter']]]; + $this->parametersMock->method('get')->willReturnMap([ + ['vars', [], $extraVars], + ['redirect', null, ['parameters' => ['myParameter']]], + ]); + + $this->assertSame($extraVars, $this->requestConfiguration->getVars()); + $this->assertSame(['myParameter', 'myExtraParameter'], $this->requestConfiguration->getRedirectParameters(new \stdClass())); + } + + public function testIsLimitedReturnsTrueWhenLimitIsSet(): void + { + $this->parametersMock->method('get')->willReturn(10); + + $this->assertTrue($this->requestConfiguration->isLimited()); + } + + public function testIsLimitedReturnsFalseWhenLimitIsNotSet(): void + { + $this->parametersMock->method('get')->willReturn(null); + + $this->assertFalse($this->requestConfiguration->isLimited()); + } + + public function testGetLimitReturnsValue(): void + { + $this->parametersMock->method('get')->willReturnMap([ + ['limit', false, true], + ['limit', 10, 10], + ]); + + $this->assertSame(10, $this->requestConfiguration->getLimit()); + } + + public function testGetLimitReturnsNullWhenNotSet(): void + { + $this->parametersMock->method('get')->willReturnMap([ + ['limit', false, false], + ['limit', 10, null], + ]); + + $this->assertNull($this->requestConfiguration->getLimit()); + } + + public function testIsPaginatedReturnsTrueWhenLimitIsPositive(): void + { + $this->parametersMock->method('get')->willReturn(10); + + $this->assertTrue($this->requestConfiguration->isPaginated()); + } + + public function testIsPaginatedReturnsTrueWhenLimitIsZero(): void + { + $this->parametersMock->method('get')->willReturn(0); + + $this->assertTrue($this->requestConfiguration->isPaginated()); + } + + public function testIsPaginatedReturnsFalseWhenLimitIsNull(): void + { + $this->parametersMock->method('get')->willReturn(null); + + $this->assertFalse($this->requestConfiguration->isPaginated()); + } + + public function testIsPaginatedReturnsFalseWhenLimitIsFalse(): void + { + $this->parametersMock->method('get')->willReturn(false); + + $this->assertFalse($this->requestConfiguration->isPaginated()); + } + + public function testGetPaginationMaxPerPageReturnsCustomValue(): void + { + $this->parametersMock->method('get')->with('paginate', 10)->willReturn(20); + + $this->assertSame(20, $this->requestConfiguration->getPaginationMaxPerPage()); + } + + public function testGetPaginationMaxPerPageReturnsDefaultValue(): void + { + $this->parametersMock->method('get')->with('paginate', 10)->willReturn(10); + + $this->assertSame(10, $this->requestConfiguration->getPaginationMaxPerPage()); + } + + public function testIsFilterableReturnsTrue(): void + { + $this->parametersMock->method('get')->willReturn(true); + + $this->assertTrue($this->requestConfiguration->isFilterable()); + } + + public function testIsFilterableReturnsFalse(): void + { + $this->parametersMock->method('get')->willReturn(null); + + $this->assertFalse($this->requestConfiguration->isFilterable()); + } + + public function testHasNoFilterableParameter(): void + { + $defaultCriteria = ['property' => 'myValue']; + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['criteria', [], []], + ['filterable', false, false], + ]); + $this->assertIsIterable($this->requestConfiguration->getCriteria($defaultCriteria)); + $this->assertCount(1, $this->requestConfiguration->getCriteria($defaultCriteria)); + } + + public function testHasCriteriaParameter(): void + { + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + $criteria = ['property' => 'myNewValue']; + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['criteria', [], []], + ['filterable', false, true], + ]); + + $attributesBagMock->expects($this->once())->method('get')->with('criteria', $this->requestMock)->willReturn($this->requestMock); + $queryBag->set('criteria', $criteria); + $requestBag->set('criteria', []); + $this->assertSame($criteria, $this->requestConfiguration->getCriteria()); + } + + public function testHasCriteriaParameterInRequest(): void + { + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + $criteria = ['property' => 'myNewValue']; + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock + ->method('get') + ->willReturnMap([ + ['criteria', [], []], + ['filterable', false, true], + ]); + + $attributesBagMock->expects($this->once())->method('get')->with('criteria', $this->requestMock)->willReturn($this->requestMock); + $requestBag->set('criteria', $criteria); + $this->assertSame($criteria, $this->requestConfiguration->getCriteria()); + } + + public function testCriteriaIsOverriddenByQueryParameters(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $criteria = ['property' => 'myValue']; + $overriddenCriteria = ['other_property' => 'myNewValue']; + $expected = ['property' => 'myValue', 'other_property' => 'myNewValue']; + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['filterable', false, true], + ['criteria', [], $criteria], + ]); + $attributesBagMock->method('get')->with('criteria', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('criteria', $overriddenCriteria); + $requestBag->set('criteria', []); + + $this->assertSame($expected, $this->requestConfiguration->getCriteria()); + } + + public function testCriteriaMergesWithDefaultCriteriaWhenOverridden(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $criteria = ['property' => 'myValue']; + $overriddenCriteria = ['other_property' => 'myNewValue']; + $defaultCriteria = ['slug' => 'foo']; + $expected = ['property' => 'myValue', 'slug' => 'foo', 'other_property' => 'myNewValue']; + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['filterable', false, true], + ['criteria', [], $criteria], + ]); + $attributesBagMock->method('get')->with('criteria', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('criteria', $overriddenCriteria); + $requestBag->set('criteria', []); + + $this->assertSame($expected, $this->requestConfiguration->getCriteria($defaultCriteria)); + } + + public function testQueryCriteriaTakesPrecedenceOverDefaultAndRouteCriteria(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $criteria = ['filter' => 'route']; + $expected = ['filter' => 'request']; + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['filterable', false, true], + ['criteria', [], $criteria], + ]); + $attributesBagMock->method('get')->with('criteria', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('criteria', ['filter' => 'request']); + $requestBag->set('criteria', []); + + $this->assertSame($expected, $this->requestConfiguration->getCriteria(['filter' => 'default'])); + } + + public function testResourceIsSortableWhenParameterIsTrue(): void + { + $this->parametersMock + ->method('get') + ->with('sortable', false) + ->willReturn(true); + + $this->assertTrue($this->requestConfiguration->isSortable()); + } + + public function testResourceIsNotSortableWhenParameterIsNull(): void + { + $this->parametersMock + ->method('get') + ->with('sortable', false) + ->willReturn(null); + + $this->assertFalse($this->requestConfiguration->isSortable()); + } + + public function testHasSortingParameter(): void + { + /** @var ParameterBag|MockObject $attributesBagMock */ + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + $sorting = ['property' => 'asc']; + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['sortable', false, true], + ['sorting', [], $sorting], + ]); + + $attributesBagMock->expects($this->once())->method('get')->with('sorting', $this->requestMock)->willReturn($this->requestMock); + $queryBag->set('sorting', $sorting); + $requestBag->set('sorting', []); + $this->assertSame($sorting, $this->requestConfiguration->getSorting()); + } + + public function testHasNoSortableParameter(): void + { + $defaultSorting = ['property' => 'desc']; + + $this->parametersMock->method('get')->willReturnMap([ + ['sortable', false, false], + ['sorting', [], []], + ]); + + $this->assertIsIterable($this->requestConfiguration->getSorting($defaultSorting)); + $this->assertCount(1, $this->requestConfiguration->getSorting($defaultSorting)); + } + + public function testSortingIsOverriddenByQueryParameters(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $sorting = ['property' => 'desc']; + $overriddenSorting = ['other_property' => 'asc']; + $expected = ['other_property' => 'asc', 'property' => 'desc']; + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['sortable', false, true], + ['sorting', [], $sorting], + ]); + $attributesBagMock->method('get')->with('sorting', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('sorting', $overriddenSorting); + $requestBag->set('sorting', []); + + $this->assertSame($expected, $this->requestConfiguration->getSorting()); + } + + public function testSortingMergesWithDefaultSortingWhenOverridden(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $sorting = ['property' => 'desc']; + $overriddenSorting = ['other_property' => 'asc']; + $defaultSorting = ['slug' => 'foo']; + $expected = ['other_property' => 'asc', 'property' => 'desc', 'slug' => 'foo']; + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['sortable', false, true], + ['sorting', [], $sorting], + ]); + $attributesBagMock->method('get')->with('sorting', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('sorting', $overriddenSorting); + $requestBag->set('sorting', []); + + $this->assertSame($expected, $this->requestConfiguration->getSorting($defaultSorting)); + } + + public function testQuerySortingTakesPrecedenceOverRouteAndDefaultSorting(): void + { + $attributesBagMock = $this->createMock(ParameterBag::class); + $queryBag = new InputBag(); + $requestBag = new InputBag(); + + $this->requestMock->attributes = $attributesBagMock; + $this->requestMock->query = $queryBag; + $this->requestMock->request = $requestBag; + + $this->parametersMock->method('get')->willReturnMap([ + ['sortable', false, true], + ['sorting', [], ['sort' => 'route']], + ]); + $attributesBagMock->method('get')->with('sorting', $this->requestMock)->willReturn($this->requestMock); + + $queryBag->set('sorting', ['sort' => 'request']); + $requestBag->set('sorting', []); + + $this->assertSame(['sort' => 'request'], $this->requestConfiguration->getSorting(['sort' => 'default'])); + } + + public function testGetRepositoryMethodReturnsNullIfRepositoryParamDoesNotExist(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('repository') + ->willReturn(false); + + $this->assertNull($this->requestConfiguration->getRepositoryMethod()); + } + + public function testGetRepositoryMethodReturnsConfiguredMethod(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('repository') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('repository') + ->willReturn(['method' => 'findAllEnabled']); + + $this->assertSame('findAllEnabled', $this->requestConfiguration->getRepositoryMethod()); + } + + public function testReturnsEmptyArrayWhenRepositoryConfigurationIsMissing(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('repository') + ->willReturn(false); + + $this->assertSame([], $this->requestConfiguration->getRepositoryArguments()); + } + + public function testReturnsRepositoryArgumentsWhenScalarValueProvided(): void + { + $repositoryConfiguration = ['arguments' => 'value']; + + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('repository') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('repository') + ->willReturn($repositoryConfiguration); + + $this->assertSame(['value'], $this->requestConfiguration->getRepositoryArguments()); + } + + public function testReturnsRepositoryArgumentsWhenArrayProvided(): void + { + $repositoryConfiguration = ['arguments' => ['foo, bar']]; + + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('repository') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('repository') + ->willReturn($repositoryConfiguration); + + $this->assertSame(['foo, bar'], $this->requestConfiguration->getRepositoryArguments()); + } + + public function testReturnsNullWhenFactoryConfigurationIsMissing(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('factory') + ->willReturn(false); + + $this->assertNull($this->requestConfiguration->getFactoryMethod()); + } + + public function testReturnsFactoryMethodWhenConfigured(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('factory') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('factory') + ->willReturn(['method' => 'createForPromotion']); + + $this->assertSame('createForPromotion', $this->requestConfiguration->getFactoryMethod()); + } + + public function testReturnsEmptyArrayWhenFactoryConfigurationIsMissing(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('factory') + ->willReturn(false); + + $this->assertSame([], $this->requestConfiguration->getFactoryArguments()); + } + + public function testReturnsFactoryArgumentsAsArrayWhenConfiguredWithScalar(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('factory') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('factory') + ->willReturn(['arguments' => 'value']); + + $this->assertSame(['value'], $this->requestConfiguration->getFactoryArguments()); + } + + public function testReturnsFactoryArgumentsAsArrayWhenConfiguredWithArray(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('factory') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('factory') + ->willReturn(['arguments' => ['foo, bar']]); + + $this->assertSame(['foo, bar'], $this->requestConfiguration->getFactoryArguments()); + } + + public function testReturnsDefaultFlashMessageForMessageAction(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('flash', 'sylius.product.message') + ->willReturn('sylius.product.message'); + + $this->assertSame('sylius.product.message', $this->requestConfiguration->getFlashMessage('message')); + } + + public function testReturnsCustomFlashMessageForFlashAction(): void + { + $this->metadataMock->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->method('getName')->willReturn('product'); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('flash', 'sylius.product.flash') + ->willReturn('sylius.product.myMessage'); + + $this->assertSame('sylius.product.myMessage', $this->requestConfiguration->getFlashMessage('flash')); + } + + public function testReturnsDefaultSortablePosition(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('sortable_position', 'position') + ->willReturn('position'); + + $this->assertSame('position', $this->requestConfiguration->getSortablePosition()); + } + + public function testReturnsCustomSortablePosition(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('sortable_position', 'position') + ->willReturn('myPosition'); + + $this->assertSame('myPosition', $this->requestConfiguration->getSortablePosition()); + } + + public function testShouldNotHavePermissionWhenPermissionIsFalse(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('permission', false) + ->willReturn(false); + + $this->assertFalse($this->requestConfiguration->hasPermission()); + } + + public function testShouldHavePermissionWhenPermissionIsCustomString(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('permission', false) + ->willReturn('custom_permission'); + + $this->assertTrue($this->requestConfiguration->hasPermission()); + } + + public function testGeneratesPermissionName(): void + { + $this->metadataMock->expects($this->once())->method('getApplicationName')->willReturn('sylius'); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->parametersMock->expects($this->once())->method('get')->with('permission')->willReturn(true); + $this->assertSame('sylius.product.index', $this->requestConfiguration->getPermission('index')); + } + + public function testTakesPermissionNameFromParametersIfProvided(): void + { + $this->parametersMock->expects($this->once())->method('get')->with('permission')->willReturn('app.sales_order.view_pricing'); + $this->assertSame('app.sales_order.view_pricing', $this->requestConfiguration->getPermission('index')); + } + + public function testThrowsAnExceptionWhenPermissionIsSetAsFalseInParametersButStillTryingToGetIt(): void + { + $this->parametersMock->expects($this->once())->method('get')->with('permission')->willReturn(null); + $this->expectException(\LogicException::class); + $this->requestConfiguration->getPermission('index'); + } + + public function testHasEventName(): void + { + $this->parametersMock->expects($this->once())->method('get')->with('event')->willReturn('foo'); + $this->assertSame('foo', $this->requestConfiguration->getEvent()); + } + + public function testReturnsNullWhenSectionIsNotSet(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('section') + ->willReturn(null); + + $this->assertNull($this->requestConfiguration->getSection()); + } + + public function testReturnsSectionWhenSet(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('section') + ->willReturn('admin'); + + $this->assertSame('admin', $this->requestConfiguration->getSection()); + } + + public function testHasVars(): void + { + $this->parametersMock->expects($this->once())->method('get')->with('vars', [])->willReturn(['foo' => 'bar']); + $this->assertSame(['foo' => 'bar'], $this->requestConfiguration->getVars()); + } + + public function testShouldNotHaveGridWhenGridNotDefined(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('grid') + ->willReturn(false); + + $this->assertFalse($this->requestConfiguration->hasGrid()); + } + + public function testShouldHaveGridWhenGridDefined(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('grid') + ->willReturn(true); + + $this->assertTrue($this->requestConfiguration->hasGrid()); + } + + public function testGetGridReturnsConfiguredValue(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('grid') + ->willReturn(true); + + $this->parametersMock + ->expects($this->once()) + ->method('get') + ->with('grid') + ->willReturn('sylius_admin_tax_category'); + + $this->assertSame('sylius_admin_tax_category', $this->requestConfiguration->getGrid()); + } + + public function testThrowsAnExceptionWhenTryingToRetrieveUndefinedGrid(): void + { + $this->parametersMock->expects($this->once())->method('has')->with('grid')->willReturn(false); + $this->expectException(\LogicException::class); + $this->requestConfiguration->getGrid(); + } + + public function testReturnsFalseWhenNoStateMachineConfigured(): void + { + $this->parametersMock + ->expects($this->once()) + ->method('has') + ->with('state_machine') + ->willReturn(false); + + $this->assertFalse($this->requestConfiguration->hasStateMachine()); + } + + public function testReturnsStateMachineDetailsWhenConfigured(): void + { + $stateMachineConfig = [ + 'graph' => 'sylius_product_review_state', + 'transition' => 'approve', + ]; + + $this->parametersMock + ->method('has') + ->with('state_machine') + ->willReturn(true); + + $this->parametersMock + ->method('get') + ->with('state_machine') + ->willReturn($stateMachineConfig); + + $this->assertTrue($this->requestConfiguration->hasStateMachine()); + $this->assertSame('sylius_product_review_state', $this->requestConfiguration->getStateMachineGraph()); + $this->assertSame('approve', $this->requestConfiguration->getStateMachineTransition()); + } +} diff --git a/tests/Bundle/Controller/ResourceControllerTest.php b/tests/Bundle/Controller/ResourceControllerTest.php new file mode 100644 index 000000000..1df76538e --- /dev/null +++ b/tests/Bundle/Controller/ResourceControllerTest.php @@ -0,0 +1,2580 @@ +metadataMock = $this->createMock(MetadataInterface::class); + $this->requestConfigurationFactoryMock = $this->createMock(RequestConfigurationFactoryInterface::class); + $this->viewHandlerMock = $this->createMock(ViewHandlerInterface::class); + $this->repositoryMock = $this->createMock(RepositoryInterface::class); + $this->factoryMock = $this->createMock(FactoryInterface::class); + $this->newResourceFactoryMock = $this->createMock(NewResourceFactoryInterface::class); + $this->managerMock = $this->createMock(ObjectManager::class); + $this->singleResourceProviderMock = $this->createMock(SingleResourceProviderInterface::class); + $this->resourcesCollectionProviderMock = $this->createMock(ResourcesCollectionProviderInterface::class); + $this->resourceFormFactoryMock = $this->createMock(ResourceFormFactoryInterface::class); + $this->redirectHandlerMock = $this->createMock(RedirectHandlerInterface::class); + $this->flashHelperMock = $this->createMock(FlashHelperInterface::class); + $this->authorizationCheckerMock = $this->createMock(AuthorizationCheckerInterface::class); + $this->eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); + $this->stateMachineMock = $this->createMock(StateMachineInterface::class); + $this->resourceUpdateHandlerMock = $this->createMock(ResourceUpdateHandlerInterface::class); + $this->resourceDeleteHandlerMock = $this->createMock(ResourceDeleteHandlerInterface::class); + $this->containerMock = $this->createMock(ContainerInterface::class); + $this->resourceController = new ResourceController($this->metadataMock, $this->requestConfigurationFactoryMock, $this->viewHandlerMock, $this->repositoryMock, $this->factoryMock, $this->newResourceFactoryMock, $this->managerMock, $this->singleResourceProviderMock, $this->resourcesCollectionProviderMock, $this->resourceFormFactoryMock, $this->redirectHandlerMock, $this->flashHelperMock, $this->authorizationCheckerMock, $this->eventDispatcherMock, $this->stateMachineMock, $this->resourceUpdateHandlerMock, $this->resourceDeleteHandlerMock); + $this->resourceController->setContainer($this->containerMock); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToViewASingleResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::SHOW)->willReturn('sylius.product.show'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.show')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->showAction($requestMock); + } + + public function testThrowsA404ExceptionIfResourceIsNotFoundBasedOnConfiguration(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::SHOW)->willReturn('sylius.product.show'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.show')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn(null); + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The "product" has not been found'); + $this->resourceController->showAction($requestMock); + } + + public function testReturnsAResponseForHtmlViewOfASingleResource(): void + { + $configurationMock = $this->createMock(RequestConfiguration::class); + $resourceMock = $this->createMock(ResourceInterface::class); + $twigMock = $this->createMock(Environment::class); + $requestMock = $this->createMock(Request::class); + + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once()) + ->method('getPermission') + ->with(ResourceActions::SHOW) + ->willReturn('sylius.product.show'); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.show') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once()) + ->method('getTemplate') + ->with(ResourceActions::SHOW . '.html') + ->willReturn('@SyliusShop/Product/show.html.twig'); + + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->method('get')->with('twig')->willReturn($twigMock); + + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $resourceMock, + 'product' => $resourceMock, + ]; + + $twigMock->expects($this->once()) + ->method('render') + ->with('@SyliusShop/Product/show.html.twig', $expectedContext) + ->willReturn('rendered'); + + $response = $this->resourceController->showAction($requestMock); + + $this->assertInstanceOf(Response::class, $response); + $this->assertSame('rendered', $response->getContent()); + } + + public function testReturnsEventResponseIfExistsDuringShow(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::SHOW)->willReturn('sylius.product.show'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.show')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatch')->with(ResourceActions::SHOW, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $configurationMock->expects($this->never())->method('isHtmlRequest'); + $this->viewHandlerMock->expects($this->never())->method('handle'); + $this->assertSame($responseMock, $this->resourceController->showAction($requestMock)); + } + + public function testReturnsAResponseForNonHtmlViewOfSingleResource(): void + { + $configurationMock = $this->createMock(RequestConfiguration::class); + $resourceMock = $this->createMock(ResourceInterface::class); + $requestMock = $this->createMock(Request::class); + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::SHOW)->willReturn('sylius.product.show'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.show')->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $this->eventDispatcherMock->expects($this->once())->method('dispatch')->with(ResourceActions::SHOW, $configurationMock, $resourceMock); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->showAction($requestMock)); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToViewAnIndexOfResources(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::INDEX)->willReturn('sylius.product.index'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.index')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->indexAction($requestMock); + } + + public function testReturnsAResponseForHtmlViewOfPaginatedResources(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resource1Mock */ + $resource1Mock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $resource2Mock */ + $resource2Mock = $this->createMock(ResourceInterface::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getPluralName')->willReturn('products'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::INDEX)->willReturn('sylius.product.index'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.index')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::INDEX . '.html')->willReturn('@SyliusShop/Product/index.html.twig'); + $this->resourcesCollectionProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn([$resource1Mock, $resource2Mock]); + $this->eventDispatcherMock->expects($this->once())->method('dispatchMultiple')->with(ResourceActions::INDEX, $configurationMock, [$resource1Mock, $resource2Mock]); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resources' => [$resource1Mock, $resource2Mock], + 'products' => [$resource1Mock, $resource2Mock], + ]; + $twigMock->expects($this->once())->method('render')->willReturnMap([['@SyliusShop/Product/index.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/index.html.twig', $expectedContext]]); + $this->resourceController->indexAction($requestMock); + } + + public function testReturnsEventResponseIfExistsDuringIndex(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceInterface|MockObject $resource1Mock */ + $resource1Mock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $resource2Mock */ + $resource2Mock = $this->createMock(ResourceInterface::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::INDEX)->willReturn('sylius.product.index'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.index')->willReturn(true); + $this->resourcesCollectionProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn([$resource1Mock, $resource2Mock]); + $this->eventDispatcherMock->expects($this->once())->method('dispatchMultiple')->with(ResourceActions::INDEX, $configurationMock, [$resource1Mock, $resource2Mock])->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $configurationMock->expects($this->never())->method('isHtmlRequest'); + $this->viewHandlerMock->expects($this->never())->method('handle'); + $this->assertSame($responseMock, $this->resourceController->indexAction($requestMock)); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToCreateANewResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->createAction($requestMock); + } + + public function testReturnsAHtmlResponseForCreatingNewResourceForm(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('POST')->willReturn(false); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $formMock->method('handleRequest')->willReturnMap([[$requestMock, $formMock], [$requestMock]]); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $newResourceMock, + 'product' => $newResourceMock, + 'form' => $formViewMock, + ]; + $twigMock->expects($this->once())->method('render')->with('@SyliusShop/Product/create.html.twig', $expectedContext)->willReturn('view'); + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/create.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/create.html.twig', $expectedContext]]); + $this->resourceController->createAction($requestMock); + } + + public function testReturnsAHtmlResponseForInvalidFormDuringResourceCreation(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->method('isSubmitted')->willReturn(true); + $formMock->method('isValid')->willReturn(false); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $newResourceMock, + 'product' => $newResourceMock, + 'form' => $formViewMock, + ]; + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/create.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/create.html.twig', $expectedContext]]); + $this->resourceController->createAction($requestMock); + } + + public function testReturnsAHtmlResponseForNotSubmittedFormDuringResourceCreation(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::CREATE . '.html')->willReturn('@SyliusShop/Product/create.html.twig'); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->method('isSubmitted')->willReturn(false); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $newResourceMock, + 'product' => $newResourceMock, + 'form' => $formViewMock, + ]; + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/create.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/create.html.twig', $expectedContext]]); + $this->resourceController->createAction($requestMock); + } + + public function testReturnsANonHtmlResponseForInvalidFormDuringResourceCreation(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.create') + ->willReturn(true); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + + $this->newResourceFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $this->factoryMock) + ->willReturn($newResourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $newResourceMock) + ->willReturn($formMock); + + $requestMock->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->method('isSubmitted')->willReturn(true); + $formMock->method('isValid')->willReturn(false); + + $expectedView = View::create($formMock, 400); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->createAction($requestMock)); + } + + public function testReturnsANonHtmlResponseForNotSubmittedFormDuringResourceCreation(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.create') + ->willReturn(true); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + + $this->newResourceFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $this->factoryMock) + ->willReturn($newResourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $newResourceMock) + ->willReturn($formMock); + + $requestMock->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->method('isSubmitted')->willReturn(false); + + $expectedView = View::create($formMock, 400); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->createAction($requestMock)); + } + + public function testDoesNotCreateTheResourceAndRedirectsToIndexForHtmlRequestsStoppedViaEvents(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->repositoryMock->expects($this->never())->method('add')->with($newResourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->redirectHandlerMock->expects($this->once())->method('redirectToIndex')->with($configurationMock, $newResourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->createAction($requestMock)); + } + + public function testDoesNotCreateTheResourceAndReturnResponseForHtmlRequestsStoppedViaEvents(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $this->repositoryMock->expects($this->never())->method('add')->with($newResourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->assertSame($responseMock, $this->resourceController->createAction($requestMock)); + } + + public function testRedirectsToNewlyCreatedResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $configurationMock->expects($this->once())->method('hasStateMachine')->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->stateMachineMock->expects($this->once())->method('apply')->with($configurationMock, $newResourceMock); + $this->repositoryMock->expects($this->once())->method('add')->with($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::CREATE, $newResourceMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $newResourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->createAction($requestMock)); + } + + public function testUsesResponseFromPostCreateEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $configurationMock->expects($this->once())->method('hasStateMachine')->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->stateMachineMock->expects($this->once())->method('apply')->with($configurationMock, $newResourceMock); + $this->repositoryMock->expects($this->once())->method('add')->with($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($postEventMock); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::CREATE, $newResourceMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->createAction($requestMock)); + } + + public function testReturnsANonHtmlResponseForCorrectlyCreatedResources(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $configurationMock->expects($this->once())->method('hasStateMachine')->willReturn(true); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.create') + ->willReturn(true); + + $configurationMock->method('isHtmlRequest')->willReturn(false); + + $this->newResourceFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $this->factoryMock) + ->willReturn($newResourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $newResourceMock) + ->willReturn($formMock); + + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::CREATE, $configurationMock, $newResourceMock) + ->willReturn($eventMock); + + $eventMock->method('isStopped')->willReturn(false); + + $this->stateMachineMock + ->expects($this->once()) + ->method('apply') + ->with($configurationMock, $newResourceMock); + + $this->repositoryMock + ->expects($this->once()) + ->method('add') + ->with($newResourceMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPostEvent') + ->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + + $expectedView = View::create($newResourceMock, 201); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->createAction($requestMock)); + } + + public function testDoesNotCreateTheResourceAndThrowsHttpExceptionForNonHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('isMethod')->with('POST')->willReturn(true); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($newResourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getMessage')->willReturn('You cannot add a new product right now.'); + $eventMock->expects($this->once())->method('getErrorCode')->willReturn(500); + $this->repositoryMock->expects($this->never())->method('add')->with($newResourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->expectException(HttpException::class); + $this->resourceController->createAction($requestMock); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToEditASingleResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->updateAction($requestMock); + } + + public function testThrowsA404ExceptionIfResourceToUpdateIsNotFoundBasedOnConfiguration(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn(null); + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The "product" has not been found'); + $this->resourceController->updateAction($requestMock); + } + + public function testReturnsAHtmlResponseForUpdatingResourceForm(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('PATCH')->willReturn(false); + $requestMock->method('getMethod')->willReturn('GET'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $resourceMock, + 'product' => $resourceMock, + 'form' => $formViewMock, + ]; + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/update.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/update.html.twig', $expectedContext]]); + $this->resourceController->updateAction($requestMock); + } + + public function testReturnsAHtmlResponseForInvalidFormDuringResourceUpdate(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('PATCH')->willReturn(false); + $requestMock->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->method('isSubmitted')->willReturn(true); + $formMock->method('isValid')->willReturn(false); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $resourceMock, + 'product' => $resourceMock, + 'form' => $formViewMock, + ]; + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/update.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/update.html.twig', $expectedContext]]); + $this->resourceController->updateAction($requestMock); + } + + public function testReturnsAHtmlResponseForNotSubmittedFormDuringResourceUpdate(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var FormView|MockObject $formViewMock */ + $formViewMock = $this->createMock(FormView::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('getTemplate')->with(ResourceActions::UPDATE . '.html')->willReturn('@SyliusShop/Product/update.html.twig'); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $requestMock->method('isMethod')->with('PATCH')->willReturn(false); + $requestMock->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->method('isSubmitted')->willReturn(false); + $formMock->expects($this->once())->method('createView')->willReturn($formViewMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->containerMock->expects($this->once())->method('get')->with('twig')->willReturn($twigMock); + $expectedContext = [ + 'configuration' => $configurationMock, + 'metadata' => $this->metadataMock, + 'resource' => $resourceMock, + 'product' => $resourceMock, + 'form' => $formViewMock, + ]; + $twigMock->method('render')->willReturnMap([['@SyliusShop/Product/update.html.twig', $expectedContext, 'view'], ['@SyliusShop/Product/update.html.twig', $expectedContext]]); + $this->resourceController->updateAction($requestMock); + } + + public function testReturnsANonHtmlResponseForInvalidFormDuringResourceUpdate(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.update') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $resourceMock) + ->willReturn($formMock); + + $requestMock->method('isMethod')->with('PATCH')->willReturn(true); + $requestMock->method('getMethod')->willReturn('PATCH'); + + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->method('isSubmitted')->willReturn(true); + $formMock->method('isValid')->willReturn(false); + + $expectedView = View::create($formMock, 400); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testReturnsANonHtmlResponseForNotSubmittedFormDuringResourceUpdate(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.update') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $resourceMock) + ->willReturn($formMock); + + $requestMock->method('isMethod')->with('PATCH')->willReturn(true); + $requestMock->method('getMethod')->willReturn('PATCH'); + + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->method('isSubmitted')->willReturn(false); + + $expectedView = View::create($formMock, 400); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testDoesNotUpdateTheResourceAndRedirectsToResourceForHtmlRequestIfStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $this->managerMock->expects($this->never())->method('flush'); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testRedirectsToUpdatedResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $preEventMock */ + $preEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($preEventMock); + $preEventMock->method('isStopped')->willReturn(false); + $this->resourceUpdateHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testUsesResponseFromPostUpdateEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $preEventMock */ + $preEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($preEventMock); + $preEventMock->method('isStopped')->willReturn(false); + $this->resourceUpdateHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn($redirectResponseMock); + $this->redirectHandlerMock->expects($this->never())->method('redirectToResource')->with($configurationMock, $resourceMock); + $this->assertSame($redirectResponseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testUsesResponseFromInitializeCreateEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $newResourceMock */ + $newResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $initializeEventMock */ + $initializeEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Environment|MockObject $twigMock */ + $twigMock = $this->createMock(Environment::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::CREATE)->willReturn('sylius.product.create'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.create')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->newResourceFactoryMock->expects($this->once())->method('create')->with($configurationMock, $this->factoryMock)->willReturn($newResourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $newResourceMock)->willReturn($formMock); + $requestMock->method('isMethod')->with('POST')->willReturn(false); + $formMock->expects($this->never())->method('createView'); + $formMock->method('handleRequest')->willReturnMap([[$requestMock, $formMock], [$requestMock]]); + $initializeEventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock)->willReturn($initializeEventMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPreEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::CREATE, $configurationMock, $newResourceMock); + $this->redirectHandlerMock->expects($this->never())->method('redirectToResource')->with($configurationMock, $newResourceMock); + $this->containerMock->method('has') + ->willReturnMap([ + ['templating', false], + ['twig', true], + ]); + $this->resourceController->createAction($requestMock); + } + + public function testUsesResponseFromInitializeUpdateEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $initializeEventMock */ + $initializeEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + $this->resourceUpdateHandlerMock->expects($this->never())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + $this->redirectHandlerMock->expects($this->never())->method('redirectToResource')->with($configurationMock, $resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchInitializeEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($initializeEventMock); + $initializeEventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $this->assertSame($responseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testReturnsANonHtmlResponseForCorrectlyUpdatedResource(): void + { + /** @var ParameterBagInterface|MockObject $parameterBagMock */ + $parameterBagMock = $this->createMock(ParameterBagInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->method('isHtmlRequest')->willReturn(false); + $configurationMock->expects($this->once())->method('getParameters')->willReturn($parameterBagMock); + + $parameterBagMock->expects($this->once())->method('get')->with('return_content', false)->willReturn(false); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.update') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $this->resourceFormFactoryMock + ->expects($this->once()) + ->method('create') + ->with($configurationMock, $resourceMock) + ->willReturn($formMock); + + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + + $formMock->expects($this->once())->method('handleRequest')->with($requestMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock) + ->willReturn($eventMock); + + $eventMock->method('isStopped')->willReturn(false); + + $this->resourceUpdateHandlerMock + ->expects($this->once()) + ->method('handle') + ->with($resourceMock, $configurationMock, $this->managerMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPostEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + + $expectedView = View::create(null, 204); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testDoesNotUpdateTheResourceThrowsAHttpExceptionForNonHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getMessage')->willReturn('Cannot update this channel.'); + $eventMock->expects($this->once())->method('getErrorCode')->willReturn(500); + $this->managerMock->expects($this->never())->method('flush'); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->expectException(HttpException::class); + $this->resourceController->updateAction($requestMock); + } + + public function testAppliesStateMachineTransitionToUpdatedResourceIfConfigured(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var Form|MockObject $formMock */ + $formMock = $this->createMock(Form::class); + /** @var ResourceControllerEvent|MockObject $preEventMock */ + $preEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $this->resourceFormFactoryMock->expects($this->once())->method('create')->with($configurationMock, $resourceMock)->willReturn($formMock); + $requestMock->expects($this->once())->method('getMethod')->willReturn('PUT'); + $formMock->expects($this->once())->method('handleRequest')->with($requestMock)->willReturn($formMock); + $formMock->expects($this->once())->method('isSubmitted')->willReturn(true); + $formMock->expects($this->once())->method('isValid')->willReturn(true); + $formMock->expects($this->once())->method('getData')->willReturn($resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($preEventMock); + $preEventMock->method('isStopped')->willReturn(false); + $this->resourceUpdateHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->updateAction($requestMock)); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToDeleteMultipleResources(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::BULK_DELETE)->willReturn('sylius.product.bulk_delete'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.bulk_delete')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->bulkDeleteAction($requestMock); + } + + public function testDeletesMultipleResourcesAndRedirectsToIndexForHtmlRequest(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $secondResourceMock */ + $secondResourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $firstPreEventMock */ + $firstPreEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $secondPreEventMock */ + $secondPreEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $firstPostEventMock */ + $firstPostEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $secondPostEventMock */ + $secondPostEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::BULK_DELETE)->willReturn('sylius.product.bulk_delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('bulk_delete', 'xyz'))->willReturn(true); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchMultiple') + ->with(ResourceActions::BULK_DELETE, $configurationMock, [$firstResourceMock, $secondResourceMock]); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.bulk_delete') + ->willReturn(true); + + $this->resourcesCollectionProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn([$firstResourceMock, $secondResourceMock]); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + + $this->eventDispatcherMock + ->expects($this->exactly(2)) + ->method('dispatchPreEvent') + ->willReturnCallback(function ($action, $configuration, $resource) use ($firstResourceMock, $secondResourceMock, $firstPreEventMock, $secondPreEventMock) { + if ($resource === $firstResourceMock) { + return $firstPreEventMock; + } + if ($resource === $secondResourceMock) { + return $secondPreEventMock; + } + + return null; + }); + + $firstPreEventMock->method('isStopped')->willReturn(false); + $secondPreEventMock->method('isStopped')->willReturn(false); + + $this->resourceDeleteHandlerMock + ->expects($this->exactly(2)) + ->method('handle') + ->willReturnCallback(function ($resource, $repository) use ($firstResourceMock, $secondResourceMock) { + static $call = 0; + ++$call; + + if ($call === 1) { + $this->assertSame($firstResourceMock, $resource); + } elseif ($call === 2) { + $this->assertSame($secondResourceMock, $resource); + } + + $this->assertSame($this->repositoryMock, $repository); + }); + + $this->eventDispatcherMock + ->expects($this->exactly(2)) + ->method('dispatchPostEvent') + ->willReturnCallback(function ($action, $configuration, $resource) use ($firstResourceMock, $secondResourceMock, $firstPostEventMock, $secondPostEventMock) { + if ($resource === $firstResourceMock) { + return $firstPostEventMock; + } + if ($resource === $secondResourceMock) { + return $secondPostEventMock; + } + + return null; + }); + + $secondPostEventMock->expects($this->once())->method('getResponse')->willReturn(null); + + $this->flashHelperMock + ->expects($this->once()) + ->method('addSuccessFlash') + ->with($configurationMock, ResourceActions::BULK_DELETE); + + $this->redirectHandlerMock + ->expects($this->once()) + ->method('redirectToIndex') + ->with($configurationMock) + ->willReturn($redirectResponseMock); + + $this->assertSame($redirectResponseMock, $this->resourceController->bulkDeleteAction($requestMock)); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToDeleteASingleResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->deleteAction($requestMock); + } + + public function testThrowsA404ExceptionIfResourceForDeletionIsNotFoundBasedOnConfiguration(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn(null); + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The "product" has not been found'); + $this->resourceController->deleteAction($requestMock); + } + + public function testDeletesAResourceAndRedirectsToIndexByForHtmlRequest(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->resourceDeleteHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::DELETE, $resourceMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToIndex')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testUsesResponseFromPostDeleteEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->resourceDeleteHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::DELETE, $resourceMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testDoesNotDeleteAResourceAndRedirectsToIndexForHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->resourceDeleteHandlerMock->expects($this->never())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash')->with($configurationMock, ResourceActions::DELETE, $resourceMock); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToIndex')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testDoesNotDeleteAResourceAndUsesResponseFromEventIfDefined(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn($redirectResponseMock); + $this->resourceDeleteHandlerMock->expects($this->never())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash')->with($configurationMock, ResourceActions::DELETE, $resourceMock); + $this->redirectHandlerMock->expects($this->never())->method('redirectToIndex')->with($configurationMock, $resourceMock); + $this->assertSame($redirectResponseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testDoesNotCorrectlyDeleteAResourceAndReturns500ForNotHtmlResponse(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + + $csrfTokenManagerMock + ->expects($this->once()) + ->method('isTokenValid') + ->with(new CsrfToken('1', 'xyz')) + ->willReturn(true); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.delete') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::DELETE, $configurationMock, $resourceMock) + ->willReturn($eventMock); + + $this->resourceDeleteHandlerMock + ->expects($this->once()) + ->method('handle') + ->with($resourceMock, $this->repositoryMock) + ->willThrowException(new DeleteHandlingException()); + + $this->eventDispatcherMock + ->expects($this->never()) + ->method('dispatchPostEvent'); + + $expectedView = View::create(null, 500); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testDeletesAResourceAndReturns204ForNonHtmlRequests(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + + $csrfTokenManagerMock + ->expects($this->once()) + ->method('isTokenValid') + ->with(new CsrfToken('1', 'xyz')) + ->willReturn(true); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.delete') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::DELETE, $configurationMock, $resourceMock) + ->willReturn($eventMock); + + $this->resourceDeleteHandlerMock + ->expects($this->once()) + ->method('handle') + ->with($resourceMock, $this->repositoryMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPostEvent') + ->with(ResourceActions::DELETE, $configurationMock, $resourceMock); + + $expectedView = View::create(null, 204); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->deleteAction($requestMock)); + } + + public function testDoesNotDeleteAResourceAndThrowsHttpExceptionForNonHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::DELETE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getMessage')->willReturn('Cannot delete this product.'); + $eventMock->expects($this->once())->method('getErrorCode')->willReturn(500); + $this->resourceDeleteHandlerMock->expects($this->never())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->flashHelperMock->expects($this->never())->method('addFlashFromEvent'); + $this->expectException(HttpException::class); + $this->resourceController->deleteAction($requestMock); + } + + public function testThrowsA403ExceptionIfCsrfTokenIsInvalidDuringDeleteAction(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::DELETE)->willReturn('sylius.product.delete'); + $requestMock->request = new InputBag(['_csrf_token' => 'xyz']); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(false); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.delete')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn(1); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $eventMock->expects($this->never())->method('isStopped'); + $this->resourceDeleteHandlerMock->expects($this->never())->method('handle')->with($resourceMock, $this->repositoryMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->flashHelperMock->expects($this->never())->method('addFlashFromEvent'); + $this->expectException(HttpException::class); + $this->resourceController->deleteAction($requestMock); + } + + public function testThrowsA403ExceptionIfUserIsUnauthorizedToApplyStateMachineTransitionOnResource(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(false); + $this->expectException(AccessDeniedException::class); + $this->resourceController->applyStateMachineTransitionAction($requestMock); + } + + public function testThrowsA404ExceptionIfResourceIsNotFoundWhenTryingToApplyStateMachineTransition(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $this->metadataMock->expects($this->once())->method('getHumanizedName')->willReturn('product'); + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn(null); + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The "product" has not been found'); + $this->resourceController->applyStateMachineTransitionAction($requestMock); + } + + public function testDoesNotApplyStateMachineTransitionOnResourceIfNotApplicableAndReturns400BadRequest(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ObjectManager|MockObject $objectManagerMock */ + $objectManagerMock = $this->createMock(ObjectManager::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $requestMock->expects($this->once())->method('get')->with('_csrf_token')->willReturn('xyz'); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn('1'); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->stateMachineMock->expects($this->once())->method('can')->with($configurationMock, $resourceMock)->willReturn(false); + $this->stateMachineMock->expects($this->never())->method('apply')->with($configurationMock, $resourceMock); + $objectManagerMock->expects($this->never())->method('flush'); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->flashHelperMock->expects($this->never())->method('addFlashFromEvent'); + $this->expectException(BadRequestHttpException::class); + $this->resourceController->applyStateMachineTransitionAction($requestMock); + } + + public function testAppliesStateMachineTransitionToResourceAndRedirectsForHtmlRequest(): void + { + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $requestMock->expects($this->once())->method('get')->with('_csrf_token')->willReturn('xyz'); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn('1'); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->stateMachineMock->expects($this->once())->method('can')->with($configurationMock, $resourceMock)->willReturn(true); + $this->resourceUpdateHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testUsesResponseFromPostApplyStateMachineTransitionEventIfDefined(): void + { + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var ResourceControllerEvent|MockObject $postEventMock */ + $postEventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $requestMock->expects($this->once())->method('get')->with('_csrf_token')->willReturn('xyz'); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn('1'); + $configurationMock->method('isHtmlRequest')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(false); + $this->stateMachineMock->expects($this->once())->method('can')->with($configurationMock, $resourceMock)->willReturn(true); + $this->resourceUpdateHandlerMock->expects($this->once())->method('handle')->with($resourceMock, $configurationMock, $this->managerMock); + $this->flashHelperMock->expects($this->once())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($postEventMock); + $postEventMock->expects($this->once())->method('getResponse')->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testDoesNotApplyStateMachineTransitionOnResourceAndRedirectsForHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $redirectResponseMock */ + $redirectResponseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $requestMock->expects($this->once())->method('get')->with('_csrf_token')->willReturn('xyz'); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn('1'); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $this->managerMock->expects($this->never())->method('flush'); + $this->stateMachineMock->expects($this->never())->method('apply')->with($resourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn(null); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $this->redirectHandlerMock->expects($this->once())->method('redirectToResource')->with($configurationMock, $resourceMock)->willReturn($redirectResponseMock); + $this->assertSame($redirectResponseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testDoesNotApplyStateMachineTransitionOnResourceAndReturnEventResponseForHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var CsrfTokenManagerInterface|MockObject $csrfTokenManagerMock */ + $csrfTokenManagerMock = $this->createMock(CsrfTokenManagerInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(true); + $requestMock->expects($this->once())->method('get')->with('_csrf_token')->willReturn('xyz'); + $this->containerMock->expects($this->once())->method('has')->with('security.csrf.token_manager')->willReturn(true); + $this->containerMock->expects($this->once())->method('get')->with('security.csrf.token_manager')->willReturn($csrfTokenManagerMock); + $csrfTokenManagerMock->expects($this->once())->method('isTokenValid')->with(new CsrfToken('1', 'xyz'))->willReturn(true); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $resourceMock->expects($this->once())->method('getId')->willReturn('1'); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->method('isStopped')->willReturn(true); + $this->managerMock->expects($this->never())->method('flush'); + $this->stateMachineMock->expects($this->never())->method('apply')->with($resourceMock); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash')->with($configurationMock, ResourceActions::UPDATE, $resourceMock); + $this->flashHelperMock->expects($this->once())->method('addFlashFromEvent')->with($configurationMock, $eventMock); + $eventMock->expects($this->once())->method('getResponse')->willReturn($responseMock); + $this->assertSame($responseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testAppliesStateMachineTransitionOnResourceAndReturns200ForNonHtmlRequests(): void + { + /** @var ParameterBagInterface|MockObject $parameterBagMock */ + $parameterBagMock = $this->createMock(ParameterBagInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('getParameters')->willReturn($parameterBagMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(false); + $parameterBagMock->expects($this->once())->method('get')->with('return_content', true)->willReturn(true); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.update') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock) + ->willReturn($eventMock); + + $eventMock->method('isStopped')->willReturn(false); + + $this->stateMachineMock + ->expects($this->once()) + ->method('can') + ->with($configurationMock, $resourceMock) + ->willReturn(true); + + $this->resourceUpdateHandlerMock + ->expects($this->once()) + ->method('handle') + ->with($resourceMock, $configurationMock, $this->managerMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPostEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + + $expectedView = View::create($resourceMock, 200); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testAppliesStateMachineTransitionOnResourceAndReturns204ForNonHtmlRequestsIfAdditionalOptionAdded(): void + { + /** @var ParameterBagInterface|MockObject $parameterBagMock */ + $parameterBagMock = $this->createMock(ParameterBagInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + + $this->requestConfigurationFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->metadataMock, $requestMock) + ->willReturn($configurationMock); + + $configurationMock->expects($this->once())->method('getParameters')->willReturn($parameterBagMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(false); + $parameterBagMock->expects($this->once())->method('get')->with('return_content', true)->willReturn(false); + + $this->authorizationCheckerMock + ->expects($this->once()) + ->method('isGranted') + ->with($configurationMock, 'sylius.product.update') + ->willReturn(true); + + $this->singleResourceProviderMock + ->expects($this->once()) + ->method('get') + ->with($configurationMock, $this->repositoryMock) + ->willReturn($resourceMock); + + $configurationMock->method('isHtmlRequest')->willReturn(false); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPreEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock) + ->willReturn($eventMock); + + $eventMock->method('isStopped')->willReturn(false); + + $this->stateMachineMock + ->expects($this->once()) + ->method('can') + ->with($configurationMock, $resourceMock) + ->willReturn(true); + + $this->resourceUpdateHandlerMock + ->expects($this->once()) + ->method('handle') + ->with($resourceMock, $configurationMock, $this->managerMock); + + $this->eventDispatcherMock + ->expects($this->once()) + ->method('dispatchPostEvent') + ->with(ResourceActions::UPDATE, $configurationMock, $resourceMock); + + $expectedView = View::create(null, 204); + + $this->viewHandlerMock + ->expects($this->once()) + ->method('handle') + ->with( + $this->anything(), + $this->callback(function ($view) use ($expectedView) { + return $view instanceof View && + $view->getData() === $expectedView->getData() && + $view->getStatusCode() === $expectedView->getStatusCode(); + }), + ) + ->willReturn($responseMock); + + $this->assertSame($responseMock, $this->resourceController->applyStateMachineTransitionAction($requestMock)); + } + + public function testDoesNotApplyStateMachineTransitionResourceAndThrowsHttpExceptionForNonHtmlRequestsStoppedViaEvent(): void + { + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ObjectManager|MockObject $objectManagerMock */ + $objectManagerMock = $this->createMock(ObjectManager::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceControllerEvent|MockObject $eventMock */ + $eventMock = $this->createMock(ResourceControllerEvent::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + + $this->requestConfigurationFactoryMock->expects($this->once())->method('create')->with($this->metadataMock, $requestMock)->willReturn($configurationMock); + $configurationMock->expects($this->once())->method('hasPermission')->willReturn(true); + $configurationMock->expects($this->once())->method('getPermission')->with(ResourceActions::UPDATE)->willReturn('sylius.product.update'); + $configurationMock->expects($this->once())->method('isCsrfProtectionEnabled')->willReturn(false); + $this->authorizationCheckerMock->expects($this->once())->method('isGranted')->with($configurationMock, 'sylius.product.update')->willReturn(true); + $this->singleResourceProviderMock->expects($this->once())->method('get')->with($configurationMock, $this->repositoryMock)->willReturn($resourceMock); + $configurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $this->eventDispatcherMock->expects($this->once())->method('dispatchPreEvent')->with(ResourceActions::UPDATE, $configurationMock, $resourceMock)->willReturn($eventMock); + $eventMock->expects($this->once())->method('isStopped')->willReturn(true); + $eventMock->expects($this->once())->method('getMessage')->willReturn('Cannot approve this product.'); + $eventMock->expects($this->once())->method('getErrorCode')->willReturn(500); + $this->stateMachineMock->expects($this->never())->method('apply')->with($configurationMock, $resourceMock); + $objectManagerMock->expects($this->never())->method('flush'); + $this->eventDispatcherMock->expects($this->never())->method('dispatchPostEvent'); + $this->flashHelperMock->expects($this->never())->method('addSuccessFlash'); + $this->flashHelperMock->expects($this->never())->method('addFlashFromEvent'); + $this->expectException(HttpException::class); + $this->resourceController->applyStateMachineTransitionAction($requestMock); + } +} diff --git a/tests/Bundle/Controller/ResourceDeleteHandlerTest.php b/tests/Bundle/Controller/ResourceDeleteHandlerTest.php new file mode 100644 index 000000000..2c098af6f --- /dev/null +++ b/tests/Bundle/Controller/ResourceDeleteHandlerTest.php @@ -0,0 +1,46 @@ +resourceDeleteHandler = new ResourceDeleteHandler(); + } + + public function testImplementsAResourceDeleteHandlerInterface(): void + { + $this->assertInstanceOf(ResourceDeleteHandlerInterface::class, $this->resourceDeleteHandler); + } + + public function testRemovesResourceViaRepository(): void + { + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $repositoryMock->expects($this->once())->method('remove')->with($resourceMock); + $this->resourceDeleteHandler->handle($resourceMock, $repositoryMock); + } +} diff --git a/tests/Bundle/Controller/ResourceFormFactoryTest.php b/tests/Bundle/Controller/ResourceFormFactoryTest.php new file mode 100644 index 000000000..88973efe8 --- /dev/null +++ b/tests/Bundle/Controller/ResourceFormFactoryTest.php @@ -0,0 +1,72 @@ +formFactoryMock = $this->createMock(FormFactoryInterface::class); + $this->resourceFormFactory = new ResourceFormFactory($this->formFactoryMock); + } + + public function testImplementsResourceFormFactoryInterface(): void + { + $this->assertInstanceOf(ResourceFormFactoryInterface::class, $this->resourceFormFactory); + } + + public function testCreatesAppropriateFormBasedOnConfiguration(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var FormInterface|MockObject $formMock */ + $formMock = $this->createMock(FormInterface::class); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('getFormType')->willReturn('sylius_product_pricing'); + $requestConfigurationMock->expects($this->once())->method('getFormOptions')->willReturn([]); + $this->formFactoryMock->expects($this->once())->method('create')->with('sylius_product_pricing', $resourceMock, $this->isType('array'))->willReturn($formMock); + $this->assertSame($formMock, $this->resourceFormFactory->create($requestConfigurationMock, $resourceMock)); + } + + public function testCreatesFormWithoutRootNameAndDisablesCsrfProtectionForNonHtmlRequests(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var FormInterface|MockObject $formMock */ + $formMock = $this->createMock(FormInterface::class); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('getFormType')->willReturn('sylius_product_api'); + $requestConfigurationMock->expects($this->once())->method('getFormOptions')->willReturn([]); + $this->formFactoryMock->expects($this->once())->method('createNamed')->with('', 'sylius_product_api', $resourceMock, ['csrf_protection' => false])->willReturn($formMock); + $this->assertSame($formMock, $this->resourceFormFactory->create($requestConfigurationMock, $resourceMock)); + } +} diff --git a/tests/Bundle/Controller/ResourceUpdateHandlerTest.php b/tests/Bundle/Controller/ResourceUpdateHandlerTest.php new file mode 100644 index 000000000..8b883deb7 --- /dev/null +++ b/tests/Bundle/Controller/ResourceUpdateHandlerTest.php @@ -0,0 +1,70 @@ +stateMachineMock = $this->createMock(StateMachineInterface::class); + $this->resourceUpdateHandler = new ResourceUpdateHandler($this->stateMachineMock); + } + + public function testImplementsAResourceUpdateHandlerInterface(): void + { + $this->assertInstanceOf(ResourceUpdateHandlerInterface::class, $this->resourceUpdateHandler); + } + + public function testAppliesAStateMachineTransition(): void + { + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ObjectManager|MockObject $managerMock */ + $managerMock = $this->createMock(ObjectManager::class); + $configurationMock->expects($this->once())->method('hasStateMachine')->willReturn(true); + $this->stateMachineMock->expects($this->once())->method('apply')->with($configurationMock, $resourceMock); + $managerMock->expects($this->once())->method('flush'); + $this->resourceUpdateHandler->handle($resourceMock, $configurationMock, $managerMock); + } + + public function testDoesNotApplyAStateMachineTransition(): void + { + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + /** @var RequestConfiguration|MockObject $configurationMock */ + $configurationMock = $this->createMock(RequestConfiguration::class); + /** @var ObjectManager|MockObject $managerMock */ + $managerMock = $this->createMock(ObjectManager::class); + $configurationMock->expects($this->once())->method('hasStateMachine')->willReturn(false); + $this->stateMachineMock->expects($this->never())->method('apply')->with($configurationMock, $resourceMock); + $managerMock->expects($this->once())->method('flush'); + $this->resourceUpdateHandler->handle($resourceMock, $configurationMock, $managerMock); + } +} diff --git a/tests/Bundle/Controller/ResourcesCollectionProviderTest.php b/tests/Bundle/Controller/ResourcesCollectionProviderTest.php new file mode 100644 index 000000000..89260e251 --- /dev/null +++ b/tests/Bundle/Controller/ResourcesCollectionProviderTest.php @@ -0,0 +1,183 @@ +resourcesResolverMock = $this->createMock(ResourcesResolverInterface::class); + $this->resourcesCollectionProvider = new ResourcesCollectionProvider($this->resourcesResolverMock, null); + } + + public function testImplementsResourcesCollectionProviderInterface(): void + { + $this->assertInstanceOf(ResourcesCollectionProviderInterface::class, $this->resourcesCollectionProvider); + } + + public function testReturnsResourcesResolvedFromRepository(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $secondResourceMock */ + $secondResourceMock = $this->createMock(ResourceInterface::class); + $this->resourcesResolverMock->expects($this->once())->method('getResources')->with($requestConfigurationMock, $repositoryMock)->willReturn([$firstResourceMock, $secondResourceMock]); + $this->assertSame([$firstResourceMock, $secondResourceMock], $this->resourcesCollectionProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testHandlesPagerfanta(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var \Pagerfanta\Pagerfanta|MockObject $paginatorMock */ + $paginatorMock = $this->createMock(Pagerfanta::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $queryParameters = new InputBag(); + $queryParameters->set('limit', 5); + $queryParameters->set('page', 6); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('getPaginationMaxPerPage')->willReturn(5); + $this->resourcesResolverMock->expects($this->once())->method('getResources')->with($requestConfigurationMock, $repositoryMock)->willReturn($paginatorMock); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->query = $queryParameters; + $this->assertEquals(5, $requestMock->query->get('limit')); + $this->assertEquals(6, $requestMock->query->get('page')); + $paginatorMock->expects($this->once())->method('setMaxPerPage')->with(5); + $paginatorMock->expects($this->once())->method('setCurrentPage')->with(6); + $paginatorMock->expects($this->once())->method('getCurrentPageResults')->willReturn([]); + $this->assertSame($paginatorMock, $this->resourcesCollectionProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testRestrictsMaxPaginationLimitBasedOnGridConfiguration(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceGridView|MockObject $gridViewMock */ + $gridViewMock = $this->createMock(ResourceGridView::class); + /** @var Grid|MockObject $gridMock */ + $gridMock = $this->createMock(Grid::class); + /** @var \Pagerfanta\Pagerfanta|MockObject $paginatorMock */ + $paginatorMock = $this->createMock(Pagerfanta::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $queryParameters = new InputBag(); + $queryParameters->set('limit', 1000); + $queryParameters->set('page', 1); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('getPaginationMaxPerPage')->willReturn(1000); + $gridMock->expects($this->once())->method('getLimits')->willReturn([10, 20, 99]); + $gridViewMock->expects($this->once())->method('getDefinition')->willReturn($gridMock); + $gridViewMock->expects($this->once())->method('getData')->willReturn($paginatorMock); + $this->resourcesResolverMock->expects($this->once())->method('getResources')->with($requestConfigurationMock, $repositoryMock)->willReturn($gridViewMock); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->query = $queryParameters; + $this->assertEquals(1000, $requestMock->query->get('limit')); + $this->assertEquals(1, $requestMock->query->get('page')); + $paginatorMock->expects($this->once())->method('setMaxPerPage')->with(99); + $paginatorMock->expects($this->once())->method('setCurrentPage')->with(1); + $paginatorMock->expects($this->once())->method('getCurrentPageResults')->willReturn([]); + $this->assertSame($gridViewMock, $this->resourcesCollectionProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCreatesAPaginatedRepresentationForPagerfantaForNonHtmlRequests(): void + { + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var MetadataInterface|MockObject $metadataMock */ + $metadataMock = $this->createMock(MetadataInterface::class); + if (!class_exists(PagerfantaFactory::class)) { + throw new SkippingException('PagerfantaFactory is not installed.'); + } + $this->resourcesCollectionProvider = new ResourcesCollectionProvider(new ResourcesResolver(), new PagerfantaFactory()); + $paginator = new Pagerfanta(new ArrayAdapter([])); + $repositoryMock->expects($this->once())->method('createPaginator')->with([], [])->willReturn($paginator); + $request = new Request(); + $request->query = new InputBag(['limit' => 8, 'page' => 1]); + $request->attributes = new ParameterBag(['_format' => 'json', '_route' => 'sylius_product_index', '_route_params' => ['slug' => 'foo-bar']]); + $requestConfiguration = new RequestConfiguration($metadataMock, $request, new Parameters(['paginate' => true])); + $this->assertInstanceOf(PaginatedRepresentation::class, $this->resourcesCollectionProvider->get($requestConfiguration, $repositoryMock)); + } + + public function testHandlesResourceGridView(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceGridView|MockObject $resourceGridViewMock */ + $resourceGridViewMock = $this->createMock(ResourceGridView::class); + /** @var Grid|MockObject $gridMock */ + $gridMock = $this->createMock(Grid::class); + /** @var \Pagerfanta\Pagerfanta|MockObject $paginatorMock */ + $paginatorMock = $this->createMock(Pagerfanta::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + $queryParameters = new InputBag(); + $queryParameters->set('limit', 5); + $queryParameters->set('page', 6); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('getPaginationMaxPerPage')->willReturn(5); + $this->resourcesResolverMock->expects($this->once())->method('getResources')->with($requestConfigurationMock, $repositoryMock)->willReturn($resourceGridViewMock); + $resourceGridViewMock->expects($this->once())->method('getData')->willReturn($paginatorMock); + $gridMock->expects($this->once())->method('getLimits')->willReturn([10, 25, 50]); + $resourceGridViewMock->expects($this->once())->method('getDefinition')->willReturn($gridMock); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->query = $queryParameters; + $this->assertEquals(5, $requestMock->query->get('limit')); + $this->assertEquals(6, $requestMock->query->get('page')); + $paginatorMock->expects($this->once())->method('setMaxPerPage')->with(5); + $paginatorMock->expects($this->once())->method('setCurrentPage')->with(6); + $paginatorMock->expects($this->once())->method('getCurrentPageResults')->willReturn([]); + $this->assertSame($resourceGridViewMock, $this->resourcesCollectionProvider->get($requestConfigurationMock, $repositoryMock)); + } +} diff --git a/tests/Bundle/Controller/ResourcesResolverTest.php b/tests/Bundle/Controller/ResourcesResolverTest.php new file mode 100644 index 000000000..a214cd55c --- /dev/null +++ b/tests/Bundle/Controller/ResourcesResolverTest.php @@ -0,0 +1,126 @@ +resourcesResolver = new ResourcesResolver(); + } + + public function testImplementsResourcesResolverInterface(): void + { + $this->assertInstanceOf(ResourcesResolverInterface::class, $this->resourcesResolver); + } + + public function testGetsAllResourcesIfHasNoCriteria(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $secondResourceMock */ + $secondResourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('isPaginated')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('isFilterable')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('isSortable')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('getLimit')->willReturn(null); + $repositoryMock->expects($this->once())->method('findBy')->with([], [], null)->willReturn([$firstResourceMock, $secondResourceMock]); + $this->assertSame([$firstResourceMock, $secondResourceMock], $this->resourcesResolver->getResources($requestConfigurationMock, $repositoryMock)); + } + + public function testFindsResourcesByCriteriaIfNotPaginated(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $secondResourceMock */ + $secondResourceMock = $this->createMock(ResourceInterface::class); + /** @var ResourceInterface|MockObject $thirdResourceMock */ + $thirdResourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('isPaginated')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('isFilterable')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('isSortable')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('getLimit')->willReturn(15); + $requestConfigurationMock->expects($this->once())->method('getCriteria')->willReturn(['custom' => 'criteria']); + $requestConfigurationMock->expects($this->once())->method('getSorting')->willReturn(['name' => 'desc']); + $repositoryMock->expects($this->once())->method('findBy')->with(['custom' => 'criteria'], ['name' => 'desc'], 15)->willReturn([$firstResourceMock, $secondResourceMock, $thirdResourceMock]); + $this->assertSame([$firstResourceMock, $secondResourceMock, $thirdResourceMock], $this->resourcesResolver->getResources($requestConfigurationMock, $repositoryMock)); + } + + public function testUsesCustomMethodAndArgumentsIfSpecified(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn('findAll'); + $requestConfigurationMock->expects($this->once())->method('getRepositoryArguments')->willReturn(['foo']); + $repositoryMock->expects($this->once())->method('findAll')->with('foo')->willReturn([$firstResourceMock]); + $this->assertSame([$firstResourceMock], $this->resourcesResolver->getResources($requestConfigurationMock, $repositoryMock)); + } + + public function testUsesCustomRepositoryIfSpecified(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var RepositoryInterface|MockObject $customRepositoryMock */ + $customRepositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $firstResourceMock */ + $firstResourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn([$customRepositoryMock, 'findBy']); + $requestConfigurationMock->expects($this->once())->method('getRepositoryArguments')->willReturn([['foo' => true]]); + $customRepositoryMock->expects($this->once())->method('findBy')->with(['foo' => true])->willReturn([$firstResourceMock]); + $this->assertSame([$firstResourceMock], $this->resourcesResolver->getResources($requestConfigurationMock, $repositoryMock)); + } + + public function testCreatesPaginatorByDefault(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var \Pagerfanta\Pagerfanta|MockObject $paginatorMock */ + $paginatorMock = $this->createMock(Pagerfanta::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('isPaginated')->willReturn(true); + $requestConfigurationMock->expects($this->once())->method('isFilterable')->willReturn(false); + $requestConfigurationMock->expects($this->once())->method('isSortable')->willReturn(false); + $repositoryMock->expects($this->once())->method('createPaginator')->with([], [])->willReturn($paginatorMock); + $this->assertSame($paginatorMock, $this->resourcesResolver->getResources($requestConfigurationMock, $repositoryMock)); + } +} diff --git a/tests/Bundle/Controller/SingleResourceProviderTest.php b/tests/Bundle/Controller/SingleResourceProviderTest.php new file mode 100644 index 000000000..d9864163f --- /dev/null +++ b/tests/Bundle/Controller/SingleResourceProviderTest.php @@ -0,0 +1,195 @@ +singleResourceProvider = new SingleResourceProvider(); + } + + public function testImplementsSingleResourceProviderInterface(): void + { + $this->assertInstanceOf(SingleResourceProviderInterface::class, $this->singleResourceProvider); + } + + public function testLooksForSpecificResourceWithIdByDefault(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->method('has')->with('id')->willReturn(true); + $requestAttributesMock->expects($this->once())->method('get')->with('id')->willReturn(5); + $repositoryMock->expects($this->once())->method('find')->with(5)->willReturn(null); + $this->assertNull($this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCanFindSpecificResourceWithIdByDefault(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->method('has')->with('id')->willReturn(true); + $requestAttributesMock->expects($this->once())->method('get')->with('id')->willReturn(3); + $repositoryMock->expects($this->once())->method('find')->with(3)->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCanFindSpecificResourceWithSlugByDefault(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getCriteria')->willReturn([]); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->expects($this->exactly(2))->method('has')->willReturnMap([['id', false], ['slug', true]]); + $requestAttributesMock->expects($this->once())->method('get')->with('slug')->willReturn('the-most-awesome-hat'); + $repositoryMock->expects($this->once())->method('findOneBy')->with(['slug' => 'the-most-awesome-hat'])->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCanFindSpecificResourceWithCustomCriteria(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getCriteria')->willReturn(['request-configuration-criteria' => '1']); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->expects($this->exactly(2))->method('has')->willReturnMap([['id', false], ['slug', false]]); + $repositoryMock->expects($this->once())->method('findOneBy')->with(['request-configuration-criteria' => '1'])->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCanFindSpecificResourceWithMergedCustomCriteria(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getCriteria')->willReturn(['request-configuration-criteria' => '1']); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->expects($this->exactly(2))->method('has')->willReturnMap([['id', false], ['slug', true]]); + $requestAttributesMock->expects($this->once())->method('get')->with('slug')->willReturn('banana'); + $repositoryMock->expects($this->once())->method('findOneBy')->with(['slug' => 'banana', 'request-configuration-criteria' => '1'])->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testCanFindSpecificResourceWithMergedCustomCriteriaOverwritingTheAttributes(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Request|MockObject $requestMock */ + $requestMock = $this->createMock(Request::class); + /** @var ParameterBag|MockObject $requestAttributesMock */ + $requestAttributesMock = $this->createMock(ParameterBag::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getCriteria')->willReturn(['id' => 5]); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn(null); + $requestConfigurationMock->expects($this->once())->method('getRequest')->willReturn($requestMock); + $requestMock->attributes = $requestAttributesMock; + $requestAttributesMock->expects($this->exactly(2))->method('has')->willReturnMap([['id', false], ['slug', false]]); + $repositoryMock->expects($this->once())->method('findOneBy')->with(['id' => 5])->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testUsesACustomMethodIfConfigured(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn('findAll'); + $requestConfigurationMock->expects($this->once())->method('getRepositoryArguments')->willReturn(['foo']); + $repositoryMock->expects($this->once())->method('findAll')->with('foo')->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } + + public function testUsesACustomRepositoryIfConfigured(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var RepositoryInterface|MockObject $repositoryMock */ + $repositoryMock = $this->createMock(RepositoryInterface::class); + /** @var RepositoryInterface|MockObject $customRepositoryMock */ + $customRepositoryMock = $this->createMock(RepositoryInterface::class); + /** @var ResourceInterface|MockObject $resourceMock */ + $resourceMock = $this->createMock(ResourceInterface::class); + $requestConfigurationMock->expects($this->once())->method('getRepositoryMethod')->willReturn([$customRepositoryMock, 'findAll']); + $requestConfigurationMock->expects($this->once())->method('getRepositoryArguments')->willReturn(['foo']); + $customRepositoryMock->expects($this->once())->method('findAll')->with('foo')->willReturn($resourceMock); + $this->assertSame($resourceMock, $this->singleResourceProvider->get($requestConfigurationMock, $repositoryMock)); + } +} diff --git a/tests/Bundle/Controller/StateMachineTest.php b/tests/Bundle/Controller/StateMachineTest.php new file mode 100644 index 000000000..a060dcd3a --- /dev/null +++ b/tests/Bundle/Controller/StateMachineTest.php @@ -0,0 +1,161 @@ +stateMachineFactoryMock = $this->createMock(FactoryInterface::class); + $this->stateMachine = new StateMachine($this->stateMachineFactoryMock); + } + + public function testImplementsStateMachineInterface(): void + { + $this->assertInstanceOf(ResourceStateMachineInterface::class, $this->stateMachine); + } + + public function testThrowsAnExceptionIfTransitionIsNotDefinedDuringCan(): void + { + $requestConfiguration = $this->createRequestConfigurationWithoutStateMachine(); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('State machine must be configured to apply transition, check your routing.'); + + $this->stateMachine->can($requestConfiguration, $resource); + } + + public function testThrowsAnExceptionIfTransitionIsNotDefinedDuringApply(): void + { + $requestConfiguration = $this->createRequestConfigurationWithoutStateMachine(); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('State machine must be configured to apply transition, check your routing.'); + + $this->stateMachine->apply($requestConfiguration, $resource); + } + + public function testReturnsIfConfiguredStateMachineCanTransition(): void + { + $requestConfiguration = $this->createRequestConfiguration('sylius_product_review_state', 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $stateMachineMock = $this->createStateMachineMock(); + + $this->stateMachineFactoryMock + ->expects($this->once()) + ->method('get') + ->with($resource, 'sylius_product_review_state') + ->willReturn($stateMachineMock); + + $stateMachineMock + ->expects($this->once()) + ->method('can') + ->with('reject') + ->willReturn(true); + + $this->assertTrue($this->stateMachine->can($requestConfiguration, $resource)); + } + + public function testAppliesConfiguredStateMachineTransitionWithoutGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration(null, 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $stateMachineMock = $this->createStateMachineMock(); + + $this->stateMachineFactoryMock + ->expects($this->once()) + ->method('get') + ->with($resource, 'default') + ->willReturn($stateMachineMock); + + $stateMachineMock + ->expects($this->once()) + ->method('apply') + ->with('reject'); + + $this->stateMachine->apply($requestConfiguration, $resource); + } + + public function testAppliesConfiguredStateMachineTransitionWithGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration('sylius_product_review_state', 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $stateMachineMock = $this->createStateMachineMock(); + + $this->stateMachineFactoryMock + ->expects($this->once()) + ->method('get') + ->with($resource, 'sylius_product_review_state') + ->willReturn($stateMachineMock); + + $stateMachineMock + ->expects($this->once()) + ->method('apply') + ->with('reject'); + + $this->stateMachine->apply($requestConfiguration, $resource); + } + + /** + * @return MockObject&RequestConfiguration + */ + private function createRequestConfigurationWithoutStateMachine(): MockObject + { + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('hasStateMachine')->willReturn(false); + + return $requestConfiguration; + } + + /** + * @return MockObject&RequestConfiguration + */ + private function createRequestConfiguration(?string $graph, string $transition): MockObject + { + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('hasStateMachine')->willReturn(true); + $requestConfiguration->method('getStateMachineGraph')->willReturn($graph); + $requestConfiguration->method('getStateMachineTransition')->willReturn($transition); + + return $requestConfiguration; + } + + /** + * @return MockObject&StateMachineInterface + */ + private function createStateMachineMock(): MockObject + { + /** @var MockObject&StateMachineInterface $stateMachine */ + $stateMachine = $this->createMock(StateMachineInterface::class); + + return $stateMachine; + } +} diff --git a/tests/Bundle/Controller/ViewHandlerTest.php b/tests/Bundle/Controller/ViewHandlerTest.php new file mode 100644 index 000000000..4cb170dc7 --- /dev/null +++ b/tests/Bundle/Controller/ViewHandlerTest.php @@ -0,0 +1,72 @@ +restViewHandlerMock = $this->createMock(ConfigurableViewHandlerInterface::class); + $this->viewHandler = new ViewHandler($this->restViewHandlerMock); + } + + public function testImplementsViewHandlerInterface(): void + { + $this->assertInstanceOf(ViewHandlerInterface::class, $this->viewHandler); + } + + public function testHandlesViewNormallyForHtmlRequests(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(true); + $view = View::create(); + $this->restViewHandlerMock->expects($this->once())->method('handle')->with($view)->willReturn($responseMock); + $this->assertSame($responseMock, $this->viewHandler->handle($requestConfigurationMock, $view)); + } + + public function testSetsProperValuesForNonHtmlRequests(): void + { + /** @var RequestConfiguration|MockObject $requestConfigurationMock */ + $requestConfigurationMock = $this->createMock(RequestConfiguration::class); + /** @var Response|MockObject $responseMock */ + $responseMock = $this->createMock(Response::class); + $requestConfigurationMock->expects($this->once())->method('isHtmlRequest')->willReturn(false); + $view = View::create(); + $view->setContext(new Context()); + $requestConfigurationMock->expects($this->once())->method('getSerializationGroups')->willReturn(['Detailed']); + $requestConfigurationMock->expects($this->once())->method('getSerializationVersion')->willReturn('2.0.0'); + $this->restViewHandlerMock->expects($this->once())->method('setExclusionStrategyGroups')->with(['Detailed']); + $this->restViewHandlerMock->expects($this->once())->method('setExclusionStrategyVersion')->with('2.0.0'); + $this->restViewHandlerMock->expects($this->once())->method('handle')->with($view)->willReturn($responseMock); + $this->assertSame($responseMock, $this->viewHandler->handle($requestConfigurationMock, $view)); + } +} diff --git a/tests/Bundle/Controller/WorkflowTest.php b/tests/Bundle/Controller/WorkflowTest.php new file mode 100644 index 000000000..e35b5ee6c --- /dev/null +++ b/tests/Bundle/Controller/WorkflowTest.php @@ -0,0 +1,187 @@ +registryMock = $this->createMock(Registry::class); + $this->workflow = new Workflow($this->registryMock); + } + + public function testImplementsStateMachineInterface(): void + { + $this->assertInstanceOf(ResourceStateMachineInterface::class, $this->workflow); + } + + public function testThrowsAnExceptionIfTransitionIsNotDefinedDuringCan(): void + { + $requestConfiguration = $this->createRequestConfigurationWithoutStateMachine(); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('State machine must be configured to apply transition, check your routing.'); + + $this->workflow->can($requestConfiguration, $resource); + } + + public function testThrowsAnExceptionIfTransitionIsNotDefinedDuringApply(): void + { + $requestConfiguration = $this->createRequestConfigurationWithoutStateMachine(); + $resource = $this->createMock(ResourceInterface::class); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('State machine must be configured to apply transition, check your routing.'); + + $this->workflow->apply($requestConfiguration, $resource); + } + + public function testReturnsIfConfiguredStateMachineCanTransitionWithoutGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration(null, 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $workflowMock = $this->createWorkflowMock(); + + $this->registryMock + ->expects($this->once()) + ->method('get') + ->with($resource, null) + ->willReturn($workflowMock); + + $workflowMock + ->expects($this->once()) + ->method('can') + ->with($resource, 'reject') + ->willReturn(true); + + $this->assertTrue($this->workflow->can($requestConfiguration, $resource)); + } + + public function testReturnsIfConfiguredStateMachineCanTransitionWithGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration('pull_request', 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $workflowMock = $this->createWorkflowMock(); + + $this->registryMock + ->expects($this->once()) + ->method('get') + ->with($resource, 'pull_request') + ->willReturn($workflowMock); + + $workflowMock + ->expects($this->once()) + ->method('can') + ->with($resource, 'reject') + ->willReturn(true); + + $this->assertTrue($this->workflow->can($requestConfiguration, $resource)); + } + + public function testAppliesConfiguredStateMachineTransitionWithoutGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration(null, 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $workflowMock = $this->createWorkflowMock(); + $marking = $this->createMock(Marking::class); + + $this->registryMock + ->expects($this->once()) + ->method('get') + ->with($resource, null) + ->willReturn($workflowMock); + + $workflowMock + ->expects($this->once()) + ->method('apply') + ->with($resource, 'reject') + ->willReturn($marking); + + $this->workflow->apply($requestConfiguration, $resource); + } + + public function testAppliesConfiguredStateMachineTransitionWithGraphConfiguration(): void + { + $requestConfiguration = $this->createRequestConfiguration('pull_request', 'reject'); + $resource = $this->createMock(ResourceInterface::class); + $workflowMock = $this->createWorkflowMock(); + $marking = $this->createMock(Marking::class); + + $this->registryMock + ->expects($this->once()) + ->method('get') + ->with($resource, 'pull_request') + ->willReturn($workflowMock); + + $workflowMock + ->expects($this->once()) + ->method('apply') + ->with($resource, 'reject') + ->willReturn($marking); + + $this->workflow->apply($requestConfiguration, $resource); + } + + /** + * @return MockObject&RequestConfiguration + */ + private function createRequestConfigurationWithoutStateMachine(): MockObject + { + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('hasStateMachine')->willReturn(false); + + return $requestConfiguration; + } + + /** + * @return MockObject&RequestConfiguration + */ + private function createRequestConfiguration(?string $graph, string $transition): MockObject + { + /** @var MockObject&RequestConfiguration $requestConfiguration */ + $requestConfiguration = $this->createMock(RequestConfiguration::class); + $requestConfiguration->method('hasStateMachine')->willReturn(true); + $requestConfiguration->method('getStateMachineGraph')->willReturn($graph); + $requestConfiguration->method('getStateMachineTransition')->willReturn($transition); + + return $requestConfiguration; + } + + /** + * @return MockObject&SymfonyWorkflow + */ + private function createWorkflowMock(): MockObject + { + /** @var MockObject&SymfonyWorkflow $workflow */ + $workflow = $this->createMock(SymfonyWorkflow::class); + + return $workflow; + } +}