PHP Patterns
example1.php #
<?php
// https://forum.nette.org/cs/34970-rozne-ceny-za-roznych-okolnosti#p218919
class Product
{
private Price $price;
public function getPrice(): Price
{
return $this->price;
}
}
//
public function getPrice(...$modifiers): Price
{
$price = $this->price;
foreach($modifiers as $modifier) {
$price = $price->modify($modifier);
}
return $price;
}
//
class PriceResolver
{
private array $modifiers = [];
public function setCustomer(IModifier $modifier): void
{
$this->modifiers[] = $modifier;
}
public function setSeason(IModifier $modifier): void
{
$this->modifiers[] = $modifier;
}
public function setOtherRule(IModifier $modifier): void
{
$this->modifiers[] = $modifier;
}
public function resolve(Product $product): Price
{
$price = $product->getPrice();
foreach($modifiers as $modifier) {
$price = $price->modify($modifier);
}
return $price;
}
}
class Price
{
private float $amount;
private string $currency;
public function __construct(float $amount, string $currency)
{
$this->amount = $amount;
$this->currency = $currency;
}
public function getAmount(int $precision = 2): float
{
return round($this->amount, $precision);
}
public function getCurrency(): string
{
return $this->currency;
}
public function modify(Modifier $modifier): Price
{
if($modifier->isPercentage()) {
$amount = $this->getAmount(4) * (100 + $modifier->getAmount()) / 100;
}
else {
$amount = $this->getAmount(4) + $modifier->getAmount();
}
return new self($amount, $this->currency);
}
public function multiply(float $multiplier): Price
{
return new self($this->amount * $multiplier, $this->currency);
}
public function divide(float $divisor): Price
{
return new self($this->amount / $divisor, $this->currency);
}
public function add(Price $price): Price
{
if($this->currency !== $price->getCurrency()) {
throw new CurrencyMismatchException("Currency missmatch");
}
return new self($this->amount + $price->getAmount(4), $this->currency);
}
public function minus(Price $price): Price
{
if($this->currency !== $price->getCurrency()) {
throw new CurrencyMismatchException("Currency missmatch");
}
return new self($this->amount - $price->getAmount(4), $this->currency);
}
public function equals(Price $other): bool
{
return $this->getAmount(4) === $other->getAmount(4) and $this->currency === $other->getCurrency();
}
}
class Modifier
{
const TYPE_PERCENTAGE = "P";
const TYPE_ABSOLUTE = "A";
private string $type;
private float $amount;
public function __construct(string $type, float $amount)
{
$this->type = $type;
$this->amount = $amount;
}
public function getType(): string
{
return $this->type;
}
public function getAmount(int $precision = 2): float
{
return round($this->amount, $precision);
}
public function cumulate(Modifier $modifier): Modifier
{
if($this->type !== $modifier->getType()) {
throw new TypeMissmatchException("Type missmatch");
}
return new self($this->type, $this->amount + $modifier->getAmount(4));
}
public function isPercentage(): bool
{
return $this->type === self::TYPE_PERCENTAGE;
}
public function isAbsolute(): bool
{
return $this->type === self::TYPE_ABSOLUTE;
}
}