# Исходные файлы ### src/DataProviderInterface.php ```php <?php namespace main; /** * Интерфейс получения данных */ interface DataProviderInterface { /** * Получить результат * * @param array $input * @return array */ function get(array $input): array; } ``` ### src/CacheDecorator.php ```php <?php namespace main; use Psr\Cache\CacheItemPoolInterface; /** * Кеширующий декоратор */ class CacheDecorator implements DataProviderInterface { /** * @var CacheItemPoolInterface */ private $cache; /** * Время кеширования в секундах * * @var int */ private $cacheTime = 3600 * 24; /** * @var DataProviderInterface */ private $dataProvider; /** * @param DataProviderInterface $dataProvider * @param CacheItemPoolInterface $cache */ public function __construct(DataProviderInterface $dataProvider, CacheItemPoolInterface $cache) { $this->dataProvider = $dataProvider; $this->cache = $cache; } /** * Время кеширования в секундах * * @return int */ public function getCacheTime(): int { return $this->cacheTime; } /** * Установить время кеширования в секундах * * @param int $cacheTime */ public function setCacheTime(int $cacheTime): void { $this->cacheTime = $cacheTime; } /** * Получить результат * * @param array $input * @return array * @throws \Psr\Cache\InvalidArgumentException */ public function get(array $input): array { $cacheKey = $this->getCacheKey($input); $cacheItem = $this->cache->getItem($cacheKey); if ($cacheItem->isHit()) { return $cacheItem->get(); } $result = $this->dataProvider->get($input); $cacheItem ->set($result) ->expiresAt( (new \DateTime())->add(new \DateInterval("PT{$this->cacheTime}S")) ); $this->cache->save($cacheItem); return $result; } /** * Получить ключ кеширования по входящему запросу * * @param array $input * @return string */ private function getCacheKey(array $input): string { return md5(serialize($input)); } } ``` ### src/LoggerDecorator.php ```php <?php namespace main; use Psr\Log\LoggerInterface; /** * Логгирующий декоратор */ class LoggerDecorator implements DataProviderInterface { /** * @var DataProviderInterface */ private $dataProvider; /** * @var LoggerInterface */ private $logger; /** * @param DataProviderInterface $dataProvider * @param LoggerInterface $logger */ public function __construct(DataProviderInterface $dataProvider, LoggerInterface $logger) { $this->dataProvider = $dataProvider; $this->logger = $logger; } /** * Получить результат * * @param array $input * @return array */ public function get(array $input): array { try { return $this->dataProvider->get($input); } catch (\Exception $ex) { $this->logger->error($ex->getMessage()); return []; } } } ``` # Тесты ### tests/CacheDecoratorTest.php ```php <?php namespace tests; use main\CacheDecorator; use PHPUnit\Framework\TestCase; class CacheDecoratorTest extends TestCase { public function testCacheMissResult() { $args = ['some']; $result = ['result']; $mockProvider = $this->createMock('main\DataProviderInterface'); $mockProvider->method('get')->with($args)->willReturn($result); $mockCacheItem = $this->createMock('\Psr\Cache\CacheItemInterface'); $mockCacheItem->method('isHit')->willReturn(false); $mockCacheItem->method('expiresAt')->willReturnCallback(function ($arg) { $this->assertEquals((new \DateTime())->modify('+1 minute'), $arg, '', 1e-4); }); $mockCacheItem->method('set')->with($result)->willReturnSelf(); $mockCache = $this->createMock('\Psr\Cache\CacheItemPoolInterface'); $mockCache->method('getItem')->willReturn($mockCacheItem); $mockCache->expects($this->once())->method('save')->with($mockCacheItem); $testProvider = new CacheDecorator($mockProvider, $mockCache); $testProvider->setCacheTime(60); $this->assertEquals($result, $testProvider->get($args)); } public function testCacheHitResult() { $args = ['some']; $result = ['result']; $mockProvider = $this->createMock('main\DataProviderInterface'); $mockProvider->expects($this->never())->method('get'); $mockCacheItem = $this->createMock('\Psr\Cache\CacheItemInterface'); $mockCacheItem->method('isHit')->willReturn(true); $mockCacheItem->method('get')->willReturn($result); $mockCache = $this->createMock('\Psr\Cache\CacheItemPoolInterface'); $mockCache->method('getItem')->willReturn($mockCacheItem); $testProvider = new CacheDecorator($mockProvider, $mockCache); $this->assertEquals($result, $testProvider->get($args)); } } ``` ### tests/LoggerDecoratorTest.php ```php <? namespace tests; use main\LoggerDecorator; use PHPUnit\Framework\TestCase; class LoggerDecoratorTest extends TestCase { public function testDataProviderException() { $mockLogger = $this->createMock('Psr\Log\LoggerInterface'); $mockLogger->expects($this->once())->method('error'); $mockProvider = $this->createMock('main\DataProviderInterface'); $mockProvider->method('get')->willThrowException(new \Exception()); $testDecorator = new LoggerDecorator($mockProvider, $mockLogger); $this->assertEquals([], $testDecorator->get(['any-args'])); } } ```