Base64EncodedStream::rewind()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2.0185
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Stream;
5
6
use Genkgo\Mail\StreamInterface;
7
8
final class Base64EncodedStream implements StreamInterface
9
{
10
    /**
11
     * @var StreamInterface
12
     */
13
    private $decoratedStream;
14
15
    /**
16
     * @var int
17
     */
18
    private $lineLength;
19
20
    /**
21
     * @var resource
22
     */
23
    private $filter;
24
25
    /**
26
     * @var string
27
     */
28
    private $lineBreak;
29
30
    /**
31
     * @param resource $resource
32
     * @param int $lineLength
33
     * @param string $lineBreak
34
     */
35 67
    public function __construct($resource, int $lineLength = 76, string $lineBreak = "\r\n")
36
    {
37 67
        $this->decoratedStream = new ResourceStream($resource);
38 67
        $this->lineLength = $lineLength;
39 67
        $this->lineBreak = $lineBreak;
40
41 67
        $this->applyFilter();
42 67
    }
43
44
    /**
45
     * @param string $string
46
     * @param int $lineLength
47
     * @param string $lineBreak
48
     * @return Base64EncodedStream
49
     */
50 33
    public static function fromString(string $string, int $lineLength = 76, string $lineBreak = "\r\n"): Base64EncodedStream
51
    {
52 33
        $resource = \fopen('php://memory', 'r+');
53 33
        if ($resource === false) {
54
            throw new \UnexpectedValueException('Cannot open php://memory for writing');
55
        }
56
57 33
        \fwrite($resource, $string);
58 33
        return new self($resource, $lineLength, $lineBreak);
59
    }
60
    
61 67
    private function applyFilter(): void
62
    {
63 67
        $filter = \stream_filter_prepend(
64 67
            $this->decoratedStream->detach(),
65 67
            'convert.base64-encode',
66 67
            STREAM_FILTER_READ,
67
            [
68 67
                'line-length' => $this->lineLength,
69 67
                'line-break-chars' => $this->lineBreak
70
            ]
71
        );
72
73 67
        if ($filter === false) {
74
            throw new \UnexpectedValueException('Cannot append filter to stream');
75
        }
76
77 67
        $this->filter = $filter;
78 67
    }
79
80 31
    private function removeFilter(): void
81
    {
82 31
        if ($this->filter !== null) {
83 31
            \stream_filter_remove($this->filter);
84
        }
85 31
    }
86
87
    /**
88
     * @return string
89
     */
90 30
    public function __toString(): string
91
    {
92 30
        $this->rewind();
93 30
        return $this->decoratedStream->__toString();
94
    }
95
    
96
    public function close(): void
97
    {
98
        $this->decoratedStream->close();
99
    }
100
101
    /**
102
     * @return mixed
103
     */
104
    public function detach()
105
    {
106
        return $this->decoratedStream->detach();
107
    }
108
109
    /**
110
     * @return int|null
111
     */
112 7
    public function getSize(): ?int
113
    {
114 7
        return (int) \ceil($this->decoratedStream->getSize() / 3) * 4;
115
    }
116
117
    /**
118
     * @return int
119
     * @throws \RuntimeException
120
     */
121 1
    public function tell(): int
122
    {
123 1
        return $this->decoratedStream->tell();
124
    }
125
126
    /**
127
     * @return bool
128
     */
129 2
    public function eof(): bool
130
    {
131 2
        return $this->decoratedStream->eof();
132
    }
133
134
    /**
135
     * @return bool
136
     */
137
    public function isSeekable(): bool
138
    {
139
        return false;
140
    }
141
142
    /**
143
     * @param int $offset
144
     * @param int $whence
145
     * @return int
146
     */
147 1
    public function seek(int $offset, int $whence = SEEK_SET): int
148
    {
149 1
        return -1;
150
    }
151
152
    /**
153
     * @return bool
154
     */
155 31
    public function rewind(): bool
156
    {
157 31
        $this->removeFilter();
158 31
        if (!$this->decoratedStream->rewind()) {
159
            return false;
160
        }
161
162 31
        $this->applyFilter();
163 31
        return true;
164
    }
165
166
    /**
167
     * @return bool
168
     */
169 1
    public function isWritable(): bool
170
    {
171 1
        return false;
172
    }
173
174
    /**
175
     * @param string $string
176
     * @return int
177
     */
178 1
    public function write($string): int
179
    {
180 1
        throw new \RuntimeException('Cannot write to stream');
181
    }
182
183
    /**
184
     * @return bool
185
     */
186
    public function isReadable(): bool
187
    {
188
        return true;
189
    }
190
191
    /**
192
     * @param int $length
193
     * @return string
194
     */
195 3
    public function read(int $length): string
196
    {
197 3
        return $this->decoratedStream->read($length);
198
    }
199
200
    /**
201
     * @return string
202
     */
203 2
    public function getContents(): string
204
    {
205 2
        return $this->decoratedStream->getContents();
206
    }
207
208
    /**
209
     * @param array<int, string> $keys
210
     * @return array<string, mixed>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
211
     */
212 26
    public function getMetadata(array $keys = []): array
213
    {
214 26
        return $this->decoratedStream->getMetadata();
215
    }
216
}
217