Passed
Push — master ( 2cda12...3e0ae5 )
by Melech
02:04 queued 37s
created

StreamHelpers::isModeWriteable()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 5
nc 5
nop 1
dl 0
loc 7
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Http\Message\Stream\Trait;
15
16
use Valkyrja\Http\Message\Stream\Enum\Mode;
17
use Valkyrja\Http\Message\Stream\Enum\ModeTranslation;
18
use Valkyrja\Http\Message\Stream\Enum\PhpWrapper;
19
use Valkyrja\Http\Message\Stream\Throwable\Exception\InvalidStreamException;
20
use Valkyrja\Http\Message\Stream\Throwable\Exception\NoStreamAvailableException;
21
use Valkyrja\Http\Message\Stream\Throwable\Exception\StreamReadException;
22
use Valkyrja\Http\Message\Stream\Throwable\Exception\StreamSeekException;
23
use Valkyrja\Http\Message\Stream\Throwable\Exception\StreamTellException;
24
use Valkyrja\Http\Message\Stream\Throwable\Exception\StreamWriteException;
25
use Valkyrja\Http\Message\Stream\Throwable\Exception\UnreadableStreamException;
26
use Valkyrja\Http\Message\Stream\Throwable\Exception\UnseekableStreamException;
27
use Valkyrja\Http\Message\Stream\Throwable\Exception\UnwritableStreamException;
28
29
use function fopen;
30
use function get_resource_type;
31
use function is_resource;
32
use function str_contains;
33
34
/**
35
 * Trait StreamHelpers.
36
 *
37
 * @author Melech Mizrachi
38
 */
39
trait StreamHelpers
40
{
41
    /**
42
     * The stream.
43
     *
44
     * @var resource|null
45
     */
46
    protected $resource;
47
48
    /**
49
     * @inheritDoc
50
     */
51
    abstract public function isSeekable(): bool;
52
53
    /**
54
     * @inheritDoc
55
     */
56
    abstract public function isReadable(): bool;
57
58
    /**
59
     * @inheritDoc
60
     */
61
    abstract public function isWritable(): bool;
62
63
    /**
64
     * @inheritDoc
65
     */
66
    abstract public function getMetadata(string|null $key = null): mixed;
67
68
    /**
69
     * Set the stream.
70
     *
71
     * @param PhpWrapper|string $stream          The stream
72
     * @param Mode              $mode            [optional] The mode
73
     * @param ModeTranslation   $modeTranslation [optional] The mode translation
74
     *
75
     * @throws InvalidStreamException
76
     *
77
     * @return void
78
     */
79
    protected function setStream(
80
        PhpWrapper|string $stream = PhpWrapper::temp,
81
        Mode $mode = Mode::WRITE_READ,
82
        ModeTranslation $modeTranslation = ModeTranslation::BINARY_SAFE
83
    ): void {
84
        // Set the mode
85
        $fopenMode = $mode->value . $modeTranslation->value;
86
87
        $streamType = $stream instanceof PhpWrapper
88
            ? $stream->value
89
            : $stream;
90
91
        // Open a new resource stream
92
        $resource = $this->openStream($streamType, $fopenMode);
93
94
        // If the resource isn't a resource or a stream resource type
95
        if (! $this->isStream($resource)) {
96
            // Throw a new invalid stream exception
97
            throw new InvalidStreamException('Invalid stream provided');
98
        }
99
100
        /** @var resource $resource */
101
102
        // Set the stream
103
        $this->resource = $resource;
104
    }
105
106
    /**
107
     * Open a stream.
108
     *
109
     * @return resource|false
110
     */
111
    protected function openStream(string $filename, string $mode)
112
    {
113
        return fopen($filename, $mode);
114
    }
115
116
    protected function isStream(mixed $resource): bool
117
    {
118
        return is_resource($resource) && get_resource_type($resource) === 'stream';
119
    }
120
121
    /**
122
     * Is the stream valid.
123
     *
124
     * @return bool
125
     */
126
    protected function isInvalidStream(): bool
127
    {
128
        return $this->resource === null;
129
    }
130
131
    /**
132
     * Verify the stream.
133
     *
134
     * @return void
135
     */
136
    protected function verifyStream(): void
137
    {
138
        // If there is no stream
139
        if ($this->isInvalidStream()) {
140
            // Throw a runtime exception
141
            throw new NoStreamAvailableException('No stream resource');
142
        }
143
    }
144
145
    /**
146
     * Is mode writable.
147
     *
148
     * @param string $mode
149
     *
150
     * @return bool
151
     */
152
    protected function isModeWriteable(string $mode): bool
153
    {
154
        return str_contains($mode, 'x')
155
            || str_contains($mode, 'w')
156
            || str_contains($mode, 'c')
157
            || str_contains($mode, 'a')
158
            || str_contains($mode, '+');
159
    }
160
161
    /**
162
     * Verify the stream is writable.
163
     *
164
     * @return void
165
     */
166
    protected function verifyWritable(): void
167
    {
168
        // If the stream isn't writable
169
        if (! $this->isWritable()) {
170
            // Throw a new runtime exception
171
            throw new UnwritableStreamException('Stream is not writable');
172
        }
173
    }
174
175
    /**
176
     * Verify the write result.
177
     *
178
     * @param int|false $result
179
     *
180
     * @return void
181
     */
182
    protected function verifyWriteResult(int|false $result): void
183
    {
184
        // If the write was not successful
185
        if ($result === false) {
186
            // Throw a runtime exception
187
            throw new StreamWriteException('Error writing to stream');
188
        }
189
    }
190
191
    /**
192
     * Verify the stream is seekable.
193
     *
194
     * @return void
195
     */
196
    protected function verifySeekable(): void
197
    {
198
        // If the stream isn't seekable
199
        if (! $this->isSeekable()) {
200
            // Throw a new runtime exception
201
            throw new UnseekableStreamException('Stream is not seekable');
202
        }
203
    }
204
205
    /**
206
     * Verify the seek result.
207
     *
208
     * @param int $result
209
     *
210
     * @return void
211
     */
212
    protected function verifySeekResult(int $result): void
213
    {
214
        // If the result was not a 0, denoting an error occurred
215
        if ($result !== 0) {
216
            // Throw a new runtime exception
217
            throw new StreamSeekException('Error seeking within stream');
218
        }
219
    }
220
221
    /**
222
     * Is mode readable.
223
     *
224
     * @param string $mode
225
     *
226
     * @return bool
227
     */
228
    protected function isModeReadable(string $mode): bool
229
    {
230
        return str_contains($mode, 'r')
231
            || str_contains($mode, '+');
232
    }
233
234
    /**
235
     * Verify the stream is readable.
236
     *
237
     * @return void
238
     */
239
    protected function verifyReadable(): void
240
    {
241
        // If the stream is not readable
242
        if (! $this->isReadable()) {
243
            // Throw a runtime exception
244
            throw new UnreadableStreamException('Stream is not readable');
245
        }
246
    }
247
248
    /**
249
     * Verify the read result.
250
     *
251
     * @param string|false $result
252
     *
253
     * @return void
254
     */
255
    protected function verifyReadResult(string|false $result): void
256
    {
257
        // If there was a failure in reading the stream
258
        if ($result === false) {
259
            // Throw a runtime exception
260
            throw new StreamReadException('Error reading stream');
261
        }
262
    }
263
264
    /**
265
     * Verify the tell result.
266
     *
267
     * @param int|false $result
268
     *
269
     * @return void
270
     */
271
    protected function verifyTellResult(int|false $result): void
272
    {
273
        // If the tell is not an int
274
        if ($result === false) {
275
            // Throw a runtime exception
276
            throw new StreamTellException('Error occurred during tell operation');
277
        }
278
    }
279
}
280