```
<?php
namespace src\Integration;
use src\Integlration\APIException;
class DataProvider
{
/**
* @var string
*/
private $host;
/**
* @var string
*/
private $user;
/**
* @var string
*/
private $password;
/**
* @param string $host
* @param string $user
* @param string $password
*/
public function __construct($host, $user, $password)
{
$this->host = $host;
$this->user = $user;
$this->password = $password;
}
/**
* @param array $request
* @return array
* @throws APIException
*/
public function get(array $request)
{
// returns a response from external service
}
}
```
```
<?php
namespace src\Data;
use Exception;
use Library\HttpLibraryException;
use Psr\Log\LoggerInterface;
use src\Cache\Cache;
use src\Cache\CacheException;
use src\Integlration\APIException;
use src\Integration\DataProvider;
class DataManager
{
/**
* @var DataProvider
*/
private $dataProvider;
/**
* @var Cache
*/
private $cache;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @param DataProvider $dataProvider
* @param Cache $cache
* @param LoggerInterface $logger
*/
public function __construct(DataProvider $dataProvider, Cache $cache, LoggerInterface $logger)
{
$this->dataProvider = $dataProvider;
$this->cache = $cache;
$this->logger = $logger;
}
/**
* @param array $input
* @return array
* @throws CacheException
*/
public function getResponse(array $input)
{
$result = null;
$cacheKey = $this->cache->getCacheKey(json_encode($input));
try {
$result = $this->dataProvider->get($input);
$this->checkResult($result);
$this->cache->set($cacheKey, $result);
} catch (CacheException $cacheException) {
$this->logger->critical(
$cacheException->getMessage(),
$this->getErrorLogContext($input, $result, $cacheException)
);
} catch (APIException | HttpLibraryException | InvalidResponseDataException | Exception $exception) {
$this->logger->error(
$exception->getMessage(),
$this->getErrorLogContext($input, $result, $exception)
);
}
if ($result === null) {
$result = $this->cache->get($cacheKey) ?: [];
}
return $result;
}
/**
* @param mixed $result
* @throws InvalidResponseDataException
*/
private function checkResult($result)
{
// check response data with some json schema and other invalid or dangerous data
if (/** not valid */) {
throw new InvalidResponseDataException(/** message which data is invalid */);
}
}
/**
* @param array $input
* @param array|null $result
* @param Exception $exception
* @return array
*/
private function getErrorLogContext($input, $result, Exception $exception)
{
$logContext = [
'request' => $input,
'response' => $result,
'exception' => $exception,
];
if ($exception instanceof APIException) {
$logContext['http_code'] = $exception->getHttpCode();
$logContext['response_body'] = $exception->getResponseBody();
}
return $logContext;
}
}
```
```
<?php
namespace src\Cache;
use DateTime;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
class Cache
{
/**
* @var CacheItemPoolInterface
*/
private $cache;
/**
* @var CacheItemInterface[]
*/
private $cacheItem = [];
public function __construct(CacheItemPoolInterface $cache)
{
$this->cache = $cache;
}
/**
* @param string $keyString
* @return string
*/
public function getCacheKey($keyString)
{
return sha1($keyString);
}
/**
* @param STRING $cacheKey
* @return string|null
* @throws CacheException
*/
public function get($cacheKey)
{
$cacheItem = $this->cache->getItem($cacheKey);
return $cacheItem->isHit() ? $cacheItem->get() : null;
}
/**
* @param string $cacheKey
* @param array $value
* @throws CacheException
*/
public function set($cacheKey, $value)
{
$cacheItem = $this->cache->getItem($cacheKey);
if (!$cacheItem->isHit() || $cacheItem->get() !== $value) {
$cacheItem
->set($value)
->expiresAt(
(new DateTime())->modify('+1 day')
);
}
}
}
```
```
<?php
namespace src\Cache;
class CacheException extends \Exception
{
}
```
```
<?php
namespace src\Integlration;
use Throwable;
class APIException extends \Exception
{
/**
* @var int
*/
private $httpCode;
/**
* @var string
*/
private $responseBody;
public function __construct($message = "", $httpCode = 500, $responseBody = '', $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->httpCode = $httpCode;
$this->responseBody = $responseBody;
}
/**
* @return int
*/
public function getHttpCode()
{
return $this->httpCode;
}
/**
* @return string
*/
public function getResponseBody()
{
return $this->responseBody;
}
}
```
```
<?php
namespace src\Data;
class InvalidResponseDataException extends \Exception
{
}
```