Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Admin][Promotion] Fix removing taxon used in promotion rule #10365

Merged
merged 8 commits into from
May 13, 2019
Prev Previous commit
Next Next commit
[Promotion] Split update rule configuration after deleting taxon to s…
…eparate services
  • Loading branch information
GSadee committed May 10, 2019
commit ed2d9a18d07556f2df1f5ca497f3eeda9ff831fe
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,33 @@

namespace Sylius\Bundle\CoreBundle\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Core\Promotion\Checker\Rule\HasTaxonRuleChecker;
use Sylius\Component\Core\Promotion\Checker\Rule\TotalOfItemsFromTaxonRuleChecker;
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Webmozart\Assert\Assert;

final class TaxonDeletionListener
{
/** @var RepositoryInterface */
private $promotionRuleRepository;

/** @var EntityManagerInterface */
private $manager;

public function __construct(RepositoryInterface $promotionRuleRepository, EntityManagerInterface $manager)
{
$this->promotionRuleRepository = $promotionRuleRepository;
$this->manager = $manager;
/** @var TaxonAwareRuleUpdaterInterface */
private $hasTaxonRuleUpdater;

/** @var TaxonAwareRuleUpdaterInterface */
private $totalOfItemsFromTaxonRuleUpdater;

public function __construct(
TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater,
GSadee marked this conversation as resolved.
Show resolved Hide resolved
TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater
) {
$this->hasTaxonRuleUpdater = $hasTaxonRuleUpdater;
$this->totalOfItemsFromTaxonRuleUpdater = $totalOfItemsFromTaxonRuleUpdater;
}

public function removeTaxonFromPromotionRules(GenericEvent $event): void
GSadee marked this conversation as resolved.
Show resolved Hide resolved
{
$taxon = $event->getSubject();
Assert::isInstanceOf($taxon, TaxonInterface::class);

$this->resolveHasTaxonRules($taxon->getCode());
$this->resolveTotalOfItemsFromTaxonRules($taxon->getCode());

$this->manager->flush();
}

private function resolveHasTaxonRules(string $taxonCode): void
{
$promotionRules = $this->promotionRuleRepository->findBy(['type' => HasTaxonRuleChecker::TYPE]);

/** @var PromotionRuleInterface $promotionRule */
foreach ($promotionRules as $promotionRule) {
$configuration = $promotionRule->getConfiguration();
if (in_array($taxonCode, $configuration['taxons'])) {
$configuration['taxons'] = array_values(array_diff($configuration['taxons'], [$taxonCode]));
$promotionRule->setConfiguration($configuration);
}
}
}

private function resolveTotalOfItemsFromTaxonRules(string $taxonCode): void
{
$promotionRules = $this->promotionRuleRepository->findBy(['type' => TotalOfItemsFromTaxonRuleChecker::TYPE]);

/** @var PromotionRuleInterface $promotionRule */
foreach ($promotionRules as $promotionRule) {
$this->removePromotionRuleIfNecessary($promotionRule, $taxonCode);
}
}

private function removePromotionRuleIfNecessary(PromotionRuleInterface $promotionRule, string $taxonCode): void
{
foreach ($promotionRule->getConfiguration() as $configuration) {
if ($taxonCode === $configuration['taxon']) {
$this->promotionRuleRepository->remove($promotionRule);

return;
}
}
$this->hasTaxonRuleUpdater->updateAfterDeletingTaxon($taxon->getCode());
$this->totalOfItemsFromTaxonRuleUpdater->updateAfterDeletingTaxon($taxon->getCode());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@
</service>

<service id="sylius.listener.taxon_deletion" class="Sylius\Bundle\CoreBundle\EventListener\TaxonDeletionListener">
<argument type="service" id="sylius.repository.promotion_rule" />
<argument type="service" id="doctrine.orm.entity_manager" />
<argument type="service" id="sylius.promotion_rule_updater.total_of_items_from_taxon" />
<argument type="service" id="sylius.promotion_rule_updater.has_taxon" />
<tag name="kernel.event_listener" event="sylius.taxon.post_delete" method="removeTaxonFromPromotionRules" />
</service>
</services>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,14 @@
<service id="sylius.promotion_usage_modifier" class="Sylius\Component\Core\Promotion\Modifier\OrderPromotionsUsageModifier">
<argument type="service" id="sylius.manager.promotion" />
</service>

<service id="sylius.promotion_rule_updater.has_taxon" class="Sylius\Component\Core\Promotion\Updater\Rule\HasTaxonRuleUpdater">
<argument type="service" id="sylius.repository.promotion_rule" />
<argument type="service" id="doctrine.orm.entity_manager" />
</service>

<service id="sylius.promotion_rule_updater.total_of_items_from_taxon" class="Sylius\Component\Core\Promotion\Updater\Rule\TotalOfItemsFromTaxonRuleUpdater">
<argument type="service" id="sylius.repository.promotion_rule" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -13,87 +13,31 @@

namespace spec\Sylius\Bundle\CoreBundle\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Core\Promotion\Updater\Rule\TaxonAwareRuleUpdaterInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

final class TaxonDeletionListenerSpec extends ObjectBehavior
{
function let(RepositoryInterface $promotionRuleRepository, EntityManagerInterface $manager): void
{
$this->beConstructedWith($promotionRuleRepository, $manager);
}

function it_removes_rules_that_using_deleted_taxon(
RepositoryInterface $promotionRuleRepository,
EntityManagerInterface $manager,
GenericEvent $event,
TaxonInterface $taxon,
PromotionRuleInterface $firstPromotionRule,
PromotionRuleInterface $secondPromotionRule
function let(
TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater,
TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater
): void {
$event->getSubject()->willReturn($taxon);
$taxon->getCode()->willReturn('toys');

$promotionRuleRepository
->findBy(['type' => 'has_taxon'])
->willReturn([$firstPromotionRule, $secondPromotionRule])
;
$firstPromotionRule->getConfiguration()->willReturn(['taxons' => ['mugs', 'toys']]);
$secondPromotionRule->getConfiguration()->willReturn(['taxons' => ['mugs']]);

$firstPromotionRule->setConfiguration(['taxons' => ['mugs']])->shouldBeCalled();
$secondPromotionRule->setConfiguration(Argument::any())->shouldNotBeCalled();

$promotionRuleRepository->findBy(['type' => 'total_of_items_from_taxon'])->willReturn([]);

$manager->flush()->shouldBeCalled();

$this->removeTaxonFromPromotionRules($event);
}

function it_removes_deleted_taxon_from_rules_configurations(
RepositoryInterface $promotionRuleRepository,
EntityManagerInterface $manager,
GenericEvent $event,
TaxonInterface $taxon,
PromotionRuleInterface $firstPromotionRule,
PromotionRuleInterface $secondPromotionRule
): void {
$event->getSubject()->willReturn($taxon);
$taxon->getCode()->willReturn('toys');

$promotionRuleRepository->findBy(['type' => 'has_taxon'])->willReturn([]);

$promotionRuleRepository
->findBy(['type' => 'total_of_items_from_taxon'])
->willReturn([$firstPromotionRule, $secondPromotionRule])
;
$firstPromotionRule->getConfiguration()->willReturn(['web' => ['taxon' => 'mugs', 'amount' => 500]]);
$secondPromotionRule->getConfiguration()->willReturn(['web' => ['taxon' => 'toys', 'amount' => 300]]);

$promotionRuleRepository->remove($firstPromotionRule)->shouldNotBeCalled();
$promotionRuleRepository->remove($secondPromotionRule)->shouldBeCalled();

$manager->flush()->shouldBeCalled();

$this->removeTaxonFromPromotionRules($event);
$this->beConstructedWith($hasTaxonRuleUpdater, $totalOfItemsFromTaxonRuleUpdater);
}

function it_does_nothing_if_there_is_no_rule_with_given_types(
RepositoryInterface $promotionRuleRepository,
function it_adds_flash_that_promotions_have_been_updated(
TaxonAwareRuleUpdaterInterface $hasTaxonRuleUpdater,
TaxonAwareRuleUpdaterInterface $totalOfItemsFromTaxonRuleUpdater,
GenericEvent $event,
TaxonInterface $taxon
): void {
$event->getSubject()->willReturn($taxon);
$taxon->getCode()->willReturn('toys');

$promotionRuleRepository->findBy(['type' => 'has_taxon'])->willReturn([]);
$promotionRuleRepository->findBy(['type' => 'total_of_items_from_taxon'])->willReturn([]);
$hasTaxonRuleUpdater->updateAfterDeletingTaxon('toys')->willReturn(['christmas', 'holiday']);
$totalOfItemsFromTaxonRuleUpdater->updateAfterDeletingTaxon('toys')->willReturn(['christmas']);

$this->removeTaxonFromPromotionRules($event);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Component\Core\Promotion\Updater\Rule;

use Doctrine\ORM\EntityManagerInterface;
use Sylius\Component\Core\Promotion\Checker\Rule\HasTaxonRuleChecker;
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;

final class HasTaxonRuleUpdater implements TaxonAwareRuleUpdaterInterface
{
/** @var RepositoryInterface */
private $promotionRuleRepository;

/** @var EntityManagerInterface */
private $manager;

public function __construct(RepositoryInterface $promotionRuleRepository, EntityManagerInterface $manager)
{
$this->promotionRuleRepository = $promotionRuleRepository;
$this->manager = $manager;
}

public function updateAfterDeletingTaxon(string $taxonCode): array
{
$updatedPromotionCodes = [];
$promotionRules = $this->promotionRuleRepository->findBy(['type' => HasTaxonRuleChecker::TYPE]);

/** @var PromotionRuleInterface $promotionRule */
foreach ($promotionRules as $promotionRule) {
$configuration = $promotionRule->getConfiguration();
if (in_array($taxonCode, $configuration['taxons'])) {
$configuration['taxons'] = array_values(array_diff($configuration['taxons'], [$taxonCode]));
$promotionRule->setConfiguration($configuration);

$updatedPromotionCodes[] = $promotionRule->getPromotion()->getCode();
}
}

$this->manager->flush();

return $updatedPromotionCodes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Component\Core\Promotion\Updater\Rule;

interface TaxonAwareRuleUpdaterInterface
{
public function updateAfterDeletingTaxon(string $taxonCode): array;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Component\Core\Promotion\Updater\Rule;

use Sylius\Component\Core\Promotion\Checker\Rule\TotalOfItemsFromTaxonRuleChecker;
use Sylius\Component\Promotion\Model\PromotionRuleInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;

final class TotalOfItemsFromTaxonRuleUpdater implements TaxonAwareRuleUpdaterInterface
{
/** @var RepositoryInterface */
private $promotionRuleRepository;

public function __construct(RepositoryInterface $ruleUpdater)
{
$this->promotionRuleRepository = $ruleUpdater;
}

public function updateAfterDeletingTaxon(string $taxonCode): array
{
$updatedPromotionCodes = [];
$promotionRules = $this->promotionRuleRepository->findBy(['type' => TotalOfItemsFromTaxonRuleChecker::TYPE]);

/** @var PromotionRuleInterface $promotionRule */
foreach ($promotionRules as $promotionRule) {
$promotionCode = $this->removePromotionRuleIfNecessary($promotionRule, $taxonCode);

if (null !== $promotionCode) {
$updatedPromotionCodes[] = $promotionRule->getPromotion()->getCode();
}
}

return $updatedPromotionCodes;
}

private function removePromotionRuleIfNecessary(PromotionRuleInterface $promotionRule, string $taxonCode): ?string
{
foreach ($promotionRule->getConfiguration() as $configuration) {
if ($taxonCode === $configuration['taxon']) {
$this->promotionRuleRepository->remove($promotionRule);

return $promotionRule->getPromotion()->getCode();
}
}

return null;
}
}
Loading