From 1dcd9eb698388cc21d11cc80f848bc30dba27310 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Mon, 3 Aug 2020 16:46:14 +0200 Subject: [PATCH] Use a CacheIterator iterator. --- spec/loophp/collection/CollectionSpec.php | 91 +++++----------------- src/Iterator/CacheIterator.php | 93 +++++++++++++++++++++++ src/Iterator/ClosureIterator.php | 4 +- src/Operation/Cache.php | 40 +--------- 4 files changed, 115 insertions(+), 113 deletions(-) create mode 100644 src/Iterator/CacheIterator.php diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index 212a14283..0a0eb56e4 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -17,8 +17,6 @@ use loophp\collection\Operation\AbstractOperation; use OutOfRangeException; use PhpSpec\ObjectBehavior; -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; use stdClass; class CollectionSpec extends ObjectBehavior @@ -226,86 +224,31 @@ public function it_can_be_returned_as_an_array(): void ->shouldIterateAs(['1', '2', '3']); } - public function it_can_cache(CacheItemPoolInterface $cache, CacheItemInterface $cacheItemFound0, CacheItemInterface $cacheItemNotFound1, CacheItemInterface $cacheItemNotFound2, CacheItemInterface $cacheItemNotFound3): void + public function it_can_cache(): void { $fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb'); - $cache - ->getItem('1') - ->shouldBeCalledOnce(); - $cache - ->getItem('2') - ->shouldBeCalledOnce(); - $cache - ->getItem('3') - ->shouldBeCalledOnce(); - - $cache - ->getItem('0') - ->willReturn($cacheItemFound0); - - $cache - ->getItem('1') - ->willReturn($cacheItemNotFound1); - - $cache - ->getItem('2') - ->willReturn($cacheItemNotFound2); - - $cache - ->getItem('3') - ->willReturn($cacheItemNotFound3); - - $cacheItemFound0 - ->isHit() - ->willReturn(true); - - $cacheItemNotFound1 - ->isHit() - ->willReturn(false); - - $cacheItemNotFound2 - ->isHit() - ->willReturn(false); - - $cacheItemNotFound3 - ->isHit() - ->willReturn(false); - - $cacheItemNotFound1 - ->set([1, 'b']) - ->shouldBeCalledOnce(); - - $cacheItemNotFound2 - ->set([2, 'c']) - ->shouldBeCalledOnce(); - - $cache - ->save($cacheItemNotFound1) - ->shouldBeCalledOnce(); - - $cacheItemFound0 - ->get() - ->willReturn([0, 'a']); - - $cache - ->save($cacheItemNotFound1) - ->shouldBeCalled(); + $this::fromResource($fhandle) + ->window(2) + ->shouldIterateAs([ + [], + ]); - $cacheItemNotFound1 - ->get() - ->willReturn([1, 'b']); + $fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb'); - $cache - ->save($cacheItemNotFound2) - ->shouldBeCalled(); + $this::fromResource($fhandle) + ->cache() + ->window(2) + ->shouldIterateAs([ + [0 => 'a', 1 => 'b'], + [1 => 'b', 2 => 'c'], + [2 => 'c'], + ]); - $cacheItemNotFound2 - ->get() - ->willReturn([2, 'c']); + $fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb'); $this::fromResource($fhandle) - ->cache($cache) + ->cache() ->shouldIterateAs(['a', 'b', 'c']); $fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb'); diff --git a/src/Iterator/CacheIterator.php b/src/Iterator/CacheIterator.php new file mode 100644 index 000000000..70a607609 --- /dev/null +++ b/src/Iterator/CacheIterator.php @@ -0,0 +1,93 @@ + + */ +final class CacheIterator implements Iterator +{ + /** + * @var CacheItemPoolInterface + */ + private $cache; + + /** + * @var Iterator + * @psalm-var Iterator + */ + private $inner; + + /** + * @var int + */ + private $key; + + /** + * @psalm-param \Iterator $iterator + */ + public function __construct(Iterator $iterator, CacheItemPoolInterface $cache) + { + $this->inner = $iterator; + $this->cache = $cache; + $this->key = 0; + } + + /** + * @psalm-return T + */ + public function current() + { + return $this->getItemOrSave((string) $this->key)->get()[1]; + } + + /** + * @psalm-return TKey + */ + public function key() + { + return $this->getItemOrSave((string) $this->key)->get()[0]; + } + + public function next(): void + { + ++$this->key; + $this->inner->next(); + } + + public function rewind(): void + { + $this->key = 0; + } + + public function valid(): bool + { + return $this->cache->hasItem((string) $this->key) || $this->inner->valid(); + } + + private function getItemOrSave(string $key): CacheItemInterface + { + $item = $this->cache->getItem($key); + + if (false === $item->isHit()) { + $item->set([ + $this->inner->key(), + $this->inner->current(), + ]); + + $this->cache->save($item); + } + + return $item; + } +} diff --git a/src/Iterator/ClosureIterator.php b/src/Iterator/ClosureIterator.php index 8cec356a5..25189aff3 100644 --- a/src/Iterator/ClosureIterator.php +++ b/src/Iterator/ClosureIterator.php @@ -26,7 +26,7 @@ final class ClosureIterator extends ProxyIterator implements Iterator, OuterIter /** * @var callable - * @psalm-var callable(T...):(Generator) + * @psalm-var callable(mixed...):(Generator) */ private $callable; @@ -39,7 +39,7 @@ final class ClosureIterator extends ProxyIterator implements Iterator, OuterIter /** * @param mixed ...$arguments * @psalm-param T ...$arguments - * @psalm-param callable(T...):(Generator) $callable + * @psalm-param callable(mixed...):(Generator) $callable */ public function __construct(callable $callable, ...$arguments) { diff --git a/src/Operation/Cache.php b/src/Operation/Cache.php index e3fecefd6..9de86fb7d 100644 --- a/src/Operation/Cache.php +++ b/src/Operation/Cache.php @@ -8,6 +8,7 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; +use loophp\collection\Iterator\CacheIterator; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -25,49 +26,14 @@ public function __construct(?CacheItemPoolInterface $cache = null) public function __invoke(): Closure { - $iteratorIndex = 0; - return /** * @psalm-param \Iterator $iterator * * @psalm-return \Generator */ - static function (Iterator $iterator, CacheItemPoolInterface $cache) use (&$iteratorIndex): Generator { - for ($index = 0; true; ++$index) { - $item = $cache->getItem((string) $index); - - if ($item->isHit()) { - /** @psalm-var array{TKey, T} $value */ - $value = $item->get(); - - yield $value[0] => $value[1]; - - continue; - } - - if ($iteratorIndex < $index) { - $iterator->next(); - - ++$iteratorIndex; - } - - if (!$iterator->valid()) { - break; - } - - $item->set([ - $iterator->key(), - $iterator->current(), - ]); - - $cache->save($item); - - /** @psalm-var array{TKey, T} $value */ - $value = $item->get(); - - yield $value[0] => $value[1]; - } + static function (Iterator $iterator, CacheItemPoolInterface $cache): Generator { + return yield from new CacheIterator($iterator, $cache); }; } }