-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Collection; | ||
|
||
use ScriptFUSION\Porter\Collection\CountableProviderRecords; | ||
use ScriptFUSION\Porter\Provider\Resource\ProviderResource; | ||
|
||
class AllRatesRecord extends CountableProviderRecords | ||
{ | ||
private $base; | ||
|
||
private $time; | ||
|
||
private $quote; | ||
|
||
private $rate; | ||
|
||
public function __construct(array $time, string $base, array $quote, array $rate) | ||
This comment has been minimized.
Sorry, something went wrong. |
||
{ | ||
$this->base = $base; | ||
$this->time = $time; | ||
$this->quote = $quote; | ||
$this->rate = $rate; | ||
} | ||
|
||
public function getBase(): string | ||
{ | ||
return $this->base; | ||
} | ||
|
||
public function getTime(): array | ||
{ | ||
return $this->time; | ||
} | ||
|
||
public function getQuote(): array | ||
{ | ||
return $this->quote; | ||
} | ||
|
||
public function getRate(): array | ||
{ | ||
return $this->rate; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Collection; | ||
|
||
use ScriptFUSION\Porter\Collection\CountableProviderRecords; | ||
use ScriptFUSION\Porter\Provider\Resource\ProviderResource; | ||
|
||
class SpecificRateRecord extends CountableProviderRecords | ||
{ | ||
private $base; | ||
|
||
private $time; | ||
|
||
private $quote; | ||
|
||
private $rate; | ||
|
||
public function __construct(string $time, string $base, string $quote, float $rate) | ||
{ | ||
$this->base = $base; | ||
$this->time = $time; | ||
$this->quote = $quote; | ||
$this->rate = $rate; | ||
} | ||
|
||
public function getBase(): string | ||
{ | ||
return $this->base; | ||
} | ||
|
||
public function getTime(): string | ||
{ | ||
return $this->time; | ||
} | ||
|
||
public function getQuote(): string | ||
{ | ||
return $this->quote; | ||
} | ||
|
||
public function getRate(): float | ||
{ | ||
return $this->rate; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Connector; | ||
|
||
use ScriptFUSION\Porter\Net\Http\HttpConnector; | ||
use ScriptFUSION\Porter\Net\Http\HttpOptions; | ||
|
||
class CryptoConnector extends HttpConnector | ||
{ | ||
private $options; | ||
|
||
public function __construct(string $apiKey) | ||
{ | ||
$buildHeader = sprintf("X-CoinAPI-Key: %s", $apiKey); | ||
|
||
parent::__construct($this->options = (new HttpOptions)->addHeader($buildHeader)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto; | ||
|
||
use ScriptFUSION\Porter\Connector\Connector; | ||
use ScriptFUSION\Porter\Provider\Provider; | ||
|
||
class CryptoMonitor implements Provider | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
{ | ||
public const EXCHANGE_API_ENDPOINT = 'https://rest.coinapi.io/'; | ||
|
||
private $connector; | ||
|
||
public function __construct(Connector $connector) | ||
{ | ||
$this->connector = $connector; | ||
} | ||
|
||
public static function buildExchangeApiUrl(string $url): string | ||
{ | ||
return self::EXCHANGE_API_ENDPOINT . $url; | ||
} | ||
|
||
public function getConnector(): Connector | ||
{ | ||
return $this->connector; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Resource; | ||
|
||
use PayCrypto\CryptoMonitor; | ||
use PayCrypto\Collection\AllRatesRecord; | ||
use ScriptFUSION\Porter\Connector\ImportConnector; | ||
use ScriptFUSION\Porter\Provider\Patreon\Collection\PledgeRecords; | ||
use ScriptFUSION\Porter\Provider\Patreon\PatreonProvider; | ||
use ScriptFUSION\Porter\Provider\Resource\ProviderResource; | ||
|
||
class GetAllRate implements ProviderResource | ||
{ | ||
private $apiKey; | ||
|
||
public $base = 'BTC'; | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
|
||
public function __construct(string $apiKey) | ||
{ | ||
$this->apiKey = $apiKey; | ||
} | ||
|
||
public function getProviderClassName(): string | ||
{ | ||
return CryptoMonitor::class; | ||
} | ||
|
||
public function fetch(ImportConnector $connector): \Iterator | ||
{ | ||
$response = \json_decode( | ||
(string) $connector->fetch( | ||
CryptoMonitor::buildExchangeApiUrl( | ||
sprintf("v1/exchangerate/%s", $this->base) | ||
) | ||
), | ||
true | ||
); | ||
|
||
$rates = $response['rates']; | ||
$base = $response['asset_id_base']; | ||
$quote = []; | ||
$rate = []; | ||
$time = []; | ||
|
||
foreach($rates as $key => $value) { | ||
$quote[] = $rates[$key]['asset_id_quote']; | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
$rate[] = $rates[$key]['rate']; | ||
$time[] = $rates[$key]['time']; | ||
} | ||
|
||
return new AllRatesRecord($time, $base, $quote, $rate); | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Resource; | ||
|
||
use PayCrypto\CryptoMonitor; | ||
use PayCrypto\Collection\SpecificRateRecord; | ||
use ScriptFUSION\Porter\Connector\ImportConnector; | ||
use ScriptFUSION\Porter\Provider\Patreon\Collection\PledgeRecords; | ||
use ScriptFUSION\Porter\Provider\Patreon\PatreonProvider; | ||
use ScriptFUSION\Porter\Provider\Resource\ProviderResource; | ||
|
||
class GetSpecificRate implements ProviderResource | ||
{ | ||
private $apiKey; | ||
|
||
public $base = 'BTC'; | ||
|
||
public $quote = 'USD'; | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
|
||
public function __construct(string $apiKey) | ||
{ | ||
$this->apiKey = $apiKey; | ||
} | ||
|
||
public function getProviderClassName(): string | ||
{ | ||
return CryptoMonitor::class; | ||
} | ||
|
||
public function fetch(ImportConnector $connector): \Iterator | ||
{ | ||
$response = \json_decode( | ||
(string) $connector->fetch( | ||
CryptoMonitor::buildExchangeApiUrl( | ||
sprintf("v1/exchangerate/%s/%s", $this->base, $this->quote) | ||
) | ||
), | ||
true | ||
); | ||
|
||
$base = $response['asset_id_base']; | ||
|
||
$quote = $response['asset_id_quote']; | ||
$rate = $response['rate']; | ||
$time = $response['time']; | ||
|
||
return new SpecificRateRecord($time, $base, $quote, $rate); | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
namespace PayCrypto\Tests; | ||
|
||
use Psr\Container\ContainerInterface; | ||
use ScriptFUSION\Porter\Porter; | ||
use PayCrypto\Connector\CryptoConnector; | ||
use PayCrypto\CryptoMonitor; | ||
use ScriptFUSION\StaticClass; | ||
|
||
final class FixtureFactory | ||
{ | ||
use StaticClass; | ||
|
||
public static function createPorter(): Porter | ||
{ | ||
return new Porter( | ||
\Mockery::mock(ContainerInterface::class) | ||
->shouldReceive('has') | ||
->with(CryptoMonitor::class) | ||
->andReturn(true) | ||
->shouldReceive('get') | ||
->with(CryptoMonitor::class) | ||
->andReturn(new CryptoMonitor(new CryptoConnector('4E861687-19D6-4894-87B9-E785B1EE3900'))) | ||
->getMock() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace PayCrypto\Tests; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use PayCrypto\Resource\GetSpecificRate; | ||
use PayCrypto\Resource\GetAllRate; | ||
use PayCrypto\Collection\SpecificRateRecord; | ||
use PayCrypto\Collection\AllRatesRecord; | ||
use ScriptFUSION\Porter\Specification\ImportSpecification; | ||
|
||
final class GetRateTest extends TestCase | ||
{ | ||
/** @var $apiKey This is the Coin API Key for test environment*/ | ||
private $apiKey = '4E861687-19D6-4894-87B9-E785B1EE3900'; | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
|
||
public function testGetSpecificRateRecords() | ||
{ | ||
/** @var SpecificRateRecord $rates */ | ||
$rates = FixtureFactory::createPorter()->import(new ImportSpecification(new GetSpecificRate($this->apiKey))) | ||
->findFirstCollection(); | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
|
||
$this->assertSame('BTC', $rates->getBase()); | ||
$this->assertSame('USD', $rates->getQuote()); | ||
$this->assertLessThanOrEqual(time(), strtotime($rates->getTime())); | ||
$this->assertInternalType('float', $rates->getRate()); | ||
} | ||
|
||
public function testGetAllRateRecords() | ||
{ | ||
/** @var AllRatesRecord $rates */ | ||
$rates = FixtureFactory::createPorter()->import(new ImportSpecification(new GetAllRate($this->apiKey))) | ||
->findFirstCollection(); | ||
This comment has been minimized.
Sorry, something went wrong.
Bilge
|
||
|
||
$base = $rates->getBase(); | ||
$quote = $rates->getQuote(); | ||
$time = $rates->getTime(); | ||
$rate = $rates->getRate(); | ||
|
||
$this->assertSame('BTC', $base); | ||
$this->assertContains('USD', $quote); | ||
$this->assertContains('GBP', $quote); | ||
$this->assertContains('EUR', $quote); | ||
$this->assertLessThanOrEqual(time(), strtotime($time[0])); | ||
$this->assertInternalType('float', $rate[0]); | ||
} | ||
} |
5 comments
on commit 4246a99
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest problem here is that the iterator contract has been broken: resources are required to return a functional iterator, but a fake iterator is being returned from these resources. This has been done by extending an iterator and then treating it as a regular object. This means Porter::import
also returns a fake iterator that cannot be iterated and Porter::importOne
will break. However, you are avoiding encountering these issues by calling findFirstCollection
on the false iterator instead of Porter::importOne
and then using object methods.
I understand you probably got this idea from looking at the source for the European Central Bank provider. Whilst you can create custom record collection and you can attach additional data to it, this is the metadata pattern, and it's usually wrong to have a collection that is only metadata. This data should be exposed as an array returned from the iterator instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've finished the review. There's some important changes to make. I'll take another look once you've addressed the issues. Let me know if you have any questions. Please submit any further changes in a separate PR branch, instead of committing to master
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Bilge, thank you for your reply.
And I almost have done this request changes.
Please see the latest commit and write the comments if having any issues.
I appreciated your work again!
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot review commits because they lack context. Please make a PR instead of committing to master.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it's my fault.
Please take a look at this PR and do code review.
Thanks.
This is invalid because it does not call the parent's constructor. It seems to me this custom collection class is not needed at all. Instead, just return the data as an array from the iterator. Recommend deleting this file and
SpecificRateRecord
, too.