CachingStream   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 94.34%
Metric Value
wmc 19
lcom 1
cbo 4
dl 0
loc 131
ccs 50
cts 53
cp 0.9434
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A getSize() 0 4 1
A rewind() 0 4 1
B seek() 0 27 6
B read() 0 28 3
A write() 0 13 2
A eof() 0 4 2
A close() 0 4 2
A cacheEntireStream() 0 7 1
1
<?php
2
3
namespace Thruster\Component\HttpMessage;
4
5
use Psr\Http\Message\StreamInterface;
6
7
/**
8
 * Class CachingStream
9
 *
10
 * @package Thruster\Component\HttpMessage
11
 * @author  Aurimas Niekis <[email protected]>
12
 */
13
class CachingStream implements StreamInterface
14
{
15
    use StreamDecoratorTrait;
16
17
    /**
18
     * @var StreamInterface Stream being wrapped
19
     */
20
    private $remoteStream;
21
22
    /**
23
     * @var int Number of bytes to skip reading due to a write on the buffer
24
     */
25
    private $skipReadBytes;
26
27
    /**
28
     * We will treat the buffer object as the body of the stream
29
     *
30
     * @param StreamInterface $stream Stream to cache
31
     * @param StreamInterface $target Optionally specify where data is cached
32
     */
33 11
    public function __construct(
34
        StreamInterface $stream,
35
        StreamInterface $target = null
36
    ) {
37 11
        $this->skipReadBytes = 0;
38 11
        $this->remoteStream = $stream;
39 11
        $this->stream = $target ?? new Stream(fopen('php://temp', 'r+'));
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
40 11
    }
41
42 3
    public function getSize()
43
    {
44 3
        return max($this->stream->getSize(), $this->remoteStream->getSize());
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
45
    }
46
47
    public function rewind()
48
    {
49
        $this->seek(0);
50
    }
51
52 8
    public function seek($offset, $whence = SEEK_SET)
53
    {
54 8
        if (SEEK_SET === $whence) {
55 4
            $byte = $offset;
56 5
        } elseif (SEEK_CUR === $whence) {
57 1
            $byte = $offset + $this->tell();
58 4
        } elseif (SEEK_END === $whence) {
59 3
            $size = $this->remoteStream->getSize();
60 3
            if (null === $size) {
61 1
                $size = $this->cacheEntireStream();
62
            }
63 3
            $byte = $size + $offset;
64
        } else {
65 1
            throw new \InvalidArgumentException('Invalid whence');
66
        }
67
68 7
        $diff = $byte - $this->stream->getSize();
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
69
70 7
        if (0 < $diff) {
71
            // If the seek byte is greater the number of read bytes, then read
72
            // the difference of bytes to cache the bytes and inherently seek.
73 3
            $this->read($diff);
74
        } else {
75
            // We can just do a normal seek since we've already seen this byte.
76 5
            $this->stream->seek($byte);
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
77
        }
78 7
    }
79
80 7
    public function read($length)
81
    {
82
        // Perform a regular read on any previously read data from the buffer
83 7
        $data = $this->stream->read($length);
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
84 7
        $remaining = $length - strlen($data);
85
86
        // More data was requested so read from the remote stream
87 7
        if ($remaining) {
88
            // If data was written to the buffer in a position that would have
89
            // been filled from the remote stream, then we must skip bytes on
90
            // the remote stream to emulate overwriting bytes from that
91
            // position. This mimics the behavior of other PHP stream wrappers.
92 7
            $remoteData = $this->remoteStream->read(
93 7
                $remaining + $this->skipReadBytes
94
            );
95
96 7
            if ($this->skipReadBytes) {
97 2
                $len = strlen($remoteData);
98 2
                $remoteData = substr($remoteData, $this->skipReadBytes);
99 2
                $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
100
            }
101
102 7
            $data .= $remoteData;
103 7
            $this->stream->write($remoteData);
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
104
        }
105
106 7
        return $data;
107
    }
108
109 2
    public function write($string)
110
    {
111
        // When appending to the end of the currently read stream, you'll want
112
        // to skip bytes from being read from the remote stream to emulate
113
        // other stream wrappers. Basically replacing bytes of data of a fixed
114
        // length.
115 2
        $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
116 2
        if (0 < $overflow) {
117 2
            $this->skipReadBytes += $overflow;
118
        }
119
120 2
        return $this->stream->write($string);
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
121
    }
122
123 3
    public function eof() : bool
124
    {
125 3
        return $this->stream->eof() && $this->remoteStream->eof();
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
126
    }
127
128
    /**
129
     * Close both the remote stream and buffer stream
130
     */
131 11
    public function close()
132
    {
133 11
        $this->remoteStream->close() && $this->stream->close();
0 ignored issues
show
Bug introduced by
The property stream does not seem to exist. Did you mean remoteStream?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
134 11
    }
135
136 1
    private function cacheEntireStream()
137
    {
138 1
        $target = new FnStream(['write' => 'strlen']);
139 1
        copy_to_stream($this, $target);
140
141 1
        return $this->tell();
142
    }
143
}
144