Skip to content

Commit

Permalink
Made PromotionRuleType Schematized instead of Configurable
Browse files Browse the repository at this point in the history
- Upgrade Xtend to v1.2 - code relies on its `getIdOf()` method
  • Loading branch information
fulopattila122 committed Jul 15, 2024
1 parent 69e6682 commit aff7240
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 112 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"laravel/framework": "^10.43|^11.0",
"konekt/enum": "^4.2",
"konekt/concord": "^1.13",
"konekt/xtend": "^1.1",
"konekt/xtend": "^1.2",
"spatie/laravel-medialibrary": "^11.0",
"cviebrock/eloquent-sluggable": "^10.0|^11.0",
"konekt/laravel-migration-compatibility": "^1.6",
Expand Down
2 changes: 1 addition & 1 deletion src/Promotion/Contracts/Promotion.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ interface Promotion
{
public function isValid(?\DateTimeInterface $at = null): bool;

public function addRule(PromotionRuleType $ruleType): self;
public function addRule(PromotionRuleType|string $type, array $configuration): self;
}
2 changes: 1 addition & 1 deletion src/Promotion/Contracts/PromotionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ interface PromotionRule extends Configurable
{
public function getRuleType(): PromotionRuleType;

public function isRuleTypPassing(object $subject): bool;
public function isPassing(object $subject): bool;
}
15 changes: 4 additions & 11 deletions src/Promotion/Contracts/PromotionRuleType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,12 @@

namespace Vanilo\Promotion\Contracts;

use Nette\Schema\Schema;
use Konekt\Extend\Contracts\Registerable;
use Vanilo\Contracts\Schematized;

interface PromotionRuleType
interface PromotionRuleType extends Schematized, Registerable
{
public static function getName(): string;

public static function getID(): string;

public function isPassing(object $subject): bool;

public function getSchema(): ?Schema;

public function setConfiguration(array $configuration): self;

public function getConfiguration(): ?array;
public function isPassing(object $subject, array $configuration): bool;
}
13 changes: 10 additions & 3 deletions src/Promotion/Models/Promotion.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Illuminate\Support\Collection;
use Vanilo\Promotion\Contracts\Promotion as PromotionContract;
use Vanilo\Promotion\Contracts\PromotionRuleType;
use Vanilo\Promotion\PromotionRuleTypes;

/**
* @property int $id
Expand Down Expand Up @@ -70,11 +71,17 @@ public function isValid(?\DateTimeInterface $at = null): bool
return $this->ends_at->isFuture();
}

public function addRule(PromotionRuleType $ruleType): PromotionContract
public function addRule(PromotionRuleType|string $type, array $configuration): self
{
$typeId = match (true) {
$type instanceof PromotionRuleType => PromotionRuleTypes::getIdOf($type::class), // $type is an object
null !== PromotionRuleTypes::getClassOf($type) => $type, // $type is the registered type ID
default => PromotionRuleTypes::getIdOf($type), // $type is the class name of the rule type
};

$this->rules()->create([
'type' => $ruleType::getID(),
'configuration' => $ruleType->getConfiguration(),
'type' => $typeId,
'configuration' => $configuration,
]);

return $this;
Expand Down
14 changes: 10 additions & 4 deletions src/Promotion/Models/PromotionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Vanilo\Contracts\Schematized;
use Vanilo\Promotion\Contracts\Promotion;
use Vanilo\Promotion\Contracts\PromotionRule as PromotionRuleContract;
use Vanilo\Promotion\Contracts\PromotionRuleType;
use Vanilo\Promotion\PromotionRuleTypes;
use Vanilo\Support\Dto\SchemaDefinition;
use Vanilo\Support\Traits\ConfigurableModel;
use Vanilo\Support\Traits\ConfigurationHasNoSchema;

Expand All @@ -24,7 +26,6 @@
class PromotionRule extends Model implements PromotionRuleContract
{
use ConfigurableModel;
use ConfigurationHasNoSchema;

protected $guarded = ['id', 'created_at', 'updated_at'];

Expand All @@ -39,11 +40,16 @@ public function promotion(): BelongsTo

public function getRuleType(): PromotionRuleType
{
return PromotionRuleTypes::make($this->type)->setConfiguration($this->configuration);
return PromotionRuleTypes::make($this->type);
}

public function isRuleTypPassing(object $subject): bool
public function isPassing(object $subject): bool
{
return $this->getRuleType()->isPassing($subject);
return $this->getRuleType()->isPassing($subject, $this->configuration());
}

public function getConfigurationSchema(): ?Schematized
{
return SchemaDefinition::wrap($this->getRuleType());
}
}
6 changes: 3 additions & 3 deletions src/Promotion/PromotionRuleTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ public static function register(string $id, string $class)

public static function make(string $id, array $parameters = []): PromotionRuleType
{
$gwClass = self::getClassOf($id);
$class = self::getClassOf($id);

if (null === $gwClass) {
if (null === $class) {
throw new InexistentPromotionRuleException(
"No rule is registered with the id `$id`."
);
}

return app()->make($gwClass, $parameters);
return app()->make($class, $parameters);
}
}
2 changes: 1 addition & 1 deletion src/Promotion/Providers/ModuleServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ public function boot()
{
parent::boot();

PromotionRuleTypes::register(CartQuantity::getID(), CartQuantity::class);
PromotionRuleTypes::register(CartQuantity::ID, CartQuantity::class);
}
}
51 changes: 14 additions & 37 deletions src/Promotion/Rules/CartQuantity.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,37 @@
use Nette\Schema\Expect;
use Nette\Schema\Processor;
use Nette\Schema\Schema;
use Vanilo\Cart\Contracts\Cart;
use Vanilo\Promotion\Contracts\PromotionRuleType;

class CartQuantity implements PromotionRuleType
{
private ?array $configuration = null;
public const ID = 'cart_quantity';

public static function getName(): string
{
return __('Cart quantity');
return __('Cart Quantity');
}

public static function getID(): string
public function getSchema(): Schema
{
return 'cart_quantity';
return Expect::structure(['count' => Expect::int(0)->required()])->castTo('array');
}

public function setConfiguration(array $configuration): self
public function getSchemaSample(array $mergeWith = null): array
{
if ($this->getSchema()) {
$configuration = (new Processor())->process($this->getSchema(), $configuration);
}

$this->configuration = (array) $configuration;

return $this;
}

public function getConfiguration(): ?array
{
$configuration = $this->configuration;

if ($this->getSchema()) {
$configuration = (new Processor())->process($this->getSchema(), $configuration);
}

return (array) $configuration;
}

public function getSchema(): ?Schema
{
return Expect::structure(['count' => Expect::int(0)->required()]);
return ['count' => 2];
}

public function isPassing(object $subject): bool
public function isPassing(object $subject, array $configuration): bool
{
if (!$subject instanceof Cart) {
throw new \InvalidArgumentException('Subject must be an instance of Vanilo\Cart\Contracts\Cart');
}
$count = match(true) {
method_exists($subject, 'itemCount') => $subject->itemCount(),
method_exists($subject, 'getItems') => count($subject->getItems()),
default => throw new \InvalidArgumentException('The cart quantity promotion rule requires either `itemCount()` or `getItems()` method on its subject'),
};

if (!$this->getConfiguration()) {
return false;
}
$configuration = (new Processor())->process($this->getSchema(), $configuration);

return $subject->itemCount() <= $this->configuration['count'];
return $count >= $configuration['count'];
}
}
18 changes: 4 additions & 14 deletions src/Promotion/Tests/Examples/CartTotalRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,18 @@ public static function getName(): string
return 'Cart Total';
}

public static function getID(): string
{
// TODO: Implement getID() method.
}

public function isPassing(object $subject): bool
public function isPassing(object $subject, array $configuration): bool
{
// TODO: Implement isPassing() method.
}

public function getSchema(): ?Schema
public function getSchema(): Schema
{
// TODO: Implement getSchema() method.
}

public function setConfiguration(array $configuration): PromotionRuleType
{
// TODO: Implement setConfiguration() method.
}

public function getConfiguration(): ?array
public function getSchemaSample(array $mergeWith = null): array
{
// TODO: Implement getConfiguration() method.
// TODO: Implement getSchemaSample() method.
}
}
7 changes: 6 additions & 1 deletion src/Promotion/Tests/Examples/DummyCart.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

class DummyCart implements Cart
{
public function __construct(
private int $itemCount = 5
) {
}

public function addItem(Buyable $product, float|int $qty = 1, array $params = []): CartItem
{
// TODO: Implement addItem() method.
Expand All @@ -34,7 +39,7 @@ public function clear(): void

public function itemCount(): int
{
return 5;
return $this->itemCount;
}

public function getUser(): ?Authenticatable
Expand Down
18 changes: 4 additions & 14 deletions src/Promotion/Tests/Examples/NthOrderRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,18 @@ public static function getName(): string
return 'Nth Order';
}

public static function getID(): string
{
// TODO: Implement getID() method.
}

public function isPassing(object $subject): bool
public function isPassing(object $subject, array $configuration): bool
{
// TODO: Implement isPassing() method.
}

public function getSchema(): ?Schema
public function getSchema(): Schema
{
// TODO: Implement getSchema() method.
}

public function setConfiguration(array $configuration): PromotionRuleType
{
// TODO: Implement setConfiguration() method.
}

public function getConfiguration(): ?array
public function getSchemaSample(array $mergeWith = null): array
{
// TODO: Implement getConfiguration() method.
// TODO: Implement getSchemaSample() method.
}
}
12 changes: 6 additions & 6 deletions src/Promotion/Tests/PromotionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,25 @@ public function it_can_run_the_type_passing()
{
$ruleA = PromotionRule::create(
[
'type' => CartQuantity::getID(),
'type' => CartQuantity::ID,
'promotion_id' => PromotionFactory::new()->create()->id,
'configuration' => ['count' => 10],
]
);

$ruleB = PromotionRule::create(
[
'type' => CartQuantity::getID(),
'type' => CartQuantity::ID,
'promotion_id' => PromotionFactory::new()->create()->id,
'configuration' => ['count' => 3],
]
);

$this->assertEquals(['count' => 10], $ruleA->configuration());
$this->assertTrue($ruleA->isRuleTypPassing(new DummyCart()));
$this->assertFalse($ruleA->isPassing(new DummyCart()));

$this->assertEquals(['count' => 3], $ruleB->configuration());
$this->assertFalse($ruleB->isRuleTypPassing(new DummyCart()));
$this->assertTrue($ruleB->isPassing(new DummyCart()));
}

/** @test */
Expand All @@ -71,9 +71,9 @@ public function throws_exception_if_configuration_needed_but_its_not_there()
$this->expectException(ValidationException::class);

$rule = PromotionRule::create(
['type' => CartQuantity::getID(), 'promotion_id' => PromotionFactory::new()->create()->id]
['type' => CartQuantity::ID, 'promotion_id' => PromotionFactory::new()->create()->id]
);

$rule->isRuleTypPassing(new DummyCart());
$rule->isPassing(new DummyCart());
}
}
4 changes: 2 additions & 2 deletions src/Promotion/Tests/PromotionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ public function can_determine_if_its_valid()
public function it_can_add_rule_and_validate()
{
$promotion = PromotionFactory::new()->create();
$promotion->addRule(PromotionRuleTypes::make(CartQuantity::getID())->setConfiguration(['count' => 3]));
$promotion->addRule(PromotionRuleTypes::make(CartQuantity::ID), ['count' => 3]);

$this->assertEquals(1, $promotion->rules()->count());
$this->assertEquals(['count' => 3], $promotion->rules()->first()->configuration);
$this->assertEquals(CartQuantity::getID(), $promotion->rules()->first()->type);
$this->assertEquals(CartQuantity::ID, $promotion->rules()->first()->type);
}
}
19 changes: 7 additions & 12 deletions src/Promotion/Tests/Rules/CartQuantityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,26 @@ class CartQuantityTest extends TestCase
/** @test */
public function can_be_created()
{
PromotionRuleTypes::register(CartQuantity::getID(), CartQuantity::class);
$ruleType = PromotionRuleTypes::make(CartQuantity::ID);

$rule = PromotionRuleTypes::make(CartQuantity::getID());

$this->assertInstanceOf(CartQuantity::class, $rule);
$this->assertInstanceOf(CartQuantity::class, $ruleType);
}

/** @test */
public function throws_exception_if_configuration_is_wrong()
{
$this->expectException(ValidationException::class);
PromotionRuleTypes::register(CartQuantity::getID(), CartQuantity::class);
$rule = PromotionRuleTypes::make(CartQuantity::getID());
$cartQuantityRule = PromotionRuleTypes::make(CartQuantity::ID);

$this->assertFalse($rule->isPassing(new DummyCart()));
$this->assertFalse($cartQuantityRule->isPassing(new DummyCart(), ['wrong' => 'config']));
}

/** @test */
public function passes_if_rule_is_valid()
{
PromotionRuleTypes::register(CartQuantity::getID(), CartQuantity::class);
$ruleA = PromotionRuleTypes::make(CartQuantity::getID())->setConfiguration(['count' => 3]);
$ruleB = PromotionRuleTypes::make(CartQuantity::getID())->setConfiguration(['count' => 6]);
$cartQuantityRuleType = PromotionRuleTypes::make(CartQuantity::ID);

$this->assertFalse($ruleA->isPassing(new DummyCart()));
$this->assertTrue($ruleB->isPassing(new DummyCart()));
$this->assertTrue($cartQuantityRuleType->isPassing(new DummyCart(4), ['count' => 3]));
$this->assertFalse($cartQuantityRuleType->isPassing(new DummyCart(6), ['count' => 7]));
}
}
Loading

0 comments on commit aff7240

Please sign in to comment.