From 097e80ec96817695adf52763993cfb87dfc48347 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 19 Jun 2023 14:48:46 +0200 Subject: [PATCH] [LazyStreamWriter] Add open mode, auto close and exceptions --- .../AbstractLazyStreamWriterException.php | 7 +++ .../LazyStreamWriterOpenException.php | 11 ++++ .../LazyStreamWriterTriggerException.php | 7 +++ src/LazyStreamWriter.php | 49 ++++++++++++++--- tests/LazyStreamWriterTest.php | 54 ++++++++++++++++++- 5 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 src/Exception/AbstractLazyStreamWriterException.php create mode 100644 src/Exception/LazyStreamWriterOpenException.php create mode 100644 src/Exception/LazyStreamWriterTriggerException.php diff --git a/src/Exception/AbstractLazyStreamWriterException.php b/src/Exception/AbstractLazyStreamWriterException.php new file mode 100644 index 0000000..a1a51ea --- /dev/null +++ b/src/Exception/AbstractLazyStreamWriterException.php @@ -0,0 +1,7 @@ +handle)) { - \fflush($this->handle); - \fclose($this->handle); } } @@ -39,15 +48,29 @@ public function __destruct() public function trigger(): void { if (!\is_resource($this->handle)) { - $this->handle = \fopen($this->uri, 'w'); + $this->handle = @\fopen($this->uri, $this->openMode); + + if ($this->handle === false) { + throw new LazyStreamWriterOpenException($this->uri, $this->openMode); + } } - while ($this->dataProvider->valid()) { - $data = $this->dataProvider->current(); + try { + while ($this->dataProvider->valid()) { + $data = $this->dataProvider->current(); + + \fwrite($this->handle, $data, \strlen($data)); - \fwrite($this->handle, $data, \strlen($data)); + $this->dataProvider->next(); + } + } catch (\Throwable $throwable) { + throw new LazyStreamWriterTriggerException(previous: $throwable); + } finally { + if (\is_resource($this->handle) && $this->autoClose) { + \fclose($this->handle); - $this->dataProvider->next(); + $this->handle = null; + } } } @@ -74,4 +97,14 @@ public function equals(self $other): bool { return $this->dataProvider === $other->dataProvider && $this->uri === $other->uri; } + + public function isAutoClose(): bool + { + return $this->autoClose; + } + + public function setAutoClose(bool $autoClose): void + { + $this->autoClose = $autoClose; + } } diff --git a/tests/LazyStreamWriterTest.php b/tests/LazyStreamWriterTest.php index 5de1159..98c91d8 100644 --- a/tests/LazyStreamWriterTest.php +++ b/tests/LazyStreamWriterTest.php @@ -9,8 +9,11 @@ namespace LazyStream\Tests; +use LazyStream\Exception\LazyStreamWriterOpenException; +use LazyStream\Exception\LazyStreamWriterTriggerException; use LazyStream\LazyStreamWriter; use PHPUnit\Framework\TestCase; +use Traversable; /** * @covers \LazyStream\LazyStreamWriter @@ -60,7 +63,7 @@ public function testTriggerStreams(): void yield 'chunk'; return 'return_value'; - })()); + })(), autoClose: false); $lazyStream->trigger(); $handle = $lazyStream->getStreamHandle(); @@ -72,4 +75,53 @@ public function testTriggerStreams(): void // Generator should be closed $this->assertFalse($generator->valid()); } + + public function testInvalidStream(): void + { + $lazyStream = new LazyStreamWriter('php://invalid', new \ArrayIterator([])); + + $this->expectException(LazyStreamWriterOpenException::class); + $this->expectExceptionMessage('Unable to open "php://invalid" with mode "w".'); + $lazyStream->trigger(); + } + + public function testTriggersThrowsOnUnwrappingWithAutoClose(): void + { + $expectedException = new \Exception(); + + $lazyStream = new LazyStreamWriter('php://memory', (static function () use ($expectedException): \Generator { + yield 'data'; + + throw $expectedException; + })()); + + $this->expectExceptionObject(new LazyStreamWriterTriggerException(previous: $expectedException)); + try { + $lazyStream->trigger(); + } catch (\Exception $exception) { + $this->assertNull($lazyStream->getStreamHandle()); + + throw $exception; + } + } + + public function testTriggersThrowsOnUnwrappingWithoutAutoClose(): void + { + $expectedException = new \Exception(); + + $lazyStream = new LazyStreamWriter('php://memory', (static function () use ($expectedException): \Generator { + yield 'data'; + + throw $expectedException; + })(), autoClose: false); + + $this->expectExceptionObject(new LazyStreamWriterTriggerException(previous: $expectedException)); + try { + $lazyStream->trigger(); + } catch (\Exception $exception) { + $this->assertNotNull($lazyStream->getStreamHandle()); + + throw $exception; + } + } }