diff --git a/README.md b/README.md index 91ef6a3..fbf1140 100755 --- a/README.md +++ b/README.md @@ -66,6 +66,12 @@ setono_sylius_callout: # That way you can trigger callouts assign process manually when # finish adding all rules # manual_triggering: true + + no_rules_eligible: false + # Set this option to true if you want no rules to be + # treated as eligible (e.g. callout without rules will + # be applied to all products) + # no_rules_eligible: true ``` ### Step 5: Import routing diff --git a/features/shop/displaying_product_callouts.feature b/features/shop/displaying_product_callouts.feature index a12e520..2322058 100644 --- a/features/shop/displaying_product_callouts.feature +++ b/features/shop/displaying_product_callouts.feature @@ -43,3 +43,9 @@ Feature: Displaying Product Callouts And this callout is disabled for "United States" channel When I browse products from taxon "T-Shirts" Then I should see 0 products with callout "Disabled" + + @ui + Scenario: Callouts without rules should be applied to all products + Given there is a callout "No rules" with "

No rules

" html + When I browse products from taxon "T-Shirts" + Then I should see 3 product with callout "No rules" diff --git a/spec/Callout/Checker/Eligibility/CalloutRulesEligibilityCheckerSpec.php b/spec/Callout/Checker/Eligibility/CalloutRulesEligibilityCheckerSpec.php index 83a61e8..bb6f1c7 100644 --- a/spec/Callout/Checker/Eligibility/CalloutRulesEligibilityCheckerSpec.php +++ b/spec/Callout/Checker/Eligibility/CalloutRulesEligibilityCheckerSpec.php @@ -40,6 +40,17 @@ function it_eligible_only_when_rules_specified( $this->isEligible($product, $callout)->shouldReturn(false); } + function it_eligible_when_no_rules_specified_but_isNoRulesEligible_option_set_to_true( + ServiceRegistryInterface $ruleRegistry, + CalloutInterface $callout, + CalloutsAwareInterface $product + ): void { + $this->beConstructedWith($ruleRegistry, true); + $callout->hasRules()->willReturn(false); + + $this->isEligible($product, $callout)->shouldReturn(true); + } + function it_checks_eligibility( CalloutInterface $callout, CalloutRuleInterface $rule, diff --git a/src/Callout/Checker/Eligibility/CalloutRulesEligibilityChecker.php b/src/Callout/Checker/Eligibility/CalloutRulesEligibilityChecker.php index 422fcdc..3a920f3 100644 --- a/src/Callout/Checker/Eligibility/CalloutRulesEligibilityChecker.php +++ b/src/Callout/Checker/Eligibility/CalloutRulesEligibilityChecker.php @@ -18,17 +18,19 @@ final class CalloutRulesEligibilityChecker implements CalloutEligibilityCheckerI /** @var ServiceRegistryInterface */ private $ruleRegistry; - public function __construct(ServiceRegistryInterface $ruleRegistry) + /** @var bool */ + private $isNoRulesEligible; + + public function __construct(ServiceRegistryInterface $ruleRegistry, bool $isNoRulesEligible = false) { $this->ruleRegistry = $ruleRegistry; + $this->isNoRulesEligible = $isNoRulesEligible; } public function isEligible(CalloutsAwareInterface $product, CalloutInterface $callout): bool { - // If a Callout has no rules - it won't be applied to any products - // As far as Callout should be applied to some group of products, not to all products if (!$callout->hasRules()) { - return false; + return $this->isNoRulesEligible; } // All rules should pass for Product to be eligible diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 7b61e0e..deb27a7 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -40,6 +40,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->info('Set it to true if you have thousands of products in your store and/or want to trigger callout assign manually.') ->defaultFalse() ->end() + ->booleanNode('no_rules_eligible') + ->info('Set it to true if you want no rules to be treated as eligible (callout will be applied to all products).') + ->defaultFalse() + ->end() ->end() ; diff --git a/src/DependencyInjection/SetonoSyliusCalloutExtension.php b/src/DependencyInjection/SetonoSyliusCalloutExtension.php index 7603188..fcae0c0 100644 --- a/src/DependencyInjection/SetonoSyliusCalloutExtension.php +++ b/src/DependencyInjection/SetonoSyliusCalloutExtension.php @@ -19,6 +19,7 @@ public function load(array $config, ContainerBuilder $container): void $loader->load('services.xml'); $container->setParameter('setono_sylius_callout.manual_triggering', $config['manual_triggering']); + $container->setParameter('setono_sylius_callout.no_rules_eligible', $config['no_rules_eligible']); $this->registerResources('setono_sylius_callout', $config['driver'], $config['resources'], $container); } } diff --git a/src/EventListener/CalloutDoctrineEventSubscriber.php b/src/EventListener/CalloutDoctrineEventSubscriber.php index c1473f8..dd1092b 100644 --- a/src/EventListener/CalloutDoctrineEventSubscriber.php +++ b/src/EventListener/CalloutDoctrineEventSubscriber.php @@ -5,14 +5,30 @@ namespace Setono\SyliusCalloutPlugin\EventListener; use Doctrine\Common\EventSubscriber; +use Doctrine\ORM\EntityManager; use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Events; use Doctrine\ORM\PersistentCollection; use Setono\SyliusCalloutPlugin\Model\CalloutInterface; use Setono\SyliusCalloutPlugin\Model\CalloutRuleInterface; +use Symfony\Component\Messenger\MessageBusInterface; final class CalloutDoctrineEventSubscriber extends AbstractCalloutDoctrineEventSubscriber implements EventSubscriber { + /** @var bool */ + private $isNoRulesEligible; + + public function __construct( + EntityManager $calloutManager, + MessageBusInterface $commandBus, + bool $manualTriggering = false, + bool $isNoRulesEligible = false + ) { + parent::__construct($calloutManager, $commandBus, $manualTriggering); + + $this->isNoRulesEligible = $isNoRulesEligible; + } + public function getSubscribedEvents() { return [ @@ -26,6 +42,16 @@ public function onFlush(OnFlushEventArgs $args): void $em = $args->getEntityManager(); $uow = $em->getUnitOfWork(); + if ($this->isNoRulesEligible) { + foreach ($uow->getScheduledEntityInsertions() as $entity) { + if (!$entity instanceof CalloutInterface) { + continue; + } + + $this->scheduleCalloutUpdate($entity); + } + } + // Here we need only rules collection changes to track as far as // creating/updating Callout itself (without rules) not require // any assign triggering diff --git a/src/Resources/config/services/callout/eligibility_checker.xml b/src/Resources/config/services/callout/eligibility_checker.xml index b114ce4..fe1bd49 100755 --- a/src/Resources/config/services/callout/eligibility_checker.xml +++ b/src/Resources/config/services/callout/eligibility_checker.xml @@ -8,6 +8,7 @@ + %setono_sylius_callout.no_rules_eligible% diff --git a/src/Resources/config/services/event_listener.xml b/src/Resources/config/services/event_listener.xml index 09b66ef..3707e5f 100644 --- a/src/Resources/config/services/event_listener.xml +++ b/src/Resources/config/services/event_listener.xml @@ -15,6 +15,7 @@ + %setono_sylius_callout.no_rules_eligible% diff --git a/src/Resources/config/validation/Callout.xml b/src/Resources/config/validation/Callout.xml index 293d588..2e5f20d 100644 --- a/src/Resources/config/validation/Callout.xml +++ b/src/Resources/config/validation/Callout.xml @@ -51,15 +51,5 @@ - - - - - - - - diff --git a/src/Resources/translations/validators.en.yml b/src/Resources/translations/validators.en.yml index d8c6c27..0683bd1 100755 --- a/src/Resources/translations/validators.en.yml +++ b/src/Resources/translations/validators.en.yml @@ -8,8 +8,6 @@ setono_sylius_callout: priority: not_blank: Priority cannot be blank. numeric: Priority must be an integer. - rules: - min: Specify at least one rule. callout_translation: text: not_blank: Text cannot be blank. diff --git a/tests/Application/config/packages/setono_sylius_callouts_plugin.yaml b/tests/Application/config/packages/setono_sylius_callouts_plugin.yaml index 48f8103..5082fb1 100644 --- a/tests/Application/config/packages/setono_sylius_callouts_plugin.yaml +++ b/tests/Application/config/packages/setono_sylius_callouts_plugin.yaml @@ -1,3 +1,6 @@ imports: - { resource: "@SetonoSyliusCalloutPlugin/Resources/config/app/config.yaml"} - { resource: "@SetonoSyliusCalloutPlugin/Resources/config/app/fixtures.yaml"} + +setono_sylius_callout: + no_rules_eligible: true diff --git a/tests/Behat/Context/Setup/ProductCalloutContext.php b/tests/Behat/Context/Setup/ProductCalloutContext.php index 970d178..09f1ff9 100644 --- a/tests/Behat/Context/Setup/ProductCalloutContext.php +++ b/tests/Behat/Context/Setup/ProductCalloutContext.php @@ -77,7 +77,7 @@ public function thereIsAProductCalloutWithRuleConfiguredWithProduct(string $name * @Given /^there is a callout "([^"]+)" with "Is new" rule configured with (\d+) days? and with "([^"]+)" html$/ * @Given /^there is a callout "([^"]+)" with "Is new" rule configured with (\d+) days? and with "([^"]+)" html in ("[^"]+" channel)$/ */ - public function thereIsAnIsNewProductCalloutWithRuleConfiguredWithProduct(string $name, string $days, string $html, ChannelInterface $channel = null): void + public function thereIsAnIsNewProductCalloutWithRuleConfiguredWithDays(string $name, string $days, string $html, ChannelInterface $channel = null): void { $callout = $this->createCallout($name, $html, $channel); $callout->addRule($this->calloutRuleFactory->createIsNewProduct((int)$days)); @@ -86,6 +86,18 @@ public function thereIsAnIsNewProductCalloutWithRuleConfiguredWithProduct(string $this->objectManager->flush(); } + /** + * @Given /^there is a callout "([^"]+)" with "([^"]+)" html$/ + * @Given /^there is a callout "([^"]+)" with "([^"]+)" html in ("[^"]+" channel)$/ + */ + public function thereIsCalloutWithoutRules(string $name, string $html, ChannelInterface $channel = null): void + { + $callout = $this->createCallout($name, $html, $channel); + + $this->objectManager->persist($callout); + $this->objectManager->flush(); + } + /** * @Given /^(the callout "([^"]+)") is disabled for ("[^"]+" channel)$/ * @Given /^(the callout "([^"]+)") is disabled for (this channel)$/