Skip to content

Commit

Permalink
feat(Exchange): support more rates, middle, buy and sell
Browse files Browse the repository at this point in the history
  • Loading branch information
h4kuna committed Jan 4, 2024
1 parent 5e5c36b commit e9daa0a
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 7 deletions.
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ parameters:
message: "#^Expression \"\\$ratingList\\['QWE'\\]\" on a separate line does not do anything\\.$#"
count: 1
path: tests/src/RatingList/RatingListTest.php
-
message: "#^Variable property access on h4kuna\\\\Exchange\\\\Currency\\\\Property\\.$#"
count: 2
path: src/Exchange.php

includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
34 changes: 33 additions & 1 deletion src/Currency/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,46 @@ class Property implements Stringable
{
public float $rate;

public float $rateBuy;

public float $rateSell;

public float $sell;

public float $buy;


public function __construct(
public int $foreign,
public float $home,
public string $code,
?float $sell = null,
?float $buy = null,
)
{
$this->rate = $this->foreign === 0 ? 0.0 : $this->home / $this->foreign;
$this->rate = $this->countRate($this->home);

if ($sell === null) {
$this->sell = $this->home;
$this->rateSell = $this->rate;
} else {
$this->sell = $sell;
$this->rateSell = $this->countRate($sell);
}

if ($buy === null) {
$this->buy = $this->home;
$this->rateBuy = $this->rate;
} else {
$this->buy = $buy;
$this->rateBuy = $this->countRate($buy);
}
}


private function countRate(float $rate): float
{
return $this->foreign === 0 ? 0.0 : $rate / $this->foreign;
}


Expand Down
20 changes: 17 additions & 3 deletions src/Exchange.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use Generator;
use h4kuna\Exchange\Currency\Property;
use h4kuna\Exchange\Exceptions\FrozenMethodException;
use h4kuna\Exchange\RatingList;
use h4kuna\Exchange\RatingList\CacheEntity;

/**
Expand All @@ -21,10 +20,14 @@ class Exchange implements \IteratorAggregate, \ArrayAccess
private Property $to;


/**
* @param Rate::* $rate
*/
public function __construct(
string|Property $from,
private RatingList\RatingListInterface $ratingList,
string|Property|null $to = null,
private string $rate = Rate::Middle,
)
{
$this->setFrom($from);
Expand All @@ -42,7 +45,15 @@ public function getFrom(): Property
}


public function modify(?string $to = null, ?string $from = null, ?CacheEntity $cacheEntity = null): static
/**
* @param Rate::* $rate
*/
public function modify(
?string $to = null,
?string $from = null,
?CacheEntity $cacheEntity = null,
string $rate = null,
): static
{
$exchange = clone $this;
if ($cacheEntity !== null) {
Expand All @@ -52,6 +63,9 @@ public function modify(?string $to = null, ?string $from = null, ?CacheEntity $c
// add currency code instead of Property, because load new data from cache
$exchange->setFrom($from ?? $this->from->code);
$exchange->setTo($to ?? $this->to->code);
if ($rate !== null) {
$exchange->rate = $rate;
}

return $exchange;
}
Expand Down Expand Up @@ -102,7 +116,7 @@ public function transfer(float $price, ?string $from = null, ?string $to = null)

$from = $from === null ? $this->from : $this->ratingList->get($from);
if ($to !== $from) {
$price *= $from->rate / $to->rate;
$price *= $from->{$this->rate} / $to->{$this->rate};
}

return [$price, $to];
Expand Down
18 changes: 18 additions & 0 deletions src/Rate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);

namespace h4kuna\Exchange;

use h4kuna\Exchange\Currency\Property;

/**
* become enum
*/
final class Rate
{
/** @see Property::$rate */
public const Middle = 'rate';
/** @see Property::$rateSell */
public const Sell = 'rateSell';
/** @see Property::$rateBuy */
public const Buy = 'rateBuy';
}
5 changes: 3 additions & 2 deletions src/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ public static function transformCurrencies(array $currencies): array
*/
public static function countTTL(DateTime $dateTime, int $beforeExpiration = 900): int
{
if (($dateTime->getTimestamp() - $beforeExpiration) < time()) {
$time = time();
if (($dateTime->getTimestamp() - $beforeExpiration) < $time) {
$dateTime->modify('+1 day');
}

return $dateTime->getTimestamp() - time();
return $dateTime->getTimestamp() - $time;
}

}
48 changes: 48 additions & 0 deletions tests/Fixtures/RatingListOffline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);

namespace h4kuna\Exchange\Fixtures;

use DateTimeImmutable;
use h4kuna\Exchange\Currency\Property;
use h4kuna\Exchange\RatingList\CacheEntity;
use h4kuna\Exchange\RatingList\RatingListInterface;

final class RatingListOffline implements RatingListInterface
{
/** @var array<string, Property> */
private array $properties;


public function __construct(array $properties = null)
{
$this->properties = $properties ?? [
'CZK' => new Property(1,1, 'CZK'),
'EUR' => new Property(1,22, 'EUR', 25, 20),
];
}


public function modify(CacheEntity $cacheEntity): RatingListInterface
{
return $this;
}


public function get(string $code): Property
{
return $this->properties[$code];
}


public function all(): array
{
return array_keys($this->properties);
}


public function getDate(): DateTimeImmutable
{
return new DateTimeImmutable();
}

}
90 changes: 90 additions & 0 deletions tests/src/Currency/PropertyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php declare(strict_types=1);

namespace h4kuna\Exchange\Tests\Currency;

use Closure;
use h4kuna\Exchange\Currency\Property;
use Tester\Assert;
use Tester\TestCase;

require_once __DIR__ . '/../../bootstrap.php';

/**
* @testCase
*/
final class PropertyTest extends TestCase
{
/**
* @return array<string|int, array{0: Closure(static):void}>
*/
public function data(): array
{
return [
[
function (self $self) {
$self->assert(
property: new Property(10, 23.0, 'EUR'),
rate: 2.3,
rateSell: 2.3,
rateBuy: 2.3,
);
},
],
[
function (self $self) {
$self->assert(
property: new Property(0, 23.0, 'EUR'),
rate: 0.0,
rateSell: 0.0,
rateBuy: 0.0,
);
},
],
[
function (self $self) {
$self->assert(
property: new Property(0, 23.0, 'EUR', 23.1, 22.9),
rate: 0.0,
rateSell: 0.0,
rateBuy: 0.0,
);
},
],
[
function (self $self) {
$self->assert(
property: new Property(10, 23.0, 'EUR', 23.1, 22.9),
rate: 2.3,
rateSell: 2.31,
rateBuy: 2.29,
);
},
],
];
}


/**
* @param Closure(static):void $assert
* @dataProvider data
*/
public function testBasic(Closure $assert): void
{
$assert($this);
}


public function assert(
Property $property,
float $rate,
float $rateSell,
float $rateBuy,
): void
{
Assert::same($rate, $property->rate);
Assert::same($rateSell, $property->rateSell);
Assert::same($rateBuy, $property->rateBuy);
}
}

(new PropertyTest())->run();
12 changes: 11 additions & 1 deletion tests/src/ExchangeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
$exchange2 = $exchange->modify(null, null, new Exchange\RatingList\CacheEntity(new \DateTime('2022-12-01'), Driver\Cnb\Day::class));
Assert::same(24.0, $exchange2['EUR']->rate);

Assert::exception(static function() use ($exchange) {
Assert::exception(static function () use ($exchange) {
$exchange->modify(cacheEntity: new Exchange\RatingList\CacheEntity(new \DateTime('2022-12-02'), Driver\Cnb\Day::class));
}, ClientExceptionInterface::class);

Expand All @@ -59,3 +59,13 @@
Exchange\Fixtures\HttpFactory::$exception = true;
$exchange4 = $exchange->modify(cacheEntity: new Exchange\RatingList\CacheEntity(null, Driver\Cnb\Day::class));
Assert::same(25.0, $exchange4['EUR']->rate);

// Rate
$exchangeRate = new Exchange\Exchange('CZK', new Exchange\Fixtures\RatingListOffline(), 'EUR');
Assert::same(5.0, $exchangeRate->change(110));

$exchangeRateBuy = $exchangeRate->modify(rate: Rate::Buy);
Assert::same(5.5, $exchangeRateBuy->change(110));

$exchangeRateSell = $exchangeRate->modify(rate: Rate::Sell);
Assert::same(4.4, $exchangeRateSell->change(110));

0 comments on commit e9daa0a

Please sign in to comment.