Protect from menu taxon deletion

This commit is contained in:
Mateusz Zalewski 2020-01-10 15:11:54 +01:00
parent 9b6ce70599
commit afcb228a8c
No known key found for this signature in database
GPG key ID: 9BECA0BB71612E52
6 changed files with 80 additions and 3 deletions

View file

@ -24,7 +24,7 @@ Feature: Deleting a taxon
And the taxon named "Women" should no longer exist in the registry And the taxon named "Women" should no longer exist in the registry
But the "Shovels" taxon should appear in the registry But the "Shovels" taxon should appear in the registry
@ui @ui @javascript
Scenario: Deleted taxon should disappear from the registry Scenario: Deleted taxon should disappear from the registry
Given the store classifies its products as "T-Shirts" and "Caps" Given the store classifies its products as "T-Shirts" and "Caps"
And the store operates on a channel named "Web Store" And the store operates on a channel named "Web Store"

View file

@ -393,7 +393,7 @@ final class ManagingTaxonsContext implements Context
public function iShouldBeNotifiedThatICannotDeleteAMenuTaxonOfAnyChannel(): void public function iShouldBeNotifiedThatICannotDeleteAMenuTaxonOfAnyChannel(): void
{ {
$this->notificationChecker->checkNotification( $this->notificationChecker->checkNotification(
'You cannot delete a menu taxon of any channel', 'You cannot delete a menu taxon of any channel.',
NotificationType::failure() NotificationType::failure()
); );
} }

View file

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\EventListener; namespace Sylius\Bundle\CoreBundle\EventListener;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
use Sylius\Component\Core\Model\TaxonInterface; use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface; use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface;
use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\EventDispatcher\GenericEvent;
@ -25,17 +26,37 @@ final class TaxonDeletionListener
/** @var SessionInterface */ /** @var SessionInterface */
private $session; private $session;
/** @var ChannelRepositoryInterface $channelRepository */
private $channelRepository;
/** @var TaxonAwareRuleUpdaterInterface[] */ /** @var TaxonAwareRuleUpdaterInterface[] */
private $ruleUpdaters; private $ruleUpdaters;
public function __construct( public function __construct(
SessionInterface $session, SessionInterface $session,
ChannelRepositoryInterface $channelRepository,
TaxonAwareRuleUpdaterInterface ...$ruleUpdaters TaxonAwareRuleUpdaterInterface ...$ruleUpdaters
) { ) {
$this->session = $session; $this->session = $session;
$this->channelRepository = $channelRepository;
$this->ruleUpdaters = $ruleUpdaters; $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 public function removeTaxonFromPromotionRules(GenericEvent $event): void
{ {
$taxon = $event->getSubject(); $taxon = $event->getSubject();

View file

@ -98,8 +98,10 @@
<service id="sylius.listener.taxon_deletion" class="Sylius\Bundle\CoreBundle\EventListener\TaxonDeletionListener"> <service id="sylius.listener.taxon_deletion" class="Sylius\Bundle\CoreBundle\EventListener\TaxonDeletionListener">
<argument type="service" id="session" /> <argument type="service" id="session" />
<argument type="service" id="sylius.repository.channel" />
<argument type="service" id="sylius.promotion_rule_updater.total_of_items_from_taxon" /> <argument type="service" id="sylius.promotion_rule_updater.total_of_items_from_taxon" />
<argument type="service" id="sylius.promotion_rule_updater.has_taxon" /> <argument type="service" id="sylius.promotion_rule_updater.has_taxon" />
<tag name="kernel.event_listener" event="sylius.taxon.pre_delete" method="protectFromRemovingMenuTaxon" />
<tag name="kernel.event_listener" event="sylius.taxon.post_delete" method="removeTaxonFromPromotionRules" /> <tag name="kernel.event_listener" event="sylius.taxon.post_delete" method="removeTaxonFromPromotionRules" />
</service> </service>
</services> </services>

View file

@ -14,6 +14,8 @@ declare(strict_types=1);
namespace spec\Sylius\Bundle\CoreBundle\EventListener; namespace spec\Sylius\Bundle\CoreBundle\EventListener;
use PhpSpec\ObjectBehavior; 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\Model\TaxonInterface;
use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface; use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface;
use Symfony\Component\EventDispatcher\GenericEvent; use Symfony\Component\EventDispatcher\GenericEvent;
@ -24,10 +26,60 @@ final class TaxonDeletionListenerSpec extends ObjectBehavior
{ {
function let( function let(
SessionInterface $session, SessionInterface $session,
ChannelRepositoryInterface $channelRepository,
TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater, TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater,
TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater
): void { ): 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( function it_adds_flash_that_promotions_have_been_updated(

View file

@ -26,3 +26,5 @@ sylius:
update_error: 'There was an unexpected problem with updating a product variant. Please, try to update product variant again.' update_error: 'There was an unexpected problem with updating a product variant. Please, try to update product variant again.'
promotion: promotion:
update_rules: 'Some rules of the promotions with codes %codes% have been updated.' 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.'