Skip to content

Commit 620d561

Browse files
committed
feat: support custom encoders in mime parts
1 parent 232d6d0 commit 620d561

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

src/Symfony/Component/Mime/Part/TextPart.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,6 @@ public function __construct($body, ?string $charset = 'utf-8', string $subtype =
6363
if (null === $encoding) {
6464
$this->encoding = $this->chooseEncoding();
6565
} else {
66-
if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) {
67-
throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding));
68-
}
6966
$this->encoding = $encoding;
7067
}
7168
}
@@ -199,6 +196,10 @@ public function asDebugString(): string
199196

200197
private function getEncoder(): ContentEncoderInterface
201198
{
199+
if ('quoted-printable' !== $this->encoding && 'base64' !== $this->encoding && '8bit' !== $this->encoding && !\array_key_exists($this->encoding, self::$encoders)) {
200+
throw new InvalidArgumentException('The encoding must be one of "quoted-printable", "base64", or "8bit" unless you provide a custom encoder.');
201+
}
202+
202203
if ('8bit' === $this->encoding) {
203204
return self::$encoders[$this->encoding] ??= new EightBitContentEncoder();
204205
}
@@ -207,7 +208,18 @@ private function getEncoder(): ContentEncoderInterface
207208
return self::$encoders[$this->encoding] ??= new QpContentEncoder();
208209
}
209210

210-
return self::$encoders[$this->encoding] ??= new Base64ContentEncoder();
211+
if ('base64' === $this->encoding) {
212+
return self::$encoders[$this->encoding] ??= new Base64ContentEncoder();
213+
}
214+
215+
return self::$encoders[$this->encoding];
216+
}
217+
218+
public function addEncoder(string $name, ContentEncoderInterface $encoder): static
219+
{
220+
self::$encoders[$name] = $encoder;
221+
222+
return $this;
211223
}
212224

213225
private function chooseEncoding(): string

src/Symfony/Component/Mime/Tests/Part/TextPartTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Mime\Tests\Part;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mime\Encoder\ContentEncoderInterface;
1516
use Symfony\Component\Mime\Header\Headers;
1617
use Symfony\Component\Mime\Header\ParameterizedHeader;
1718
use Symfony\Component\Mime\Header\UnstructuredHeader;
@@ -87,6 +88,35 @@ public function testEncoding()
8788
), $p->getPreparedHeaders());
8889
}
8990

91+
public function testCustomEncoding()
92+
{
93+
$p = new TextPart('content', 'utf-8', 'plain', 'test_encoding');
94+
$p->addEncoder('test_encoding', new class() implements ContentEncoderInterface {
95+
public function encodeByteStream($stream, int $maxLineLength = 0): iterable
96+
{
97+
while (!feof($stream)) {
98+
yield fread($stream, 16372);
99+
}
100+
}
101+
102+
public function getName(): string
103+
{
104+
return 'test_encoding';
105+
}
106+
107+
public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string
108+
{
109+
return $string;
110+
}
111+
});
112+
$this->assertEquals('content', $p->bodyToString());
113+
$this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable())));
114+
$this->assertEquals(new Headers(
115+
new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']),
116+
new UnstructuredHeader('Content-Transfer-Encoding', 'test_encoding')
117+
), $p->getPreparedHeaders());
118+
}
119+
90120
public function testSerialize()
91121
{
92122
$r = fopen('php://memory', 'r+', false);

0 commit comments

Comments
 (0)