OptimalTransferEncodedTextStream   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 190
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 63.46%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 4
dl 0
loc 190
ccs 33
cts 52
cp 0.6346
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A calculateOptimalStream() 0 15 3
A __toString() 0 4 1
A close() 0 4 1
A detach() 0 4 1
A getSize() 0 4 1
A tell() 0 4 1
A eof() 0 4 1
A isSeekable() 0 4 1
A seek() 0 4 1
A rewind() 0 4 1
A isWritable() 0 4 1
A write() 0 4 1
A isReadable() 0 4 1
A read() 0 4 1
A getContents() 0 4 1
A getMetadata() 0 15 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Stream;
5
6
use Genkgo\Mail\StreamInterface;
7
8
final class OptimalTransferEncodedTextStream implements StreamInterface
9
{
10
    /**
11
     * @var StreamInterface
12
     */
13
    private $decoratedStream;
14
15
    /**
16
     * @var string
17
     */
18
    private $encoding = '7bit';
19
20
    /**
21
     * @var int
22
     */
23
    private $lineLength = 78;
24
    
25
    private const NON_7BIT_CHARS = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
26
27
    /**
28
     * @var string
29
     */
30
    private $lineBreak;
31
32
    /**
33
     * @param string $text
34
     * @param int $lineLength
35
     * @param string $lineBreak
36
     */
37 175
    public function __construct(string $text, int $lineLength = 78, string $lineBreak = "\r\n")
38
    {
39 175
        $this->lineLength = $lineLength;
40 175
        $this->lineBreak = $lineBreak;
41 175
        $this->decoratedStream = $this->calculateOptimalStream($text);
42 175
    }
43
44
    /**
45
     * @param string $text
46
     * @return StreamInterface
47
     */
48 175
    private function calculateOptimalStream(string $text): StreamInterface
49
    {
50 175
        if (\strcspn($text, self::NON_7BIT_CHARS) === \strlen($text)) {
51 155
            $this->encoding = '7bit';
52 155
            return new AsciiEncodedStream($text, $this->lineLength, $this->lineBreak);
53
        }
54
55 31
        if (\preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $text) > (\strlen($text) / 3)) {
56 15
            $this->encoding = 'base64';
57 15
            return Base64EncodedStream::fromString($text, $this->lineLength, $this->lineBreak);
58
        }
59
60 16
        $this->encoding = 'quoted-printable';
61 16
        return QuotedPrintableStream::fromString($text, $this->lineLength, $this->lineBreak);
62
    }
63
64
    /**
65
     * @return string
66
     */
67 147
    public function __toString(): string
68
    {
69 147
        return $this->decoratedStream->__toString();
70
    }
71
    
72
    public function close(): void
73
    {
74
        $this->decoratedStream->close();
75
    }
76
77
    /**
78
     * @return mixed
79
     */
80
    public function detach()
81
    {
82
        return $this->decoratedStream->detach();
83
    }
84
85
    /**
86
     * @return int|null
87
     */
88 25
    public function getSize(): ?int
89
    {
90 25
        return $this->decoratedStream->getSize();
91
    }
92
93
    /**
94
     * @return int
95
     * @throws \RuntimeException
96
     */
97
    public function tell(): int
98
    {
99
        return $this->decoratedStream->tell();
100
    }
101
102
    /**
103
     * @return bool
104
     */
105 2
    public function eof(): bool
106
    {
107 2
        return $this->decoratedStream->eof();
108
    }
109
110
    /**
111
     * @return bool
112
     */
113
    public function isSeekable(): bool
114
    {
115
        return $this->decoratedStream->isSeekable();
116
    }
117
118
    /**
119
     * @param int $offset
120
     * @param int $whence
121
     * @return int
122
     */
123
    public function seek(int $offset, int $whence = SEEK_SET): int
124
    {
125
        return $this->decoratedStream->seek($offset, $whence);
126
    }
127
128
    /**
129
     * @return bool
130
     */
131 2
    public function rewind(): bool
132
    {
133 2
        return $this->decoratedStream->rewind();
134
    }
135
136
    /**
137
     * @return bool
138
     */
139
    public function isWritable(): bool
140
    {
141
        return $this->decoratedStream->isWritable();
142
    }
143
144
    /**
145
     * @param string $string
146
     * @return int
147
     */
148
    public function write($string): int
149
    {
150
        return $this->decoratedStream->write($string);
151
    }
152
153
    /**
154
     * @return bool
155
     */
156
    public function isReadable(): bool
157
    {
158
        return $this->decoratedStream->isReadable();
159
    }
160
161
    /**
162
     * @param int $length
163
     * @return string
164
     */
165 2
    public function read(int $length): string
166
    {
167 2
        return $this->decoratedStream->read($length);
168
    }
169
170
    /**
171
     * @return string
172
     */
173
    public function getContents(): string
174
    {
175
        return $this->decoratedStream->getContents();
176
    }
177
178
    /**
179
     * @param array<int, string> $keys
180
     * @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...
181
     */
182 175
    public function getMetadata(array $keys = []): array
183
    {
184 175
        $metaData = $this->decoratedStream->getMetadata($keys);
185 175
        $metaData['transfer-encoding'] = $this->encoding;
186
187 175
        $keys = \array_map('strtolower', $keys);
188
189 175
        return \array_filter(
190 175
            $metaData,
191
            function ($key) use ($keys) {
192 175
                return \in_array(\strtolower($key), $keys);
193 175
            },
194 175
            ARRAY_FILTER_USE_KEY
195
        );
196
    }
197
}
198