Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
50.00% |
2 / 4 |
CRAP | |
83.87% |
26 / 31 |
SampleDataSource | |
0.00% |
0 / 1 |
|
50.00% |
2 / 4 |
10.42 | |
83.87% |
26 / 31 |
__construct | |
100.00% |
1 / 1 |
3 | |
100.00% |
13 / 13 |
|||
getQuotes | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
transformResponseInQuotesCollection | |
0.00% |
0 / 1 |
3.21 | |
71.43% |
5 / 7 |
|||
fetchQuotesFromSource | |
0.00% |
0 / 1 |
3.24 | |
70.00% |
7 / 10 |
<?php | |
declare(strict_types=1); | |
namespace App\Quote\DataSource; | |
use App\Quote\Collection\QuoteCollection; | |
use App\Quote\Collection\QuoteCollectionInterface; | |
use App\Quote\DataSource\Exception\DataSourceException; | |
use App\Quote\DataSource\Exception\DataSourceIsNotReadableException; | |
use Psr\Log\LoggerInterface; | |
use Symfony\Component\Cache\Adapter\AdapterInterface; | |
use Symfony\Component\HttpClient\Exception\ClientException; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; | |
use Symfony\Contracts\HttpClient\HttpClientInterface; | |
use Symfony\Contracts\HttpClient\ResponseInterface; | |
use Webmozart\Assert\Assert; | |
final class SampleDataSource implements DataSourceInterface | |
{ | |
private const KEY = 'SampleDataSource'; | |
private HttpClientInterface $httpClient; | |
private QuoteCollectionInterface $quotes; | |
private AdapterInterface $cache; | |
private LoggerInterface $logger; | |
private string $url; | |
public function __construct( | |
HttpClientInterface $httpClient, | |
AdapterInterface $cache, | |
LoggerInterface $logger, | |
string $dataSourceUrl | |
) { | |
$this->httpClient = $httpClient; | |
$this->cache = $cache; | |
$this->url = $dataSourceUrl; | |
$this->logger = $logger; | |
$cachedItem = $this->cache->getItem(self::KEY); | |
if ($cachedItem->get() instanceof QuoteCollectionInterface) { | |
$this->quotes = $cachedItem->get(); | |
$this->logger->info('Data fetched from cache', ['DataSource' => self::KEY]); | |
} | |
if (false === $cachedItem->isHit()) { | |
$this->fetchQuotesFromSource(); | |
$cachedItem->set($this->quotes); | |
$this->cache->save($cachedItem); | |
} | |
} | |
public function getQuotes(): QuoteCollectionInterface | |
{ | |
return $this->quotes; | |
} | |
private function transformResponseInQuotesCollection(ResponseInterface $rawDataResponse): array | |
{ | |
if ($rawDataResponse->getStatusCode() !== Response::HTTP_OK) { | |
return []; | |
} | |
$data = json_decode($rawDataResponse->getContent(), true, 512, JSON_THROW_ON_ERROR); | |
if (empty($data)) { | |
return []; | |
} | |
Assert::keyExists($data, 'quotes'); | |
return $data['quotes']; | |
} | |
private function fetchQuotesFromSource(): void | |
{ | |
try { | |
$rawDataResponse = $this->httpClient->request(Request::METHOD_GET, $this->url); | |
} catch (TransportExceptionInterface | ClientException $e) { | |
throw new DataSourceException( | |
sprintf('Could not fetch quotes from %s data source', __CLASS__) | |
); | |
} | |
if ($rawDataResponse->getStatusCode() === Response::HTTP_NOT_FOUND) { | |
throw new DataSourceIsNotReadableException( | |
sprintf('The url %s provided is not readable or reachable', $this->url) | |
); | |
} | |
$this->logger->info('Raw data fetched from text collection quotes api', ['DataSource' => self::KEY]); | |
$this->quotes = QuoteCollection::fromArray($this->transformResponseInQuotesCollection($rawDataResponse)); | |
} | |
} |