From 8e4847cc6b863b784f30547824bca9847c96794b Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:43:47 +0200 Subject: [PATCH 1/8] Add remove button to the Form --- .../Resources/config/app/twig_hooks/product_option/create.yaml | 2 ++ .../Resources/config/app/twig_hooks/product_option/update.yaml | 2 ++ .../form/sections/values/value/button_delete.html.twig | 3 +++ 3 files changed, 7 insertions(+) create mode 100644 src/Sylius/Bundle/AdminBundle/templates/product_option/form/sections/values/value/button_delete.html.twig diff --git a/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/create.yaml b/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/create.yaml index 17309f9b58..49ad9f88da 100644 --- a/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/create.yaml +++ b/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/create.yaml @@ -40,3 +40,5 @@ twig_hooks: template: '@SyliusAdmin/product_option/form/sections/values/value/code.html.twig' translations: template: '@SyliusAdmin/product_option/form/sections/values/value/translations.html.twig' + button_delete: + template: '@SyliusAdmin/product_option/form/sections/values/value/button_delete.html.twig' diff --git a/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/update.yaml b/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/update.yaml index 1d0e1abac0..2b3cd4274c 100644 --- a/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/update.yaml +++ b/src/Sylius/Bundle/AdminBundle/Resources/config/app/twig_hooks/product_option/update.yaml @@ -42,3 +42,5 @@ twig_hooks: template: '@SyliusAdmin/product_option/form/sections/values/value/code.html.twig' translations: template: '@SyliusAdmin/product_option/form/sections/values/value/translations.html.twig' + button_delete: + template: '@SyliusAdmin/product_option/form/sections/values/value/button_delete.html.twig' diff --git a/src/Sylius/Bundle/AdminBundle/templates/product_option/form/sections/values/value/button_delete.html.twig b/src/Sylius/Bundle/AdminBundle/templates/product_option/form/sections/values/value/button_delete.html.twig new file mode 100644 index 0000000000..136a387f00 --- /dev/null +++ b/src/Sylius/Bundle/AdminBundle/templates/product_option/form/sections/values/value/button_delete.html.twig @@ -0,0 +1,3 @@ +
+ {{ form_row(hookable_metadata.context.form.vars.button_delete, { attr: {class: 'btn btn-outline-danger', 'data-test-delete-option-value': '' }}) }} +
From 3d39f05fdf9dd9e789387b3e96e96e1efd81c16d Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:44:11 +0200 Subject: [PATCH 2/8] cover the tests --- .../managing_values_of_product_option.feature | 23 +++++++++++++++---- .../Admin/ManagingProductOptionsContext.php | 22 +++++++++++++++--- .../Admin/ManagingProductOptionsContext.php | 3 ++- .../Admin/ProductOption/FormElement.php | 12 ++++++++++ .../config/services/contexts/api/admin.xml | 1 + .../api/product/managing_product_options.yml | 4 ++++ .../ui/product/managing_product_options.yml | 4 ++++ 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/features/admin/product/managing_product_options/managing_values_of_product_option.feature b/features/admin/product/managing_product_options/managing_values_of_product_option.feature index 67be1a3766..6762eaf29b 100644 --- a/features/admin/product/managing_product_options/managing_values_of_product_option.feature +++ b/features/admin/product/managing_product_options/managing_values_of_product_option.feature @@ -5,7 +5,7 @@ Feature: Managing option values of a product option I want to be able to edit a product option and its option values Background: - Given the store is available in "English (United States)" + Given the store operates on a single channel in "United States" And the store has a product option "T-Shirt size" with a code "t_shirt_size" And this product option has the "S" option value with code "OV1" And this product option has also the "M" option value with code "OV2" @@ -19,21 +19,34 @@ Feature: Managing option values of a product option Then I should be notified that it has been successfully edited And this product option should have the "L" option value - @api @todo-ui @javascript + @api @ui @mink:chromedriver Scenario: Removing an option value from an existing product option Given this product option has also the "L" option value with code "OV3" When I want to modify the "T-Shirt size" product option - And I delete the "L" option value of this product option + And I delete the "OV3" option value of this product option And I save my changes Then I should be notified that it has been successfully edited And this product option should not have the "L" option value - @api @todo-ui @javascript + @api @ui @mink:chromedriver Scenario: Removing and adding a new option value to an existing product option When I want to modify the "T-Shirt size" product option - And I delete the "M" option value of this product option + And I delete the "OV2" option value of this product option And I add the "L" option value identified by "OV3" And I save my changes Then I should be notified that it has been successfully edited And this product option should not have the "M" option value And this product option should have the "L" option value + + @api @ui @mink:chromedriver + Scenario: Removing product option value that is in use by product variant + Given the store has a "Car" configurable product + And this product has option "Model" with values "Sedan", "Kombi" and "Cabrio" + And this product has "Car-Variant-1" variant priced at "$20.00" configured with "Sedan" option value + And this product has "Car-Variant-2" variant priced at "$25.00" configured with "Kombi" option value + And this product has "Car-Variant-3" variant priced at "$50.00" configured with "Cabrio" option value + When I want to modify the "Model" product option + And I delete the "Sedan" option value of this product option + And I try to save my changes + Then I should be notified that it is in use + And product option "Model" should still have the "Sedan" option value diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingProductOptionsContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingProductOptionsContext.php index bec83b98d7..249c1a90bc 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingProductOptionsContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingProductOptionsContext.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Sylius\Behat\Context\Api\Admin; +use ApiPlatform\Api\IriConverterInterface; use Behat\Behat\Context\Context; use Sylius\Behat\Client\ApiClientInterface; use Sylius\Behat\Client\ResponseCheckerInterface; @@ -20,6 +21,7 @@ use Sylius\Behat\Context\Api\Admin\Helper\ValidationTrait; use Sylius\Behat\Context\Api\Resources; use Sylius\Behat\Service\SharedStorageInterface; use Sylius\Component\Product\Model\ProductOptionInterface; +use Sylius\Component\Product\Model\ProductOptionValueInterface; use Webmozart\Assert\Assert; final class ManagingProductOptionsContext implements Context @@ -30,6 +32,7 @@ final class ManagingProductOptionsContext implements Context private ApiClientInterface $client, private ResponseCheckerInterface $responseChecker, private SharedStorageInterface $sharedStorage, + private IriConverterInterface $iriConverter, ) { } @@ -113,11 +116,12 @@ final class ManagingProductOptionsContext implements Context } /** - * @When I delete the :value option value of this product option + * @When I delete the :optionValue option value of this product option */ - public function iDeleteTheOptionValueOfThisProductOption(string $value): void + public function iDeleteTheOptionValueOfThisProductOption(ProductOptionValueInterface $optionValue): void { - $this->client->removeSubResourceObject('values', $value, 'value'); + $optionValueIri = $this->iriConverter->getIriFromResource($optionValue); + $this->client->removeSubResourceObject('values', $optionValueIri, 'value'); } /** @@ -228,6 +232,7 @@ final class ManagingProductOptionsContext implements Context /** * @Then /^(product option "[^"]+") should have the "([^"]+)" option value$/ + * @Then /^(product option "[^"]+") should still have the "([^"]+)" option value$/ * @Then /^(this product option) should have the "([^"]*)" option value$/ */ public function productOptionShouldHaveTheOptionValue( @@ -296,6 +301,17 @@ final class ManagingProductOptionsContext implements Context ); } + /** + * @Then I should be notified that it is in use + */ + public function iShouldBeNotifiedThatItIsInUse(): void + { + Assert::contains( + $this->responseChecker->getError($this->client->getLastResponse()), + 'Cannot delete, the product option value is in use.', + ); + } + /** * @Then I should be notified that it has been successfully created */ diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingProductOptionsContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingProductOptionsContext.php index 3685a1bd03..3c172e8a7d 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingProductOptionsContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingProductOptionsContext.php @@ -143,7 +143,7 @@ final readonly class ManagingProductOptionsContext implements Context */ public function iDeleteTheOptionValueWithCodeAndValue(string $value): void { - // TODO: Implement deleting option value + $this->formElement->removeOptionValue($value); } /** @@ -253,6 +253,7 @@ final readonly class ManagingProductOptionsContext implements Context /** * @Then /^(this product option) should have the "([^"]*)" option value$/ * @Then /^(product option "[^"]+") should have the "([^"]*)" option value$/ + * @Then /^(product option "[^"]+") should still have the "([^"]*)" option value$/ * @Then /^(this product option) should have the "([^"]*)" option value in ("([^"]+)" locale)$/ */ public function thisProductOptionShouldHaveTheOptionValue( diff --git a/src/Sylius/Behat/Element/Admin/ProductOption/FormElement.php b/src/Sylius/Behat/Element/Admin/ProductOption/FormElement.php index d45d615c3a..474c723778 100644 --- a/src/Sylius/Behat/Element/Admin/ProductOption/FormElement.php +++ b/src/Sylius/Behat/Element/Admin/ProductOption/FormElement.php @@ -28,6 +28,17 @@ class FormElement extends BaseFormElement implements FormElementInterface $this->getElement('name', ['%locale_code%' => $localeCode])->setValue($name); } + public function removeOptionValue(string $optionValue): void + { + $optionValues = $this->getDocument()->findAll('css', '[data-test-option-value]'); + foreach ($optionValues as $optionValueElement) { + if ($optionValueElement->has('css', sprintf('input[value="%s"]', $optionValue))) { + $optionValueElement->find('css', '[data-test-delete-option-value]')->click(); + $this->waitForFormUpdate(); + } + } + } + public function addOptionValue(string $code, string $localeCode, string $value): void { $this->getElement('add_option_value')->press(); @@ -56,6 +67,7 @@ class FormElement extends BaseFormElement implements FormElementInterface 'add_option_value' => '[data-test-add-option-value]', 'apply_to_all' => '[data-test-option-value="%value_code%"] [data-test-option-value-locale="%locale_code%"] [data-test-apply-to-all]', 'code' => '[data-test-code]', + 'delete_option_value' => '[data-test-delete-option-value]', 'form' => '[data-live-name-value="sylius_admin:product_option:form"]', 'last_option_value' => '[data-test-option-values] [data-test-option-value]:last-child', 'name' => '#sylius_admin_product_option_translations_%locale_code%_name', diff --git a/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml b/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml index 1b4faf97b6..f90d6b73f4 100644 --- a/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml +++ b/src/Sylius/Behat/Resources/config/services/contexts/api/admin.xml @@ -126,6 +126,7 @@ + diff --git a/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_options.yml b/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_options.yml index a6c710c133..104f9e6221 100644 --- a/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_options.yml +++ b/src/Sylius/Behat/Resources/config/suites/api/product/managing_product_options.yml @@ -9,12 +9,16 @@ default: - sylius.behat.context.transform.lexical - sylius.behat.context.transform.locale + - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option + - sylius.behat.context.transform.product_option_value - sylius.behat.context.transform.shared_storage + - sylius.behat.context.setup.channel - sylius.behat.context.setup.locale - sylius.behat.context.setup.product_option - sylius.behat.context.setup.admin_api_security + - sylius.behat.context.setup.product - sylius.behat.context.api.admin.managing_product_options - sylius.behat.context.api.admin.response diff --git a/src/Sylius/Behat/Resources/config/suites/ui/product/managing_product_options.yml b/src/Sylius/Behat/Resources/config/suites/ui/product/managing_product_options.yml index 1ca606a9ff..7ac01ef859 100644 --- a/src/Sylius/Behat/Resources/config/suites/ui/product/managing_product_options.yml +++ b/src/Sylius/Behat/Resources/config/suites/ui/product/managing_product_options.yml @@ -10,12 +10,16 @@ default: - sylius.behat.context.transform.lexical - sylius.behat.context.transform.locale + - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option + - sylius.behat.context.transform.product_option_value - sylius.behat.context.transform.shared_storage + - sylius.behat.context.setup.channel - sylius.behat.context.setup.locale - sylius.behat.context.setup.product_option - sylius.behat.context.setup.admin_security + - sylius.behat.context.setup.product - sylius.behat.context.ui.admin.managing_product_options - sylius.behat.context.ui.admin.notification From 5691cea019b512ac334cb0f8a7e1ffdf08cb0e25 Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:45:54 +0200 Subject: [PATCH 3/8] Refactor ResourceDeleteSubscriber --- .../ResourceDeleteExceptionListener.php | 65 ++++++++++++++ ...scriber.php => ResourceDeleteListener.php} | 45 +--------- .../Resources/config/services/listener.xml | 8 +- .../ResourceDeleteExceptionListenerSpec.php | 90 +++++++++++++++++++ .../ResourceDeleteListenerSpec.php | 72 +++++++++++++++ .../Resources/config/services/listeners.xml | 5 ++ .../Exception/ResourceDeleteException.php | 35 ++++++++ 7 files changed, 277 insertions(+), 43 deletions(-) create mode 100644 src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteExceptionListener.php rename src/Sylius/Bundle/AdminBundle/EventListener/{ResourceDeleteSubscriber.php => ResourceDeleteListener.php} (59%) create mode 100644 src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteExceptionListenerSpec.php create mode 100644 src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteListenerSpec.php create mode 100644 src/Sylius/Component/Core/Exception/ResourceDeleteException.php diff --git a/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteExceptionListener.php b/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteExceptionListener.php new file mode 100644 index 0000000000..4e2193a7c4 --- /dev/null +++ b/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteExceptionListener.php @@ -0,0 +1,65 @@ +getThrowable(); + + if (!$exception instanceof ResourceDeleteException) { + return; + } + + FlashBagProvider::getFlashBag($this->requestStack)->add('error', [ + 'message' => 'sylius.resource.delete_error', + 'parameters' => ['%resource%' => $exception->getResourceName()], + ]); + + $eventRequest = $event->getRequest(); + $requestAttributes = $eventRequest->attributes; + $originalRoute = $requestAttributes->get('_route', ''); + + $referrer = $eventRequest->headers->get('referer'); + if (null !== $referrer) { + $event->setResponse(new RedirectResponse($referrer)); + + return; + } + + $event->setResponse($this->createRedirectResponse($originalRoute, ResourceActions::INDEX)); + } + + private function createRedirectResponse(string $originalRoute, string $targetAction): RedirectResponse + { + $redirectRoute = str_replace(ResourceActions::DELETE, $targetAction, $originalRoute); + + return new RedirectResponse($this->router->generate($redirectRoute)); + } +} diff --git a/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteSubscriber.php b/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteListener.php similarity index 59% rename from src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteSubscriber.php rename to src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteListener.php index f175fe3bc0..a19f284d22 100644 --- a/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteSubscriber.php +++ b/src/Sylius/Bundle/AdminBundle/EventListener/ResourceDeleteListener.php @@ -14,31 +14,12 @@ declare(strict_types=1); namespace Sylius\Bundle\AdminBundle\EventListener; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; -use Sylius\Bundle\CoreBundle\Provider\FlashBagProvider; -use Sylius\Resource\ResourceActions; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\ExceptionEvent; -use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -final readonly class ResourceDeleteSubscriber implements EventSubscriberInterface +final readonly class ResourceDeleteListener { - public function __construct( - private UrlGeneratorInterface $router, - private RequestStack $requestStack, - ) { - } - - public static function getSubscribedEvents(): array - { - return [ - KernelEvents::EXCEPTION => 'onResourceDelete', - ]; - } - public function onResourceDelete(ExceptionEvent $event): void { $exception = $event->getThrowable(); @@ -67,19 +48,7 @@ final readonly class ResourceDeleteSubscriber implements EventSubscriberInterfac return; } - FlashBagProvider::getFlashBag($this->requestStack)->add('error', [ - 'message' => 'sylius.resource.delete_error', - 'parameters' => ['%resource%' => $resourceName], - ]); - - $referrer = $eventRequest->headers->get('referer'); - if (null !== $referrer) { - $event->setResponse(new RedirectResponse($referrer)); - - return; - } - - $event->setResponse($this->createRedirectResponse($originalRoute, ResourceActions::INDEX)); + throw new ResourceDeleteException($resourceName); } private function getResourceNameFromRoute(string $route): string @@ -92,13 +61,6 @@ final readonly class ResourceDeleteSubscriber implements EventSubscriberInterfac return trim(implode(' ', $routeArrayWithoutPrefixes)); } - private function createRedirectResponse(string $originalRoute, string $targetAction): RedirectResponse - { - $redirectRoute = str_replace(ResourceActions::DELETE, $targetAction, $originalRoute); - - return new RedirectResponse($this->router->generate($redirectRoute)); - } - private function isMethodDelete(Request $request): bool { return Request::METHOD_DELETE === $request->getMethod(); @@ -109,6 +71,7 @@ final readonly class ResourceDeleteSubscriber implements EventSubscriberInterfac return str_starts_with($route, 'sylius'); } + /** @param array $syliusParameters */ private function isAdminSection(array $syliusParameters): bool { return array_key_exists('section', $syliusParameters) && 'admin' === $syliusParameters['section']; diff --git a/src/Sylius/Bundle/AdminBundle/Resources/config/services/listener.xml b/src/Sylius/Bundle/AdminBundle/Resources/config/services/listener.xml index 52561395e5..aabfa0e563 100644 --- a/src/Sylius/Bundle/AdminBundle/Resources/config/services/listener.xml +++ b/src/Sylius/Bundle/AdminBundle/Resources/config/services/listener.xml @@ -26,10 +26,14 @@ - + - + + + + + diff --git a/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteExceptionListenerSpec.php b/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteExceptionListenerSpec.php new file mode 100644 index 0000000000..29a4893f76 --- /dev/null +++ b/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteExceptionListenerSpec.php @@ -0,0 +1,90 @@ +beConstructedWith($router, $requestStack); + } + + function it_does_nothing_if_exception_is_not_resource_delete_exception( + KernelInterface $kernel, + ForeignKeyConstraintViolationException $exception, + ): void { + $event = new ExceptionEvent($kernel->getWrappedObject(), new Request(), HttpKernelInterface::MAIN_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDeleteException($event)->shouldReturn(null); + } + + function it_redirects_to_referer_if_present_and_adds_flash_message( + KernelInterface $kernel, + Request $request, + RequestStack $requestStack, + FlashBagInterface $flashBag, + UrlGeneratorInterface $router, + SessionInterface $session, + ): void { + $request->attributes = new ParameterBag(['_route' => 'sylius_admin_product_delete']); + $request->headers = new HeaderBag(['referer' => '/admin/product/index']); + $exception = new ResourceDeleteException('Product'); + $event = new ExceptionEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, $exception); + + $requestStack->getSession()->willReturn($session); + $session->getBag('flashes')->willReturn($flashBag); + $flashBag->add('error', ['message' => 'sylius.resource.delete_error', 'parameters' => ['%resource%' => 'Product']])->shouldBeCalled(); + + $router->generate(Argument::cetera())->shouldNotBeCalled(); + + $this->onResourceDeleteException($event); + } + + function it_redirects_to_index_when_no_referer_present_and_adds_flash_message( + KernelInterface $kernel, + Request $request, + RequestStack $requestStack, + FlashBagInterface $flashBag, + UrlGeneratorInterface $router, + SessionInterface $session, + ): void { + $request->attributes = new ParameterBag(['_route' => 'sylius_admin_product_delete']); + $request->headers = new HeaderBag(); + $exception = new ResourceDeleteException('Product'); + $event = new ExceptionEvent($kernel->getWrappedObject(), $request->getWrappedObject(), HttpKernelInterface::MAIN_REQUEST, $exception); + + $requestStack->getSession()->willReturn($session); + $session->getBag('flashes')->willReturn($flashBag); + $flashBag->add('error', ['message' => 'sylius.resource.delete_error', 'parameters' => ['%resource%' => 'Product']])->shouldBeCalled(); + + $router->generate('sylius_admin_product_index')->willReturn('/admin/product/index'); + + $this->onResourceDeleteException($event); + } +} diff --git a/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteListenerSpec.php b/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteListenerSpec.php new file mode 100644 index 0000000000..49e8689fe6 --- /dev/null +++ b/src/Sylius/Bundle/AdminBundle/spec/EventListener/ResourceDeleteListenerSpec.php @@ -0,0 +1,72 @@ +onResourceDelete(new ExceptionEvent($kernel->getWrappedObject(), new Request(), HttpKernelInterface::MAIN_REQUEST, new \Exception()))->shouldReturn(null); + } + + function it_does_nothing_if_request_is_not_main(KernelInterface $kernel, ForeignKeyConstraintViolationException $exception): void + { + $event = new ExceptionEvent($kernel->getWrappedObject(), new Request(), HttpKernelInterface::SUB_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDelete($event)->shouldReturn(null); + } + + function it_should_throw_resource_delete_exception_if_all_conditions_are_met(KernelInterface $kernel, ForeignKeyConstraintViolationException $exception): void + { + $event = new ExceptionEvent($kernel->getWrappedObject(), new Request(), HttpKernelInterface::MAIN_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDelete($event)->shouldThrow(ResourceDeleteException::class); + } + + function it_should_do_nothing_if_method_is_not_delete(KernelInterface $kernel, ForeignKeyConstraintViolationException $exception): void + { + $request = new Request([], [], ['_route' => 'sylius_admin_product_delete', '_sylius' => ['section' => 'admin']]); + $request->setMethod('GET'); + + $event = new ExceptionEvent($kernel->getWrappedObject(), $request, HttpKernelInterface::MAIN_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDelete($event)->shouldReturn(null); + } + + function it_should_do_nothing_if_route_is_not_sylius(KernelInterface $kernel, ForeignKeyConstraintViolationException $exception): void + { + $request = new Request([], [], ['_route' => 'non_sylius_route', '_sylius' => ['section' => 'admin']]); + + $event = new ExceptionEvent($kernel->getWrappedObject(), $request, HttpKernelInterface::MAIN_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDelete($event)->shouldReturn(null); + } + + function it_should_do_nothing_if_section_is_not_admin(KernelInterface $kernel, ForeignKeyConstraintViolationException $exception): void + { + $request = new Request([], [], ['_route' => 'sylius_admin_product_delete', '_sylius' => ['section' => 'shop']]); + + $event = new ExceptionEvent($kernel->getWrappedObject(), $request, HttpKernelInterface::MAIN_REQUEST, $exception->getWrappedObject()); + + $this->onResourceDelete($event)->shouldReturn(null); + } +} diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml index 4faab97057..afb90c5a8e 100644 --- a/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml +++ b/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml @@ -119,6 +119,11 @@ + + + + + diff --git a/src/Sylius/Component/Core/Exception/ResourceDeleteException.php b/src/Sylius/Component/Core/Exception/ResourceDeleteException.php new file mode 100644 index 0000000000..66aee8da65 --- /dev/null +++ b/src/Sylius/Component/Core/Exception/ResourceDeleteException.php @@ -0,0 +1,35 @@ +resourceName; + } +} From f66858c77a379e88f9763d6764164e50967b8ef7 Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:49:00 +0200 Subject: [PATCH 4/8] Add persist processor for ProductOption --- .../ProductOptionValueCannotBeRemoved.php | 25 +++++++ .../resources/admin/ProductOption.xml | 1 + .../Resources/config/app/config.yaml | 1 + .../config/services/state_processors.xml | 5 ++ .../Admin/PaymentMethod/RemoveProcessor.php | 1 + .../ProductAttribute/RemoveProcessor.php | 1 + .../Admin/ProductOption/PersistProcessor.php | 43 ++++++++++++ .../Admin/ShippingMethod/RemoveProcessor.php | 1 + .../Admin/Zone/RemoveProcessor.php | 1 + .../PaymentMethod/RemoveProcessorSpec.php | 1 + .../ProductAttribute/RemoveProcessorSpec.php | 1 + .../ProductOption/PersistProcessorSpec.php | 67 +++++++++++++++++++ .../ShippingMethod/RemoveProcessorSpec.php | 1 + .../Admin/Zone/RemoveProcessorSpec.php | 1 + 14 files changed, 150 insertions(+) create mode 100644 src/Sylius/Bundle/ApiBundle/Exception/ProductOptionValueCannotBeRemoved.php create mode 100644 src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php create mode 100644 src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductOption/PersistProcessorSpec.php diff --git a/src/Sylius/Bundle/ApiBundle/Exception/ProductOptionValueCannotBeRemoved.php b/src/Sylius/Bundle/ApiBundle/Exception/ProductOptionValueCannotBeRemoved.php new file mode 100644 index 0000000000..66aee044ec --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Exception/ProductOptionValueCannotBeRemoved.php @@ -0,0 +1,25 @@ + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml b/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml index 40bd49fae5..28df3afa27 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/app/config.yaml @@ -59,6 +59,7 @@ api_platform: Sylius\Bundle\ApiBundle\Exception\PaymentMethodCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProductAttributeCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProductCannotBeRemoved: 422 + Sylius\Bundle\ApiBundle\Exception\ProductOptionValueCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProductVariantCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\PromotionCouponCannotBeRemoved: 422 Sylius\Bundle\ApiBundle\Exception\ProvinceCannotBeRemoved: 422 diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml index 1e883cc97f..90bec365b8 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml @@ -68,6 +68,11 @@ + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/PaymentMethod/RemoveProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/PaymentMethod/RemoveProcessor.php index d496688a9f..e2321d0c02 100644 --- a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/PaymentMethod/RemoveProcessor.php +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/PaymentMethod/RemoveProcessor.php @@ -18,6 +18,7 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Sylius\Bundle\ApiBundle\Exception\PaymentMethodCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Core\Model\PaymentMethodInterface; use Webmozart\Assert\Assert; diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductAttribute/RemoveProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductAttribute/RemoveProcessor.php index 6591faeaf7..a0a4845212 100644 --- a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductAttribute/RemoveProcessor.php +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductAttribute/RemoveProcessor.php @@ -18,6 +18,7 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Sylius\Bundle\ApiBundle\Exception\ProductAttributeCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Product\Model\ProductAttributeInterface; use Webmozart\Assert\Assert; diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php new file mode 100644 index 0000000000..6edf638a8c --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php @@ -0,0 +1,43 @@ + */ +final readonly class PersistProcessor implements ProcessorInterface +{ + public function __construct( + private ProcessorInterface $processor, + ) { + } + + public function process($data, Operation $operation, array $uriVariables = [], array $context = []): void + { + Assert::isInstanceOf($data, ProductOptionInterface::class); + Assert::isInstanceOf($operation, Put::class); + + try { + $this->processor->process($data, $operation, $uriVariables, $context); + } catch (ResourceDeleteException) { + throw new ProductOptionValueCannotBeRemoved(); + } + } +} diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ShippingMethod/RemoveProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ShippingMethod/RemoveProcessor.php index 1b2e8b8b4e..48ff7dd3d3 100644 --- a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ShippingMethod/RemoveProcessor.php +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ShippingMethod/RemoveProcessor.php @@ -18,6 +18,7 @@ use ApiPlatform\Metadata\Operation; use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Sylius\Bundle\ApiBundle\Exception\ShippingMethodCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Core\Model\ShippingMethodInterface; use Webmozart\Assert\Assert; diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/Zone/RemoveProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/Zone/RemoveProcessor.php index 0a6a646176..99cc2fe3dd 100644 --- a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/Zone/RemoveProcessor.php +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/Zone/RemoveProcessor.php @@ -20,6 +20,7 @@ use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Sylius\Bundle\ApiBundle\Exception\ZoneCannotBeRemoved; use Sylius\Component\Addressing\Checker\ZoneDeletionCheckerInterface; use Sylius\Component\Addressing\Model\ZoneInterface; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Webmozart\Assert\Assert; /** @implements ProcessorInterface */ diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/PaymentMethod/RemoveProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/PaymentMethod/RemoveProcessorSpec.php index 8322ed2fd4..8953d33df8 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/PaymentMethod/RemoveProcessorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/PaymentMethod/RemoveProcessorSpec.php @@ -21,6 +21,7 @@ use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use PhpSpec\ObjectBehavior; use Sylius\Bundle\ApiBundle\Exception\PaymentMethodCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Core\Model\ShippingMethodInterface; diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductAttribute/RemoveProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductAttribute/RemoveProcessorSpec.php index 180120d246..8a8e91b833 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductAttribute/RemoveProcessorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductAttribute/RemoveProcessorSpec.php @@ -19,6 +19,7 @@ use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use PhpSpec\ObjectBehavior; use Sylius\Bundle\ApiBundle\Exception\ProductAttributeCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Product\Model\ProductAttributeInterface; final class RemoveProcessorSpec extends ObjectBehavior diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductOption/PersistProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductOption/PersistProcessorSpec.php new file mode 100644 index 0000000000..a5594bcf6e --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ProductOption/PersistProcessorSpec.php @@ -0,0 +1,67 @@ +beConstructedWith($processor); + } + + function it_is_a_processor_interface(): void + { + $this->shouldImplement(ProcessorInterface::class); + } + + public function it_processes_remove_operation( + ProcessorInterface $processor, + ProductOptionInterface $productOption, + ): void { + $operation = new Put(); + $processor->process($productOption, $operation, [], [])->shouldBeCalled(); + + $this->process($productOption, $operation); + } + + public function it_throws_an_exception_when_resource_delete_exception_occurs( + ProcessorInterface $processor, + ProductOptionInterface $productOption, + ): void { + $operation = new Put(); + $processor->process($productOption, $operation, [], [])->willThrow(ResourceDeleteException::class); + + $this->shouldThrow(ProductOptionValueCannotBeRemoved::class)->during('process', [$productOption, $operation]); + } + + public function it_throws_an_exception_if_operation_is_not_put( + ShippingMethodInterface $shippingMethod, + ): void { + $this->shouldThrow(\InvalidArgumentException::class)->during('process', [$shippingMethod, new Delete()]); + } + + public function it_throws_exception_if_data_is_not_product_option_interface(): void + { + $this->shouldThrow(\InvalidArgumentException::class)->during('process', [new \stdClass(), new Put()]); + } +} diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ShippingMethod/RemoveProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ShippingMethod/RemoveProcessorSpec.php index 3f85566609..5e3b275db9 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ShippingMethod/RemoveProcessorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/ShippingMethod/RemoveProcessorSpec.php @@ -21,6 +21,7 @@ use ApiPlatform\State\ProcessorInterface; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use PhpSpec\ObjectBehavior; use Sylius\Bundle\ApiBundle\Exception\ShippingMethodCannotBeRemoved; +use Sylius\Component\Core\Exception\ResourceDeleteException; use Sylius\Component\Core\Model\ShippingMethodInterface; final class RemoveProcessorSpec extends ObjectBehavior diff --git a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/Zone/RemoveProcessorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/Zone/RemoveProcessorSpec.php index 4a73cda51a..4b0b7a1807 100644 --- a/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/Zone/RemoveProcessorSpec.php +++ b/src/Sylius/Bundle/ApiBundle/spec/StateProcessor/Admin/Zone/RemoveProcessorSpec.php @@ -22,6 +22,7 @@ use Prophecy\Argument; use Sylius\Bundle\ApiBundle\Exception\ZoneCannotBeRemoved; use Sylius\Component\Addressing\Checker\ZoneDeletionCheckerInterface; use Sylius\Component\Addressing\Model\ZoneInterface; +use Sylius\Component\Core\Exception\ResourceDeleteException; final class RemoveProcessorSpec extends ObjectBehavior { From 82de1b5906a96e675ba29e5aa6959c4bdd90d3d6 Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:50:19 +0200 Subject: [PATCH 5/8] Prevent removal of Option values in use --- .../config/services/state_processors.xml | 2 +- .../Admin/ProductOption/PersistProcessor.php | 4 +- .../Doctrine/ORM/ProductVariantRepository.php | 11 +++++ .../ProductOptionValueDeletionListener.php | 37 +++++++++++++++ ...ProductOptionValueDeletionListenerSpec.php | 47 +++++++++++++++++++ .../ProductVariantRepositoryInterface.php | 2 + 6 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/Sylius/Bundle/CoreBundle/EventListener/ProductOptionValueDeletionListener.php create mode 100644 src/Sylius/Bundle/CoreBundle/spec/EventListener/ProductOptionValueDeletionListenerSpec.php diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml index 90bec365b8..c120e6cc7a 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/state_processors.xml @@ -69,7 +69,7 @@ - + diff --git a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php index 6edf638a8c..322c78b8ca 100644 --- a/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php +++ b/src/Sylius/Bundle/ApiBundle/StateProcessor/Admin/ProductOption/PersistProcessor.php @@ -29,7 +29,7 @@ final readonly class PersistProcessor implements ProcessorInterface ) { } - public function process($data, Operation $operation, array $uriVariables = [], array $context = []): void + public function process($data, Operation $operation, array $uriVariables = [], array $context = []) { Assert::isInstanceOf($data, ProductOptionInterface::class); Assert::isInstanceOf($operation, Put::class); @@ -39,5 +39,7 @@ final readonly class PersistProcessor implements ProcessorInterface } catch (ResourceDeleteException) { throw new ProductOptionValueCannotBeRemoved(); } + + return $this->processor->process($data, $operation, $uriVariables, $context); } } diff --git a/src/Sylius/Bundle/CoreBundle/Doctrine/ORM/ProductVariantRepository.php b/src/Sylius/Bundle/CoreBundle/Doctrine/ORM/ProductVariantRepository.php index cc991a0e80..f4d055daa0 100644 --- a/src/Sylius/Bundle/CoreBundle/Doctrine/ORM/ProductVariantRepository.php +++ b/src/Sylius/Bundle/CoreBundle/Doctrine/ORM/ProductVariantRepository.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\CoreBundle\Doctrine\ORM; +use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Sylius\Bundle\ProductBundle\Doctrine\ORM\ProductVariantRepository as BaseProductVariantRepository; use Sylius\Component\Core\Model\CatalogPromotionInterface; @@ -64,4 +65,14 @@ class ProductVariantRepository extends BaseProductVariantRepository implements P ->setParameter('locale', $locale) ; } + + public function countByProductOptionValueId(mixed $id): int + { + return (int) $this->createQueryBuilder('o') + ->select('COUNT(o.id)') + ->innerJoin('o.optionValues', 'optionValue', Join::WITH, 'optionValue.id = :id') + ->setParameter('id', $id) + ->getQuery() + ->getSingleScalarResult(); + } } diff --git a/src/Sylius/Bundle/CoreBundle/EventListener/ProductOptionValueDeletionListener.php b/src/Sylius/Bundle/CoreBundle/EventListener/ProductOptionValueDeletionListener.php new file mode 100644 index 0000000000..e1e0c28f93 --- /dev/null +++ b/src/Sylius/Bundle/CoreBundle/EventListener/ProductOptionValueDeletionListener.php @@ -0,0 +1,37 @@ + $productVariantRepository + */ + public function __construct( + private ProductVariantRepositoryInterface $productVariantRepository, + ) { + } + + public function preRemove(ProductOptionValueInterface $optionValue): void + { + if ($this->productVariantRepository->countByProductOptionValueId($optionValue->getId()) > 0) { + throw new ResourceDeleteException('product option value'); + } + } +} diff --git a/src/Sylius/Bundle/CoreBundle/spec/EventListener/ProductOptionValueDeletionListenerSpec.php b/src/Sylius/Bundle/CoreBundle/spec/EventListener/ProductOptionValueDeletionListenerSpec.php new file mode 100644 index 0000000000..0f899d6413 --- /dev/null +++ b/src/Sylius/Bundle/CoreBundle/spec/EventListener/ProductOptionValueDeletionListenerSpec.php @@ -0,0 +1,47 @@ +beConstructedWith($productVariantRepository); + } + + function it_throws_resource_delete_exception_if_product_variants_exist_for_option_value( + ProductVariantRepositoryInterface $productVariantRepository, + ProductOptionValueInterface $optionValue, + ): void { + $optionValue->getId()->willReturn(1); + $productVariantRepository->countByProductOptionValueId(1)->willReturn(1); + + $this->shouldThrow(ResourceDeleteException::class)->during('preRemove', [$optionValue]); + } + + function it_does_nothing_if_no_product_variants_exist_for_option_value( + ProductVariantRepositoryInterface $productVariantRepository, + ProductOptionValueInterface $optionValue, + ): void { + $optionValue->getId()->willReturn(1); + $productVariantRepository->countByProductOptionValueId(1)->willReturn(0); + + $this->preRemove($optionValue)->shouldReturn(null); + } +} diff --git a/src/Sylius/Component/Core/Repository/ProductVariantRepositoryInterface.php b/src/Sylius/Component/Core/Repository/ProductVariantRepositoryInterface.php index 3e6be90656..d043604e19 100644 --- a/src/Sylius/Component/Core/Repository/ProductVariantRepositoryInterface.php +++ b/src/Sylius/Component/Core/Repository/ProductVariantRepositoryInterface.php @@ -34,4 +34,6 @@ interface ProductVariantRepositoryInterface extends BaseProductVariantRepository string $locale, CatalogPromotionInterface $catalogPromotion, ): QueryBuilder; + + public function countByProductOptionValueId(mixed $id): int; } From b381697cea1020c2bb9713098eb33da1db41c351 Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:53:27 +0200 Subject: [PATCH 6/8] Remove cascade onDelete from Product option value in ProductVariant --- .../Resources/config/doctrine/model/ProductVariant.orm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sylius/Bundle/ProductBundle/Resources/config/doctrine/model/ProductVariant.orm.xml b/src/Sylius/Bundle/ProductBundle/Resources/config/doctrine/model/ProductVariant.orm.xml index 86fb529d1b..4f844eb7f1 100644 --- a/src/Sylius/Bundle/ProductBundle/Resources/config/doctrine/model/ProductVariant.orm.xml +++ b/src/Sylius/Bundle/ProductBundle/Resources/config/doctrine/model/ProductVariant.orm.xml @@ -44,10 +44,10 @@ - + - + From 1d21e4a29a039ac6763c24ae67256ce9dd7ee920 Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:54:40 +0200 Subject: [PATCH 7/8] add migration for postgress --- .../Migrations/Version20240926122944.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Sylius/Bundle/CoreBundle/Migrations/Version20240926122944.php diff --git a/src/Sylius/Bundle/CoreBundle/Migrations/Version20240926122944.php b/src/Sylius/Bundle/CoreBundle/Migrations/Version20240926122944.php new file mode 100644 index 0000000000..1f22ad8d20 --- /dev/null +++ b/src/Sylius/Bundle/CoreBundle/Migrations/Version20240926122944.php @@ -0,0 +1,41 @@ +addSql('ALTER TABLE sylius_product_variant_option_value DROP CONSTRAINT FK_76CDAFA13B69A9AF'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP CONSTRAINT FK_76CDAFA1D957CA06'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA13B69A9AF FOREIGN KEY (variant_id) REFERENCES sylius_product_variant (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA1D957CA06 FOREIGN KEY (option_value_id) REFERENCES sylius_product_option_value (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP CONSTRAINT fk_76cdafa13b69a9af'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP CONSTRAINT fk_76cdafa1d957ca06'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT fk_76cdafa13b69a9af FOREIGN KEY (variant_id) REFERENCES sylius_product_variant (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT fk_76cdafa1d957ca06 FOREIGN KEY (option_value_id) REFERENCES sylius_product_option_value (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + } +} From f291a1e91e69c59b658807d9c577e37ece7d861f Mon Sep 17 00:00:00 2001 From: Kamil Grygierzec Date: Fri, 27 Sep 2024 17:57:11 +0200 Subject: [PATCH 8/8] Add migration for MySQL --- .../Migrations/Version20240927155535.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Sylius/Bundle/CoreBundle/Migrations/Version20240927155535.php diff --git a/src/Sylius/Bundle/CoreBundle/Migrations/Version20240927155535.php b/src/Sylius/Bundle/CoreBundle/Migrations/Version20240927155535.php new file mode 100644 index 0000000000..1843feff46 --- /dev/null +++ b/src/Sylius/Bundle/CoreBundle/Migrations/Version20240927155535.php @@ -0,0 +1,41 @@ +addSql('ALTER TABLE sylius_product_variant_option_value DROP FOREIGN KEY FK_76CDAFA13B69A9AF'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP FOREIGN KEY FK_76CDAFA1D957CA06'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA13B69A9AF FOREIGN KEY (variant_id) REFERENCES sylius_product_variant (id)'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA1D957CA06 FOREIGN KEY (option_value_id) REFERENCES sylius_product_option_value (id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP FOREIGN KEY FK_76CDAFA13B69A9AF'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value DROP FOREIGN KEY FK_76CDAFA1D957CA06'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA13B69A9AF FOREIGN KEY (variant_id) REFERENCES sylius_product_variant (id) ON UPDATE NO ACTION ON DELETE CASCADE'); + $this->addSql('ALTER TABLE sylius_product_variant_option_value ADD CONSTRAINT FK_76CDAFA1D957CA06 FOREIGN KEY (option_value_id) REFERENCES sylius_product_option_value (id) ON UPDATE NO ACTION ON DELETE CASCADE'); + } +}