From afcb228a8c8d680a3776dbe201b0d74c2253206b Mon Sep 17 00:00:00 2001 From: Mateusz Zalewski Date: Fri, 10 Jan 2020 15:11:54 +0100 Subject: [PATCH] Protect from menu taxon deletion --- .../managing_taxons/deleting_taxon.feature | 2 +- .../Ui/Admin/ManagingTaxonsContext.php | 2 +- .../EventListener/TaxonDeletionListener.php | 21 ++++++++ .../Resources/config/services/listeners.xml | 2 + .../TaxonDeletionListenerSpec.php | 54 ++++++++++++++++++- .../Resources/translations/flashes.en.yml | 2 + 6 files changed, 80 insertions(+), 3 deletions(-) diff --git a/features/taxonomy/managing_taxons/deleting_taxon.feature b/features/taxonomy/managing_taxons/deleting_taxon.feature index fe6ea9f17e..eb981a532c 100644 --- a/features/taxonomy/managing_taxons/deleting_taxon.feature +++ b/features/taxonomy/managing_taxons/deleting_taxon.feature @@ -24,7 +24,7 @@ Feature: Deleting a taxon And the taxon named "Women" should no longer exist in the registry But the "Shovels" taxon should appear in the registry - @ui + @ui @javascript Scenario: Deleted taxon should disappear from the registry Given the store classifies its products as "T-Shirts" and "Caps" And the store operates on a channel named "Web Store" diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingTaxonsContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingTaxonsContext.php index 3c7f3263d7..bdc213bc17 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingTaxonsContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingTaxonsContext.php @@ -393,7 +393,7 @@ final class ManagingTaxonsContext implements Context public function iShouldBeNotifiedThatICannotDeleteAMenuTaxonOfAnyChannel(): void { $this->notificationChecker->checkNotification( - 'You cannot delete a menu taxon of any channel', + 'You cannot delete a menu taxon of any channel.', NotificationType::failure() ); } diff --git a/src/Sylius/Bundle/CoreBundle/EventListener/TaxonDeletionListener.php b/src/Sylius/Bundle/CoreBundle/EventListener/TaxonDeletionListener.php index 487041f214..07c41fb6fb 100644 --- a/src/Sylius/Bundle/CoreBundle/EventListener/TaxonDeletionListener.php +++ b/src/Sylius/Bundle/CoreBundle/EventListener/TaxonDeletionListener.php @@ -13,6 +13,7 @@ declare(strict_types=1); namespace Sylius\Bundle\CoreBundle\EventListener; +use Sylius\Component\Channel\Repository\ChannelRepositoryInterface; use Sylius\Component\Core\Model\TaxonInterface; use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface; use Symfony\Component\EventDispatcher\GenericEvent; @@ -25,17 +26,37 @@ final class TaxonDeletionListener /** @var SessionInterface */ private $session; + /** @var ChannelRepositoryInterface $channelRepository */ + private $channelRepository; + /** @var TaxonAwareRuleUpdaterInterface[] */ private $ruleUpdaters; public function __construct( SessionInterface $session, + ChannelRepositoryInterface $channelRepository, TaxonAwareRuleUpdaterInterface ...$ruleUpdaters ) { $this->session = $session; + $this->channelRepository = $channelRepository; $this->ruleUpdaters = $ruleUpdaters; } + public function protectFromRemovingMenuTaxon(GenericEvent $event): void + { + $taxon = $event->getSubject(); + Assert::isInstanceOf($taxon, TaxonInterface::class); + + $channel = $this->channelRepository->findOneBy(['menuTaxon' => $taxon]); + if ($channel !== null) { + /** @var FlashBagInterface $flashes */ + $flashes = $this->session->getBag('flashes'); + $flashes->add('error', 'sylius.taxon.menu_taxon_delete'); + + $event->stopPropagation(); + } + } + public function removeTaxonFromPromotionRules(GenericEvent $event): void { $taxon = $event->getSubject(); diff --git a/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml b/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml index c1ebb3d1f0..5f4f549b29 100644 --- a/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml +++ b/src/Sylius/Bundle/CoreBundle/Resources/config/services/listeners.xml @@ -98,8 +98,10 @@ + + diff --git a/src/Sylius/Bundle/CoreBundle/spec/EventListener/TaxonDeletionListenerSpec.php b/src/Sylius/Bundle/CoreBundle/spec/EventListener/TaxonDeletionListenerSpec.php index 59d9634cdf..b44886e6cd 100644 --- a/src/Sylius/Bundle/CoreBundle/spec/EventListener/TaxonDeletionListenerSpec.php +++ b/src/Sylius/Bundle/CoreBundle/spec/EventListener/TaxonDeletionListenerSpec.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace spec\Sylius\Bundle\CoreBundle\EventListener; use PhpSpec\ObjectBehavior; +use Sylius\Component\Channel\Repository\ChannelRepositoryInterface; +use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Core\Model\TaxonInterface; use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface; use Symfony\Component\EventDispatcher\GenericEvent; @@ -24,10 +26,60 @@ final class TaxonDeletionListenerSpec extends ObjectBehavior { function let( SessionInterface $session, + ChannelRepositoryInterface $channelRepository, TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater, TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater ): void { - $this->beConstructedWith($session, $hasTaxonRuleUpdater, $totalOfItemsFromTaxonRuleUpdater); + $this->beConstructedWith( + $session, + $channelRepository, + $hasTaxonRuleUpdater, + $totalOfItemsFromTaxonRuleUpdater + ); + } + + function it_does_not_allow_to_remove_taxon_if_any_channel_has_it_as_a_menu_taxon( + SessionInterface $session, + ChannelRepositoryInterface $channelRepository, + GenericEvent $event, + TaxonInterface $taxon, + ChannelInterface $channel, + FlashBagInterface $flashes + ): void { + $event->getSubject()->willReturn($taxon); + + $channelRepository->findOneBy(['menuTaxon' => $taxon])->willReturn($channel); + + $session->getBag('flashes')->willReturn($flashes); + $flashes->add('error', 'sylius.taxon.menu_taxon_delete')->shouldBeCalled(); + $event->stopPropagation()->shouldBeCalled(); + + $this->protectFromRemovingMenuTaxon($event); + } + + function it_does_nothing_if_taxon_is_not_a_menu_taxon_of_any_channel( + SessionInterface $session, + ChannelRepositoryInterface $channelRepository, + GenericEvent $event, + TaxonInterface $taxon, + ChannelInterface $channel + ): void { + $event->getSubject()->willReturn($taxon); + + $channelRepository->findOneBy(['menuTaxon' => $taxon])->willReturn(null); + $session->getBag('flashes')->shouldNotBeCalled(); + + $this->protectFromRemovingMenuTaxon($event); + } + + function it_throws_an_exception_if_an_event_subject_is_not_taxon(GenericEvent $event): void + { + $event->getSubject()->willReturn('wrongSubject'); + + $this + ->shouldThrow(\InvalidArgumentException::class) + ->during('protectFromRemovingMenuTaxon', [$event]) + ; } function it_adds_flash_that_promotions_have_been_updated( diff --git a/src/Sylius/Bundle/UiBundle/Resources/translations/flashes.en.yml b/src/Sylius/Bundle/UiBundle/Resources/translations/flashes.en.yml index 0fd9e41ac7..8096639e9e 100644 --- a/src/Sylius/Bundle/UiBundle/Resources/translations/flashes.en.yml +++ b/src/Sylius/Bundle/UiBundle/Resources/translations/flashes.en.yml @@ -26,3 +26,5 @@ sylius: update_error: 'There was an unexpected problem with updating a product variant. Please, try to update product variant again.' promotion: update_rules: 'Some rules of the promotions with codes %codes% have been updated.' + taxon: + menu_taxon_delete: 'You cannot delete a menu taxon of any channel.'