New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Approve code review #6
Conversation
int $count, | ||
ProviderResource $resource | ||
) { | ||
parent::__construct($providerRecords, $count, $resource); |
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.
A constructor override that only calls the parent implementation is the same as having no constructor override. That is, this whole constructor can be deleted and have exactly the same effect. However, I also suggest (as previously), that this entire file should be deleted because custom collections are usually to supply metadata but this class is not adding any extra value, let alone supplying metadata.
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.
You're right. I will remove this collection record.
src/Resource/GetAllRate.php
Outdated
|
||
return new AllRatesRecord($time, $base, $quote, $rate); | ||
|
||
$rate = function () use ($rates) { |
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.
This closure seems to just copy the array into an iterator. You can replace this entire code block with new ArrayIterator($response['rates'])
.
src/Collection/AllRatesRecord.php
Outdated
{ | ||
return $this->rate; | ||
return iterator_to_array($this); |
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.
This doesn't seem to add any value, and its implementation encourages using array instead of iterators. If the client want to use arrays it can call iterator_to_array
itself, but Porter and her providers should not encourage this because it loads the entire data set into memory. In this case, since we're not streaming the response, it's already loaded into memory anyway, but it's still a bad idea to encourage this. Recommend removing this method.
src/Resource/GetSpecificRate.php
Outdated
$time = $response['time']; | ||
|
||
return new SpecificRateRecord($time, $base, $quote, $rate); | ||
$rate = function () use ($response) { |
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.
Again, this seems to be a very roundabout way of copying an array. Since we don't need the SpecificRateRecord
collection, this entire code block (lines 42-51) can be replaced with yield $response
.
tests/Functional/GetRateTest.php
Outdated
@@ -21,10 +21,13 @@ public function testGetSpecificRateRecords() | |||
$rates = FixtureFactory::createPorter()->import(new ImportSpecification(new GetSpecificRate($this->apiKey))) | |||
->findFirstCollection(); |
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.
This should not be necessary.
tests/Functional/GetRateTest.php
Outdated
$this->assertSame('USD', $rates->getQuote()); | ||
$this->assertLessThanOrEqual(time(), strtotime($rates->getTime())); | ||
$this->assertInternalType('float', $rates->getRate()); | ||
$rateRecords = $rates->toAssociativeArray(); |
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.
This should not be necessary. Use Porter::importOne()
instead of import()
.
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 think you add the wrong place for this comment.
I cannot see any code that is related to the import()
.
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.
They're both related. This line should be deleted because it is not necessary if you use importOne
.
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.
Can you give some sample code about this?
I don't understand Porter::importOne()
usage clearly.
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.
import()
returns the collection from the resource. importOne()
does the same thing, except it returns the first record from the collection instead of the collection itself (and ensures there is no more than one record in the collection).
tests/Functional/GetRateTest.php
Outdated
@@ -33,16 +36,12 @@ public function testGetAllRateRecords() | |||
$rates = FixtureFactory::createPorter()->import(new ImportSpecification(new GetAllRate($this->apiKey))) | |||
->findFirstCollection(); |
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.
findFirstCollection()
should only be used when you need to get metadata. Call it later when testing getBase()
, but do not call it here, before iteration has been tested.
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.
Can you show some example approach for this?
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.
Just call findFirstCollection()
later, after you've done all the other assertions.
tests/Functional/GetRateTest.php
Outdated
|
||
$this->assertArrayHasKey('asset_id_quote', $rateRecords[0]); | ||
$this->assertArrayHasKey('rate', $rateRecords[0]); | ||
$this->assertArrayHasKey('time', $rateRecords[0]); |
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.
This is a bad pattern for testing iterators: we should ensure the whole iterator looks and works as we expect, instead of only looking at the first record. Use foreach
to loop over each record and assert each record is correct. It's a good idea to make assertions on the data too, not just the keys. If you don't know what the data should look like, at least try a type assertion and maybe a not empty assertion if the data should be non-null.
I'm sorry but this is completely wrong. It seems you are doing your own thing instead of following my guidelines. |
src/Resource/GetSpecificRate.php
Outdated
@@ -30,7 +32,7 @@ public function getProviderClassName(): string | |||
|
|||
public function fetch(ImportConnector $connector): \Iterator | |||
{ | |||
$response = \json_decode( | |||
$response[] = \json_decode( |
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.
This is wrapping your record in an outer array, which is not correct. This should just be $response
instead of $response[]
.
src/Resource/GetSpecificRate.php
Outdated
}; | ||
|
||
return new SpecificRateRecord($rate(), count($response), $this); | ||
return yield $response; |
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.
return
does nothing here, since yield $response
has no return value. Should just be yield $response
.
tests/Functional/GetRateTest.php
Outdated
|
||
$rateRecords = $rates->toAssociativeArray(); | ||
$this->assertCount(1, $rate); |
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.
This is unnecessary because importOne
guarantees the iterator only contains one result. If it contains more it throws an exception.
tests/Functional/GetRateTest.php
Outdated
|
||
$this->assertSame('BTC', $rates->getBase()); | ||
$this->assertCount(1267, $rates); |
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.
This magic number is too brittle. The test needs to prove the count is correct without breaking whenever a rate is added or removed. You have two options, either:
- Count the number of records during iteration and ensure it matches the reported count. To do this, the assertion would have to be moved after the loop.
- Estimate the number of expected values, e.g.
self::assertGreaterThan(1200, count($rates))
.
@Bilge, I've approved the recommendations that you suggest. Thanks. |
@Bilge , this is the second code review after modifying this.