Completed
Push — single-stream-object ( f32912...964235 )
by Daniel
06:09
created

Stream::bindResource()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
ccs 9
cts 9
cp 1
rs 9.4286
cc 1
eloc 9
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * This file is part of the stream package
4
 *
5
 * @author Daniel Schröder <[email protected]>
6
 */
7
8
namespace GravityMedia\Stream;
9
10
use GravityMedia\Stream\Exception;
11
12
/**
13
 * Stream
14
 *
15
 * @package GravityMedia\Stream
16
 */
17
class Stream implements StreamInterface
18
{
19
    /**
20
     * @var string[]
21
     */
22
    private static $readModes = ['r', 'w+', 'r+', 'x+', 'c+', 'rb', 'w+b', 'r+b', 'x+b', 'c+b', 'rt', 'w+t',
23
        'r+t', 'x+t', 'c+t', 'a+'];
24
25
    /**
26
     * @var string[]
27
     */
28
    private static $writeModes = ['w', 'w+', 'rw', 'r+', 'x+', 'c+', 'wb', 'w+b', 'r+b', 'x+b', 'c+b', 'w+t',
29
        'r+t', 'x+t', 'c+t', 'a', 'a+'];
30
31
    /**
32
     * @var resource
33
     */
34
    protected $resource;
35
36
    /**
37
     * @var bool
38
     */
39
    protected $local;
40
41
    /**
42
     * @var bool
43
     */
44
    protected $readable;
45
46
    /**
47
     * @var bool
48
     */
49
    protected $writable;
50
51
    /**
52
     * @var bool
53
     */
54
    protected $seekable;
55
56
    /**
57
     * @var string
58
     */
59
    protected $uri;
60
61
    /**
62
     * Create stream object from resource
63
     *
64
     * @param resource $resource
65
     *
66
     * @return StreamInterface
67
     */
68 69
    public static function fromResource($resource)
69
    {
70 69
        $instance = new static();
71
72 69
        return $instance->bindResource($resource);
73
    }
74
75
    /**
76
     * Get meta data from the stream
77
     *
78
     * @throws Exception\IOException An exception will be thrown for invalid stream resources
79
     *
80
     * @return array
81
     */
82 66
    protected function getMetaData()
83
    {
84 66
        return stream_get_meta_data($this->getResource());
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90 69
    public function bindResource($resource)
91
    {
92 69
        $this->resource = $resource;
93
94 69
        $this->local = stream_is_local($this->getResource());
95
96 66
        $metaData = $this->getMetaData();
97 66
        $this->readable = in_array($metaData['mode'], self::$readModes);
98 66
        $this->writable = in_array($metaData['mode'], self::$writeModes);
99 66
        $this->seekable = $metaData['seekable'];
100 66
        $this->uri = $metaData['uri'];
101
102 66
        return $this;
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108 69
    public function getResource()
109
    {
110 69
        if (!is_resource($this->resource)) {
111 27
            throw new Exception\IOException('Invalid resource');
112
        }
113
114 66
        return $this->resource;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 9
    public function isLocal()
121
    {
122 9
        return $this->local;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 9
    public function isReadable()
129
    {
130 9
        return $this->readable;
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136 12
    public function isWritable()
137
    {
138 12
        return $this->writable;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 12
    public function isSeekable()
145
    {
146 12
        return $this->seekable;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152 6
    public function getUri()
153
    {
154 6
        return $this->uri;
155
    }
156
157
    /**
158
     * Get information about the stream
159
     *
160
     * @param string $info The information to retrieve
161
     *
162
     * @throws Exception\IOException An exception will be thrown for invalid stream resources
163
     *
164
     * @return int
165
     */
166 6
    protected function getStat($info)
167
    {
168 6
        $resource = $this->getResource();
169
170 3
        $uri = $this->getUri();
171 3
        if (is_string($uri)) {
172 3
            clearstatcache(true, $uri);
173 3
        }
174
175 3
        $stat = fstat($resource);
176
177 3
        return $stat[$info];
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183 9
    public function getSize()
184
    {
185 9
        if (!$this->isLocal()) {
186 3
            throw new Exception\BadMethodCallException('Operation not supported');
187
        }
188
189 6
        return $this->getStat('size');
190
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195 6
    public function eof()
196
    {
197 6
        return feof($this->getResource());
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203 12
    public function tell()
204
    {
205 12
        return ftell($this->getResource());
206
    }
207
208
    /**
209
     * {@inheritdoc}
210
     */
211 15
    public function seek($offset, $whence = SEEK_SET)
212
    {
213 15
        $resource = $this->getResource();
214
215 12
        if (!$this->isSeekable()) {
216 3
            throw new Exception\BadMethodCallException('Operation not supported');
217
        }
218
219 9
        if (fseek($resource, $offset, $whence) < 0) {
220 3
            throw new Exception\IOException('Unexpected result of operation');
221
        }
222
223 6
        return $this->tell();
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229 3
    public function rewind()
230
    {
231 3
        return $this->seek(0);
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237 12 View Code Duplication
    public function read($length = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
238
    {
239 12
        $resource = $this->getResource();
240
241 9
        if (!$this->isReadable()) {
242 3
            throw new Exception\BadMethodCallException('Operation not supported');
243
        }
244
245 6
        $data = @fread($resource, $length);
246 6
        if (false === $data) {
247 3
            throw new Exception\IOException('Unexpected result of operation');
248
        }
249
250 3
        return $data;
251
    }
252
253
    /**
254
     * {@inheritdoc}
255
     */
256 12 View Code Duplication
    public function write($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
    {
258 12
        $resource = $this->getResource();
259
260 9
        if (!$this->isWritable()) {
261 3
            throw new Exception\BadMethodCallException('Operation not supported');
262
        }
263
264 6
        $length = @fwrite($resource, $data);
265 6
        if (false === $length) {
266 3
            throw new Exception\IOException('Unexpected result of operation');
267
        }
268
269 3
        return $length;
270
    }
271
272
    /**
273
     * {@inheritdoc}
274
     */
275 9
    public function truncate($size)
276
    {
277 9
        $resource = $this->getResource();
278
279 6
        if (!$this->isWritable()) {
280 3
            throw new Exception\BadMethodCallException('Operation not supported');
281
        }
282
283 3
        return @ftruncate($resource, $size);
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289 3
    public function close()
290
    {
291 3
        return @fclose($this->resource);
292
    }
293
}
294