BucketStream::isReadable()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace roxblnfk\SmartStream\Stream;
6
7
use Psr\Http\Message\StreamInterface;
8
use roxblnfk\SmartStream\ConverterInterface;
9
use roxblnfk\SmartStream\ConverterMatcherInterface;
10
use roxblnfk\SmartStream\Data\DataBucket;
11
use roxblnfk\SmartStream\Exception\ConverterNotFoundException;
12
use roxblnfk\SmartStream\Matching\MatchingResult;
13
use RuntimeException;
14
15
final class BucketStream implements StreamInterface
16
{
17
    private ConverterMatcherInterface $converterMatcher;
18
    private ?DataBucket $bucket;
19
    private ?GeneratorStream $stream = null;
20
    private ?MatchingResult $matchedResult = null;
21
22 98
    public function __construct(ConverterMatcherInterface $converterMatcher, DataBucket $bucket)
23
    {
24 98
        $this->bucket = $bucket;
25 98
        $this->converterMatcher = $converterMatcher;
26
27 98
        if ($bucket->isConvertable()) {
28 94
            $result = $this->converterMatcher->match($this->bucket);
29
            // if should be converted but no converter was found
30 94
            if ($result === null && $bucket->hasFormat()) {
31 1
                throw new ConverterNotFoundException($bucket->getFormat());
32
            }
33 93
            $this->matchedResult = $result;
34
        }
35 97
    }
36 4
    public function __toString(): string
37
    {
38
        try {
39 4
            return $this->getContents();
40 3
        } catch (\Exception $e) {
41 3
            return '';
42
        }
43
    }
44 2
    public function close(): void
45
    {
46 2
        $this->detach();
47 2
    }
48 19
    public function detach()
49
    {
50 19
        $this->matchedResult = null;
51 19
        $this->stream = null;
52 19
        $this->bucket = null;
53 19
        return null;
54
    }
55 9
    public function getSize(): ?int
56
    {
57 9
        return $this->stream === null ? null : $this->stream->getSize();
58
    }
59 7
    public function tell(): int
60
    {
61 7
        return $this->stream === null ? 0 : $this->stream->tell();
62
    }
63 20
    public function eof(): bool
64
    {
65 20
        if ($this->bucket === null) {
66 6
            return true;
67
        }
68 14
        return $this->stream === null ? false : $this->stream->eof();
69
    }
70 6
    public function isSeekable(): bool
71
    {
72 6
        return false;
73
    }
74 2
    public function seek($offset, $whence = \SEEK_SET): void
75
    {
76 2
        throw new RuntimeException('Stream is not seekable.');
77
    }
78 3
    public function rewind(): void
79
    {
80 3
        if ($this->stream !== null) {
81 1
            $this->stream->rewind();
82
        }
83 3
    }
84 2
    public function isWritable(): bool
85
    {
86 2
        return false;
87
    }
88 2
    public function write($string): int
89
    {
90 2
        throw new RuntimeException('Cannot write to a non-writable stream.');
91
    }
92 28
    public function isReadable(): bool
93
    {
94 28
        return $this->initConverter() ? $this->stream->isReadable() : false;
0 ignored issues
show
Bug introduced by
The method isReadable() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        return $this->initConverter() ? $this->stream->/** @scrutinizer ignore-call */ isReadable() : false;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
95
    }
96 13
    public function read($length): string
97
    {
98 13
        if (!$this->isReadable()) {
99 5
            throw new RuntimeException('Stream should be rendered.');
100
        }
101
        # read generator stream
102 8
        return $this->stream->read($length);
103
    }
104 12
    public function getContents(): string
105
    {
106 12
        if ($this->bucket === null) {
107 4
            throw new RuntimeException('Unable to read stream contents.');
108
        }
109 8
        $content = '';
110 8
        while (!$this->eof()) {
111 8
            $content .= $this->read(PHP_INT_MAX);
112
        }
113 6
        return $content;
114
    }
115 8
    public function getMetadata($key = null)
116
    {
117 8
        if ($this->bucket === null) {
118 4
            return $key ? null : [];
119
        }
120
121
        $meta = [
122 4
            'seekable' => $this->isSeekable(),
123 4
            'eof' => $this->eof(),
124
        ];
125
126 4
        if (null === $key) {
127 2
            return $meta;
128
        }
129
130 2
        return $meta[$key] ?? null;
131
    }
132
133 5
    public function withBucket(DataBucket $bucket): self
134
    {
135 5
        return new static($this->converterMatcher, $bucket);
136
    }
137
138 7
    public function hasConverter(): bool
139
    {
140 7
        return $this->matchedResult !== null;
141
    }
142 2
    public function getConverter(): ?ConverterInterface
143
    {
144 2
        return $this->matchedResult === null ? null : $this->matchedResult->getConverter();
145
    }
146
147 6
    public function hasBucketFormat(): bool
148
    {
149 6
        return $this->bucket === null ? false : $this->bucket->hasFormat();
150
    }
151 7
    public function getBucketFormat(): ?string
152
    {
153 7
        return $this->bucket === null ? null : $this->bucket->getFormat();
154
    }
155
156 2
    public function hasMatchedFormat(): bool
157
    {
158 2
        return $this->matchedResult !== null;
159
    }
160 2
    public function getMatchedFormat(): ?string
161
    {
162 2
        return $this->matchedResult === null ? null : $this->matchedResult->getFormat();
163
    }
164
165 9
    public function isRenderStarted(): bool
166
    {
167 9
        return $this->stream !== null;
168
    }
169
170 28
    public function getBucket(): ?DataBucket
171
    {
172 28
        return $this->bucket;
173
    }
174 7
    public function getMatchedResult(): ?MatchingResult
175
    {
176 7
        return $this->matchedResult;
177
    }
178
179 28
    private function initConverter(): bool
180
    {
181 28
        if ($this->stream !== null) {
182 6
            return true;
183
        }
184 28
        if ($this->matchedResult === null || $this->bucket === null) {
185 17
            return false;
186
        }
187 11
        $this->stream = new GeneratorStream($this->matchedResult->getConverter()->convert($this->bucket));
188 11
        return true;
189
    }
190
}
191