• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

predis / predis / 13716769884

07 Mar 2025 08:31AM UTC coverage: 92.8% (+0.03%) from 92.772%
13716769884

push

github

web-flow
Added support for transactions in OSS Cluster (#1497)

* Added support for transactions in OSS Cluster

* Updated test cases

* Updated version restriction

* Updated server version restriction

* Added test skip for Relay

* Added test case for Relay

* Set transaction slot to null in case of failed transaction

* Restrict usage of transaction commands outside of transaction context

* Added handling for Relay responses

* Reverted changes

* Removed unsupported command

* Added dummy arguments

* Codestyle fixes

* Added additional test coverage

* Added CHANGELOG and README entries

* Added missing PR reference

* Missing word

* Fixed README

124 of 136 new or added lines in 11 files covered. (91.18%)

4 existing lines in 1 file now uncovered.

6870 of 7403 relevant lines covered (92.8%)

111.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.7
/src/Connection/Resource/Stream.php
1
<?php
2

3
/*
4
 * This file is part of the Predis package.
5
 *
6
 * (c) 2009-2020 Daniele Alessandri
7
 * (c) 2021-2023 Till Krüss
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12

13
namespace Predis\Connection\Resource;
14

15
use InvalidArgumentException;
16
use Psr\Http\Message\StreamInterface;
17
use RuntimeException;
18

19
class Stream implements StreamInterface
20
{
21
    /**
22
     * @see https://www.php.net/manual/en/function.fopen.php
23
     * @see https://www.php.net/manual/en/function.gzopen.php
24
     */
25
    private const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/';
26
    private const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';
27

28
    /**
29
     * @var resource
30
     */
31
    private $stream;
32

33
    /**
34
     * @var bool
35
     */
36
    private $seekable;
37

38
    /**
39
     * @var bool
40
     */
41
    private $readable;
42

43
    /**
44
     * @var bool
45
     */
46
    private $writable;
47

48
    /**
49
     * @param  resource                 $stream
50
     * @throws InvalidArgumentException if stream is not a valid resource.
51
     */
52
    public function __construct($stream)
1,532✔
53
    {
54
        if (!is_resource($stream)) {
1,532✔
55
            throw new InvalidArgumentException('Given stream is not a valid resource');
1✔
56
        }
57

58
        $this->stream = $stream;
1,531✔
59
        $metadata = stream_get_meta_data($this->stream);
1,531✔
60
        $this->seekable = $metadata['seekable'];
1,531✔
61
        $this->readable = (bool) preg_match(self::READABLE_MODES, $metadata['mode']);
1,531✔
62
        $this->writable = (bool) preg_match(self::WRITABLE_MODES, $metadata['mode']);
1,531✔
63
    }
64

65
    /**
66
     * {@inheritDoc}
67
     */
68
    public function __toString(): string
1✔
69
    {
70
        if ($this->isSeekable()) {
1✔
71
            $this->seek(0);
1✔
72
        }
73

74
        return $this->getContents();
1✔
75
    }
76

77
    /**
78
     * {@inheritDoc}
79
     */
80
    public function close(): void
1,470✔
81
    {
82
        if (isset($this->stream)) {
1,470✔
83
            fclose($this->stream);
1,461✔
84
        }
85

86
        $this->detach();
1,470✔
87
    }
88

89
    /**
90
     * {@inheritDoc}
91
     */
92
    public function detach()
1,481✔
93
    {
94
        if (!isset($this->stream)) {
1,481✔
95
            return null;
10✔
96
        }
97

98
        $result = $this->stream;
1,481✔
99
        unset($this->stream);
1,481✔
100
        $this->readable = $this->writable = $this->seekable = false;
1,481✔
101

102
        return $result;
1,481✔
103
    }
104

105
    /**
106
     * {@inheritDoc}
107
     */
108
    public function getSize(): ?int
1✔
109
    {
110
        if (!isset($this->stream)) {
1✔
111
            return null;
1✔
112
        }
113

114
        $stats = fstat($this->stream);
1✔
115
        if (is_array($stats) && isset($stats['size'])) {
1✔
116
            return $stats['size'];
1✔
117
        }
118

UNCOV
119
        return null;
×
120
    }
121

122
    /**
123
     * {@inheritDoc}
124
     */
125
    public function tell(): int
2✔
126
    {
127
        if (!isset($this->stream)) {
2✔
128
            throw new RuntimeException('Stream is detached');
1✔
129
        }
130

131
        $result = ftell($this->stream);
1✔
132

133
        if ($result === false) {
1✔
UNCOV
134
            throw new RuntimeException('Unable to determine stream position');
×
135
        }
136

137
        return $result;
1✔
138
    }
139

140
    /**
141
     * {@inheritDoc}
142
     */
143
    public function eof(): bool
1,449✔
144
    {
145
        if (!isset($this->stream)) {
1,449✔
146
            throw new RuntimeException('Stream is detached');
1✔
147
        }
148

149
        return feof($this->stream);
1,448✔
150
    }
151

152
    /**
153
     * {@inheritDoc}
154
     */
155
    public function isSeekable(): bool
8✔
156
    {
157
        return $this->seekable;
8✔
158
    }
159

160
    /**
161
     * {@inheritDoc}
162
     */
163
    public function seek(int $offset, int $whence = SEEK_SET): void
7✔
164
    {
165
        if (!isset($this->stream)) {
7✔
166
            throw new RuntimeException('Stream is detached');
1✔
167
        }
168

169
        if (!$this->isSeekable()) {
6✔
UNCOV
170
            throw new RuntimeException('Stream is not seekable');
×
171
        }
172

173
        if (fseek($this->stream, $offset, $whence) === -1) {
6✔
174
            throw new RuntimeException("Unable to seek stream from offset {$offset} to whence {$whence}");
1✔
175
        }
176
    }
177

178
    /**
179
     * {@inheritDoc}
180
     */
181
    public function rewind(): void
4✔
182
    {
183
        $this->seek(0);
4✔
184
    }
185

186
    /**
187
     * {@inheritDoc}
188
     */
189
    public function isWritable(): bool
1,473✔
190
    {
191
        return $this->writable;
1,473✔
192
    }
193

194
    /**
195
     * {@inheritDoc}
196
     * @throws RuntimeException
197
     */
198
    public function write(string $string): int
1,455✔
199
    {
200
        if (!isset($this->stream)) {
1,455✔
201
            throw new RuntimeException('Stream is detached');
1✔
202
        }
203

204
        if (!$this->isWritable()) {
1,454✔
205
            throw new RuntimeException('Cannot write to a non-writable stream');
1✔
206
        }
207

208
        $result = fwrite($this->stream, $string);
1,453✔
209

210
        if ($result === false) {
1,453✔
UNCOV
211
            throw new RuntimeException('Unable to write to stream', 1);
×
212
        }
213

214
        return $result;
1,453✔
215
    }
216

217
    /**
218
     * {@inheritDoc}
219
     */
220
    public function isReadable(): bool
1,473✔
221
    {
222
        return $this->readable;
1,473✔
223
    }
224

225
    /**
226
     * {@inheritDoc}
227
     * @param  int              $length If length = -1, reads a stream line by line (e.g fgets())
228
     * @throws RuntimeException
229
     */
230
    public function read(int $length): string
1,453✔
231
    {
232
        if (!isset($this->stream)) {
1,453✔
233
            throw new RuntimeException('Stream is detached');
1✔
234
        }
235

236
        if (!$this->isReadable()) {
1,452✔
237
            throw new RuntimeException('Cannot read from non-readable stream');
1✔
238
        }
239

240
        if ($length < -1) {
1,451✔
241
            throw new RuntimeException('Length parameter cannot be negative');
1✔
242
        }
243

244
        if (0 === $length) {
1,450✔
245
            return '';
1✔
246
        }
247

248
        if ($length === -1) {
1,449✔
249
            $string = fgets($this->stream);
1,447✔
250
        } else {
251
            $string = fread($this->stream, $length);
1,434✔
252
        }
253

254
        if (false === $string) {
1,449✔
255
            throw new RuntimeException('Unable to read from stream', 1);
2✔
256
        }
257

258
        return $string;
1,449✔
259
    }
260

261
    /**
262
     * {@inheritDoc}
263
     */
264
    public function getContents(): string
4✔
265
    {
266
        if (!isset($this->stream)) {
4✔
267
            throw new RuntimeException('Stream is detached');
1✔
268
        }
269

270
        if (!$this->isReadable()) {
3✔
271
            throw new RuntimeException('Cannot read from non-readable stream');
1✔
272
        }
273

274
        return stream_get_contents($this->stream);
2✔
275
    }
276

277
    /**
278
     * {@inheritDoc}
279
     */
280
    public function getMetadata(?string $key = null)
1✔
281
    {
282
        if (!isset($this->stream)) {
1✔
283
            return null;
1✔
284
        }
285

286
        if (!$key) {
1✔
287
            return stream_get_meta_data($this->stream);
1✔
288
        }
289

290
        $metadata = stream_get_meta_data($this->stream);
1✔
291

292
        return $metadata[$key] ?? null;
1✔
293
    }
294
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc