Stream::throwIfUnSeekable()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 3
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Yuloh\Stream;
4
5
use Psr\Http\Message\StreamInterface;
6
7
class Stream implements StreamInterface
8
{
9
    private $readable = [
10
        'r',
11
        'w+',
12
        'r+',
13
        'x+',
14
        'c+',
15
        'rb',
16
        'w+b',
17
        'r+b',
18
        'x+b',
19
        'c+b',
20
        'rt',
21
        'w+t',
22
        'r+t',
23
        'x+t',
24
        'c+t',
25
        'a+',
26
    ];
27
28
    private $writable = [
29
        'w',
30
        'w+',
31
        'rw',
32
        'r+',
33
        'x+',
34
        'c+',
35
        'wb',
36
        'w+b',
37
        'r+b',
38
        'x+b',
39
        'c+b',
40
        'w+t',
41
        'r+t',
42
        'x+t',
43
        'c+t',
44
        'a',
45
        'a+',
46
    ];
47
48
    /**
49
     * @var resource
50
     */
51
    private $resource;
52
53
    /**
54
     * @param resource $resource
55
     * @throws \InvalidArgumentException
56
     */
57 174
    public function __construct($resource)
58
    {
59 174
        if (!is_resource($resource)) {
60 2
            throw new \InvalidArgumentException(
61 2
                sprintf('Expected a valid resource, got "%s".', gettype($resource))
62 2
            );
63
        }
64
65 172
        $this->resource = $resource;
66 172
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71 6
    public function __toString()
72
    {
73
        try {
74 6
            $this->rewind();
75 6
            return $this->getContents();
76 2
        } catch (\RuntimeException $e) {
77 2
            return '';
78
        }
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 2
    public function close()
85
    {
86 2
        if ($this->resource) {
87 2
            fclose($this->detach());
88 2
        }
89 2
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 24
    public function detach()
95
    {
96 24
        $resource       = $this->resource;
97 24
        $this->resource = null;
98
99 24
        return $resource;
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 4
    public function getSize()
106
    {
107 4
        if (!$this->resource) {
108 2
            return null;
109
        }
110
111 2
        return fstat($this->resource)['size'];
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117 12
    public function tell()
118
    {
119 12
        if (!$this->resource) {
120 2
            throw new \RuntimeException('Cannot find the current pointer position, the stream is detached.');
121
        }
122
123 10
        if (($pos = ftell($this->resource)) !== false) {
124 8
            return $pos;
125
        }
126
127 2
        throw new \RuntimeException('Unable to find current pointer position of stream.');
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 6
    public function eof()
134
    {
135 6
        if (!$this->resource) {
136 2
            return true;
137
        }
138
139 4
        return feof($this->resource);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145 26
    public function isSeekable()
146
    {
147 26
        return $this->resource && $this->getMetadata('seekable');
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 22
    public function seek($offset, $whence = SEEK_SET)
154
    {
155 22
        $this->throwIfUnSeekable();
156
157 20
        if (fseek($this->resource, $offset, $whence) === 0) {
158 18
            return;
159
        }
160
161 2
        throw new \RuntimeException('Unable to seek stream.');
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167 14
    public function rewind()
168
    {
169 14
        $this->seek(0);
170 14
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 46
    public function isWritable()
176
    {
177 46
        return $this->resource && in_array($this->getMetadata('mode'), $this->writable);
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 6
    public function write($string)
184
    {
185 6
        $this->throwIfUnwritable();
186
187 4
        if ($bytesWritten = fwrite($this->resource, $string)) {
188 2
            return $bytesWritten;
189
        }
190
191 2
        throw new \RuntimeException('Unable to write stream.');
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 86
    public function isReadable()
198
    {
199 86
        return $this->resource && in_array($this->getMetadata('mode'), $this->readable);
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205 6
    public function read($length)
206
    {
207 6
        $this->throwIfUnreadable();
208
209 4
        if ($contents = fread($this->resource, $length)) {
210 2
            return $contents;
211
        }
212
213 2
        throw new \RuntimeException('Unable to read stream.');
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219 28
    public function getContents()
220
    {
221 28
        $this->throwIfUnreadable();
222
223 24
        if (($contents = stream_get_contents($this->resource)) !== false) {
224 22
            return $contents;
225
        }
226
227 2
        throw new \RuntimeException('Unable to read stream.');
228
    }
229
230
    /**
231
     * {@inheritdoc}
232
     */
233 146
    public function getMetadata($key = null)
234
    {
235 146
        if (!$this->resource) {
236 4
            return $key ? null : [];
237
        }
238
239 142
        $metadata = stream_get_meta_data($this->resource);
240
241 142
        if (is_null($key)) {
242 2
            return $metadata;
243
        }
244
245 140
        return array_key_exists($key, $metadata) ? $metadata[$key] : null;
246
    }
247
248
    /**
249
     * @throws \RuntimeException
250
     */
251 6
    private function throwIfUnwritable()
252
    {
253 6
        if (!$this->isWritable()) {
254 2
            throw new \RuntimeException('The stream is not writable.');
255
        }
256 4
    }
257
258
    /**
259
     * @throws \RuntimeException
260
     */
261 34
    private function throwIfUnreadable()
262
    {
263 34
        if (!$this->isReadable()) {
264 6
            throw new \RuntimeException('The stream is not readable.');
265
        }
266 28
    }
267
268
    /**
269
     * @throws \RuntimeException
270
     */
271 22
    private function throwIfUnSeekable()
272
    {
273 22
        if (!$this->isSeekable()) {
274 2
            throw new \RuntimeException('The stream is not seekable.');
275
        }
276 20
    }
277
}
278