Passed
Push — master ( 4f4dd1...f4eddc )
by Aleksei
14:21
created

BucketStream::getMatchedFormat()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 6
rs 10
c 0
b 0
f 0
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
14
final class BucketStream implements StreamInterface
15
{
16
    private ConverterMatcherInterface $converterMatcher;
17
    private ?DataBucket $bucket;
18
    private ?GeneratorStream $stream = null;
19
    private ?MatchingResult $matchedResult = null;
20
21
    public function __construct(ConverterMatcherInterface $converterMatcher, DataBucket $bucket)
22
    {
23
        $this->bucket = $bucket;
24
        $this->converterMatcher = $converterMatcher;
25
26
        // if should be converted
27
        if ($bucket->isConvertable()) {
28
            $result = $this->converterMatcher->match($this->bucket);
29
            if ($result === null && $bucket->hasFormat()) {
30
                throw new ConverterNotFoundException((string)$bucket->getFormat());
31
            }
32
            $this->matchedResult = $result;
33
        }
34
    }
35
    public function __toString(): string
36
    {
37
        try {
38
            if ($this->isSeekable()) {
39
                $this->seek(0);
40
            }
41
            return $this->getContents();
42
        } catch (\Exception $e) {
43
            return '';
44
        }
45
    }
46
    public function close(): void
47
    {
48
        $this->detach();
49
    }
50
    public function detach()
51
    {
52
        $this->matchedResult = null;
53
        $this->stream = null;
54
        $this->bucket = null;
55
        return null;
56
    }
57
    public function getSize(): ?int
58
    {
59
        return $this->stream === null ? null : $this->stream->getSize();
60
    }
61
    public function tell(): int
62
    {
63
        return $this->stream === null ? 0 : $this->stream->tell();
64
    }
65
    public function eof(): bool
66
    {
67
        return $this->stream === null ? false : $this->stream->eof();
68
    }
69
    public function isSeekable(): bool
70
    {
71
        return false;
72
    }
73
    public function seek($offset, $whence = \SEEK_SET): void
74
    {
75
        throw new \RuntimeException('Stream is not seekable.');
76
    }
77
    public function rewind(): void
78
    {
79
        if ($this->stream !== null) {
80
            $this->stream->rewind();
81
        }
82
    }
83
    public function isWritable(): bool
84
    {
85
        return false;
86
    }
87
    public function write($string): int
88
    {
89
        throw new \RuntimeException('Cannot write to a non-writable stream.');
90
    }
91
    public function isReadable(): bool
92
    {
93
        if ($this->matchedResult === null) {
94
            return false;
95
        }
96
        $this->initConverter();
97
        return $this->stream === null ? false : $this->stream->isReadable();
98
    }
99
    public function read($length): string
100
    {
101
        if (!$this->isReadable()) {
102
            throw new \RuntimeException('Stream should be rendered.');
103
        }
104
        # read generator stream
105
        return $this->stream->read($length);
0 ignored issues
show
Bug introduced by
The method read() 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

105
        return $this->stream->/** @scrutinizer ignore-call */ read($length);

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...
106
    }
107
    public function getContents(): string
108
    {
109
        return $this->read(PHP_INT_MAX);
110
    }
111
    public function getMetadata($key = null)
112
    {
113
        $meta = [
114
            'seekable' => $this->isSeekable(),
115
            'eof' => $this->eof(),
116
        ];
117
118
        if (null === $key) {
119
            return $meta;
120
        }
121
122
        return $meta[$key] ?? null;
123
    }
124
125
    public function withBucket(DataBucket $bucket): self
126
    {
127
        return new static($this->converterMatcher, $bucket);
128
    }
129
130
    public function hasConverter(): bool
131
    {
132
        return $this->matchedResult !== null;
133
    }
134
    public function getConverter(): ?ConverterInterface
135
    {
136
        return $this->matchedResult === null ? null : $this->matchedResult->getConverter();
137
    }
138
    public function hasBucketFormat(): bool
139
    {
140
        return $this->bucket === null ? false : $this->bucket->hasFormat();
141
    }
142
    public function hasMatchedFormat(): bool
143
    {
144
        return $this->matchedResult !== null;
145
    }
146
    public function getMatchedFormat(): ?string
147
    {
148
        return $this->matchedResult === null ? null : $this->matchedResult->getFormat();
149
    }
150
    public function getBucketFormat(): ?string
151
    {
152
        return $this->bucket === null ? null : $this->bucket->getFormat();
153
    }
154
155
    public function isRenderStarted(): bool
156
    {
157
        return $this->stream !== null;
158
    }
159
160
    public function getBucket(): ?DataBucket
161
    {
162
        return $this->bucket;
163
    }
164
    public function getMatchedResult(): ?MatchingResult
165
    {
166
        return $this->matchedResult;
167
    }
168
169
    private function initConverter(): bool
170
    {
171
        if ($this->stream !== null) {
172
            return true;
173
        }
174
        if ($this->matchedResult === null || $this->bucket === null) {
175
            return false;
176
        }
177
        $this->stream = new GeneratorStream($this->matchedResult->getConverter()->convert($this->bucket));
178
        return true;
179
    }
180
}
181