Skip to content

Commit

Permalink
Allow runtime eligibility checks
Browse files Browse the repository at this point in the history
  • Loading branch information
loevgaard committed Jan 26, 2024
1 parent 4dfe2ab commit 37ee7af
Show file tree
Hide file tree
Showing 18 changed files with 122 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@
interface CalloutEligibilityCheckerInterface

Check failure on line 10 in src/Checker/Eligibility/CalloutEligibilityCheckerInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

Method isRuntimeEligible() was added to interface Setono\SyliusCalloutPlugin\Checker\Eligibility\CalloutEligibilityCheckerInterface
{
public function isEligible(ProductInterface $product, CalloutInterface $callout): bool;

/**
* This is called at runtime, so it should be as fast as possible
*/
public function isRuntimeEligible(ProductInterface $product, CalloutInterface $callout): bool;
}
24 changes: 24 additions & 0 deletions src/Checker/Eligibility/CalloutRulesEligibilityChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,35 @@ public function isEligible(ProductInterface $product, CalloutInterface $callout)
return true;
}

public function isRuntimeEligible(ProductInterface $product, CalloutInterface $callout): bool

Check warning on line 38 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L38

Added line #L38 was not covered by tests
{
if (!$callout->hasRules()) {
return true;

Check warning on line 41 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L40-L41

Added lines #L40 - L41 were not covered by tests
}

// All rules should pass for Product to be eligible
foreach ($callout->getRules() as $rule) {
if (!$this->isRuntimeEligibleToRule($product, $rule)) {
return false;

Check warning on line 47 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L45-L47

Added lines #L45 - L47 were not covered by tests
}
}

return true;

Check warning on line 51 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L51

Added line #L51 was not covered by tests
}

private function isEligibleToRule(ProductInterface $product, CalloutRuleInterface $rule): bool
{
/** @var CalloutRuleCheckerInterface $checker */
$checker = $this->ruleRegistry->get((string) $rule->getType());

return $checker->isEligible($product, $rule->getConfiguration());
}

private function isRuntimeEligibleToRule(ProductInterface $product, CalloutRuleInterface $rule): bool

Check warning on line 62 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L62

Added line #L62 was not covered by tests
{
/** @var CalloutRuleCheckerInterface $checker */
$checker = $this->ruleRegistry->get((string) $rule->getType());

Check warning on line 65 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L65

Added line #L65 was not covered by tests

return $checker->isEligible($product, $rule->getConfiguration());

Check warning on line 67 in src/Checker/Eligibility/CalloutRulesEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CalloutRulesEligibilityChecker.php#L67

Added line #L67 was not covered by tests
}
}
11 changes: 11 additions & 0 deletions src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,15 @@ public function isEligible(ProductInterface $product, CalloutInterface $callout)

return true;
}

public function isRuntimeEligible(ProductInterface $product, CalloutInterface $callout): bool

Check warning on line 27 in src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php#L27

Added line #L27 was not covered by tests
{
foreach ($this->services as $service) {
if (!$service->isRuntimeEligible($product, $callout)) {
return false;

Check warning on line 31 in src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php#L29-L31

Added lines #L29 - L31 were not covered by tests
}
}

return true;

Check warning on line 35 in src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Eligibility/CompositeCalloutEligibilityChecker.php#L35

Added line #L35 was not covered by tests
}
}
15 changes: 15 additions & 0 deletions src/Checker/Rule/AbstractCalloutRuleChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusCalloutPlugin\Checker\Rule;

use Sylius\Component\Core\Model\ProductInterface;

abstract class AbstractCalloutRuleChecker implements CalloutRuleCheckerInterface
{
public function isRuntimeEligible(ProductInterface $product, array $configuration): bool

Check warning on line 11 in src/Checker/Rule/AbstractCalloutRuleChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Rule/AbstractCalloutRuleChecker.php#L11

Added line #L11 was not covered by tests
{
return true;

Check warning on line 13 in src/Checker/Rule/AbstractCalloutRuleChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Rule/AbstractCalloutRuleChecker.php#L13

Added line #L13 was not covered by tests
}
}
5 changes: 5 additions & 0 deletions src/Checker/Rule/CalloutRuleCheckerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
interface CalloutRuleCheckerInterface

Check failure on line 9 in src/Checker/Rule/CalloutRuleCheckerInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

Method isRuntimeEligible() was added to interface Setono\SyliusCalloutPlugin\Checker\Rule\CalloutRuleCheckerInterface
{
public function isEligible(ProductInterface $product, array $configuration): bool;

/**
* This is called at runtime, so it should be as fast as possible
*/
public function isRuntimeEligible(ProductInterface $product, array $configuration): bool;
}
2 changes: 1 addition & 1 deletion src/Checker/Rule/HasProductCalloutRuleChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Sylius\Component\Core\Repository\ProductRepositoryInterface;
use Webmozart\Assert\Assert;

final class HasProductCalloutRuleChecker implements CalloutRuleCheckerInterface
final class HasProductCalloutRuleChecker extends AbstractCalloutRuleChecker
{
public const TYPE = 'has_product';

Expand Down
2 changes: 1 addition & 1 deletion src/Checker/Rule/HasTaxonCalloutRuleChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Sylius\Component\Taxonomy\Repository\TaxonRepositoryInterface;
use Webmozart\Assert\Assert;

final class HasTaxonCalloutRuleChecker implements CalloutRuleCheckerInterface
final class HasTaxonCalloutRuleChecker extends AbstractCalloutRuleChecker
{
public const TYPE = 'has_taxon';

Expand Down
2 changes: 1 addition & 1 deletion src/Checker/Rule/IsNewCalloutRuleChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use Sylius\Component\Core\Model\ProductInterface;
use Webmozart\Assert\Assert;

final class IsNewCalloutRuleChecker implements CalloutRuleCheckerInterface
final class IsNewCalloutRuleChecker extends AbstractCalloutRuleChecker
{
public const TYPE = 'is_new';

Expand Down
5 changes: 5 additions & 0 deletions src/Checker/Rule/OnSaleCalloutRuleChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public function __construct(ChannelContextInterface $channelContext)
}

public function isEligible(ProductInterface $product, array $configuration): bool
{
return true;

Check warning on line 27 in src/Checker/Rule/OnSaleCalloutRuleChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Rule/OnSaleCalloutRuleChecker.php#L27

Added line #L27 was not covered by tests
}

public function isRuntimeEligible(ProductInterface $product, array $configuration): bool

Check warning on line 30 in src/Checker/Rule/OnSaleCalloutRuleChecker.php

View check run for this annotation

Codecov / codecov/patch

src/Checker/Rule/OnSaleCalloutRuleChecker.php#L30

Added line #L30 was not covered by tests
{
try {
/** @var ChannelInterface $channel */
Expand Down
14 changes: 13 additions & 1 deletion src/Form/Type/Rule/OnSaleConfigurationType.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,23 @@
namespace Setono\SyliusCalloutPlugin\Form\Type\Rule;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;

final class OnSaleConfigurationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void

Check warning on line 13 in src/Form/Type/Rule/OnSaleConfigurationType.php

View check run for this annotation

Codecov / codecov/patch

src/Form/Type/Rule/OnSaleConfigurationType.php#L13

Added line #L13 was not covered by tests
{
$builder
->add('singleVariantEligible', CheckboxType::class, [
'label' => 'setono_sylius_callout.form.callout_rule.on_sale.single_variant_eligible',
'required' => false,
])
;

Check warning on line 20 in src/Form/Type/Rule/OnSaleConfigurationType.php

View check run for this annotation

Codecov / codecov/patch

src/Form/Type/Rule/OnSaleConfigurationType.php#L15-L20

Added lines #L15 - L20 were not covered by tests
}

public function getBlockPrefix(): string
{
return 'setono_callout_rule_on_sale_configuration';
return 'setono_sylius_callout_rule_on_sale_configuration';

Check warning on line 25 in src/Form/Type/Rule/OnSaleConfigurationType.php

View check run for this annotation

Codecov / codecov/patch

src/Form/Type/Rule/OnSaleConfigurationType.php#L25

Added line #L25 was not covered by tests
}
}
12 changes: 11 additions & 1 deletion src/Model/Callout.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,18 @@ public function hasRules(): bool
return !$this->rules->isEmpty();
}

public function hasRule(CalloutRuleInterface $rule): bool
public function hasRule(CalloutRuleInterface|string $rule): bool

Check failure on line 213 in src/Model/Callout.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $rule of Setono\SyliusCalloutPlugin\Model\Callout#hasRule() changed from Setono\SyliusCalloutPlugin\Model\CalloutRuleInterface to Setono\SyliusCalloutPlugin\Model\CalloutRuleInterface|string

Check warning on line 213 in src/Model/Callout.php

View check run for this annotation

Codecov / codecov/patch

src/Model/Callout.php#L213

Added line #L213 was not covered by tests
{
if (is_string($rule)) {
foreach ($this->rules as $r) {
if ($r->getType() === $rule) {
return true;

Check warning on line 218 in src/Model/Callout.php

View check run for this annotation

Codecov / codecov/patch

src/Model/Callout.php#L215-L218

Added lines #L215 - L218 were not covered by tests
}
}

return false;

Check warning on line 222 in src/Model/Callout.php

View check run for this annotation

Codecov / codecov/patch

src/Model/Callout.php#L222

Added line #L222 was not covered by tests
}

return $this->rules->contains($rule);
}

Expand Down
5 changes: 4 additions & 1 deletion src/Model/CalloutInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ public function getRules(): Collection;

public function hasRules(): bool;

public function hasRule(CalloutRuleInterface $rule): bool;
/**
* @param CalloutRuleInterface|string $rule if the rule is a string, it will be treated as a rule type
*/
public function hasRule(CalloutRuleInterface|string $rule): bool;

Check failure on line 82 in src/Model/CalloutInterface.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $rule of Setono\SyliusCalloutPlugin\Model\CalloutInterface#hasRule() changed from Setono\SyliusCalloutPlugin\Model\CalloutRuleInterface to Setono\SyliusCalloutPlugin\Model\CalloutRuleInterface|string

public function addRule(CalloutRuleInterface $rule): void;

Expand Down
11 changes: 6 additions & 5 deletions src/Repository/CalloutRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ public function findEnabled(array $codes = []): array

public function findByCodes(array $codes, ChannelInterface $channel, string $locale): array
{
$objs = $this->createQueryBuilder('o')
->select('o, c, t')
->join('o.channels', 'c', 'WITH', 'c = :channel')
->join('o.translations', 't', 'WITH', 't.locale = :locale')
->andWhere('o.code IN (:codes)')
$objs = $this->createQueryBuilder('callout')
->select('callout, rule, channel, translation')
->join('callout.rules', 'rule')
->join('callout.channels', 'channel', 'WITH', 'channel = :channel')
->join('callout.translations', 'translation', 'WITH', 'translation.locale = :locale')
->andWhere('callout.code IN (:codes)')

Check warning on line 44 in src/Repository/CalloutRepository.php

View check run for this annotation

Codecov / codecov/patch

src/Repository/CalloutRepository.php#L39-L44

Added lines #L39 - L44 were not covered by tests
->setParameter('codes', $codes)
->setParameter('channel', $channel)
->setParameter('locale', $locale)
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/config/services/form.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<tag name="form.type"/>
</service>

<service id="setono_sylius_callout.form.type.rule.has_taxon_product"
<service id="setono_sylius_callout.form.type.rule.has_product"
class="Setono\SyliusCalloutPlugin\Form\Type\Rule\HasProductConfigurationType">
<argument type="service" id="sylius.form.type.data_transformer.products_to_codes"/>
<tag name="form.type"/>
Expand Down
1 change: 1 addition & 0 deletions src/Resources/config/services/twig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<service id="setono_sylius_callout.twig.callout_runtime"
class="Setono\SyliusCalloutPlugin\Twig\CalloutRuntime">
<argument type="service" id="setono_sylius_callout.checker.rendering_eligibility.composite"/>
<argument type="service" id="setono_sylius_callout.checker.eligibility.composite"/>
<argument type="service" id="setono_sylius_callout.css_class_builder.default"/>
<argument type="service" id="setono_sylius_callout.provider.rendering_callout"/>
<argument type="service" id="setono_sylius_callout.renderer.callout"/>
Expand Down
2 changes: 2 additions & 0 deletions src/Resources/translations/messages.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ setono_sylius_callout:
taxons: Taxons
is_new:
days: Days
on_sale:
single_variant_eligible: A product is considered on sale if it has a single variant (the default) that is on sale
ui:
action:
assign: Assign
Expand Down
6 changes: 6 additions & 0 deletions src/Twig/CalloutRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Setono\SyliusCalloutPlugin\Twig;

use Setono\SyliusCalloutPlugin\Checker\Eligibility\CalloutEligibilityCheckerInterface;
use Setono\SyliusCalloutPlugin\Checker\RenderingEligibility\CalloutRenderingEligibilityCheckerInterface;
use Setono\SyliusCalloutPlugin\CssClassBuilder\CssClassBuilderInterface;
use Setono\SyliusCalloutPlugin\Model\CalloutInterface;
Expand All @@ -16,6 +17,7 @@ final class CalloutRuntime implements RuntimeExtensionInterface
{
public function __construct(

Check failure on line 18 in src/Twig/CalloutRuntime.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The number of required arguments for Setono\SyliusCalloutPlugin\Twig\CalloutRuntime#__construct() increased from 4 to 5

Check failure on line 18 in src/Twig/CalloutRuntime.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $cssClassBuilder of Setono\SyliusCalloutPlugin\Twig\CalloutRuntime#__construct() changed from Setono\SyliusCalloutPlugin\CssClassBuilder\CssClassBuilderInterface to a non-contravariant Setono\SyliusCalloutPlugin\Checker\Eligibility\CalloutEligibilityCheckerInterface

Check failure on line 18 in src/Twig/CalloutRuntime.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $renderingCalloutProvider of Setono\SyliusCalloutPlugin\Twig\CalloutRuntime#__construct() changed from Setono\SyliusCalloutPlugin\Provider\RenderingCalloutProviderInterface to a non-contravariant Setono\SyliusCalloutPlugin\CssClassBuilder\CssClassBuilderInterface

Check failure on line 18 in src/Twig/CalloutRuntime.php

View workflow job for this annotation

GitHub Actions / Backwards Compatibility Check

The parameter $calloutRenderer of Setono\SyliusCalloutPlugin\Twig\CalloutRuntime#__construct() changed from Setono\SyliusCalloutPlugin\Renderer\CalloutRendererInterface to a non-contravariant Setono\SyliusCalloutPlugin\Provider\RenderingCalloutProviderInterface
private readonly CalloutRenderingEligibilityCheckerInterface $calloutRenderingEligibilityChecker,
private readonly CalloutEligibilityCheckerInterface $calloutEligibilityChecker,
private readonly CssClassBuilderInterface $cssClassBuilder,
private readonly RenderingCalloutProviderInterface $renderingCalloutProvider,
private readonly CalloutRendererInterface $calloutRenderer,
Expand All @@ -42,6 +44,10 @@ public function getCallouts(ProductInterface $product, string $element = null):
continue;
}

if (!$this->calloutEligibilityChecker->isRuntimeEligible($product, $callout)) {
continue;

Check warning on line 48 in src/Twig/CalloutRuntime.php

View check run for this annotation

Codecov / codecov/patch

src/Twig/CalloutRuntime.php#L48

Added line #L48 was not covered by tests
}

$elements = $callout->getElements();
if ([] === $elements) {
$elements = [CalloutInterface::DEFAULT_KEY];
Expand Down
10 changes: 10 additions & 0 deletions tests/Twig/CalloutRuntimeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Setono\SyliusCalloutPlugin\Checker\Eligibility\CalloutEligibilityCheckerInterface;
use Setono\SyliusCalloutPlugin\Checker\RenderingEligibility\CalloutRenderingEligibilityCheckerInterface;
use Setono\SyliusCalloutPlugin\CssClassBuilder\CssClassBuilderInterface;
use Setono\SyliusCalloutPlugin\Model\Callout;
Expand Down Expand Up @@ -54,6 +55,14 @@ private function getCalloutRuntime(): CalloutRuntime
$calloutRenderingEligibilityChecker = $this->prophesize(CalloutRenderingEligibilityCheckerInterface::class);
$calloutRenderingEligibilityChecker->isEligible(Argument::type(CalloutInterface::class))->willReturn(true);

$calloutEligibilityChecker = $this->prophesize(CalloutEligibilityCheckerInterface::class);
$calloutEligibilityChecker
->isRuntimeEligible(
Argument::type(ProductInterface::class),
Argument::type(CalloutInterface::class),
)->willReturn(true)
;

$cssClassBuilder = $this->prophesize(CssClassBuilderInterface::class);

$renderCalloutProvider = $this->prophesize(RenderingCalloutProviderInterface::class);
Expand All @@ -70,6 +79,7 @@ private function getCalloutRuntime(): CalloutRuntime

return new CalloutRuntime(
$calloutRenderingEligibilityChecker->reveal(),
$calloutEligibilityChecker->reveal(),
$cssClassBuilder->reveal(),
$renderCalloutProvider->reveal(),
$calloutRenderer->reveal(),
Expand Down

0 comments on commit 37ee7af

Please sign in to comment.