Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0811e87

Browse filesBrowse files
committed
[Mime] Simplify adding Parts to an Email
1 parent 4d09837 commit 0811e87
Copy full SHA for 0811e87

File tree

14 files changed

+121
-139
lines changed
Filter options

14 files changed

+121
-139
lines changed

‎src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php
+8-2Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,16 @@ public function testSymfonySerialize()
7474
"htmlCharset": null,
7575
"attachments": [
7676
{
77+
"filename": "test.txt",
78+
"mediaType": "application",
7779
"body": "Some Text file",
80+
"charset": null,
81+
"subtype": "octet-stream",
82+
"disposition": "attachment",
7883
"name": "test.txt",
79-
"content-type": null,
80-
"inline": false
84+
"encoding": "base64",
85+
"headers": [],
86+
"class": "Symfony\\\Component\\\Mime\\\Part\\\DataPart"
8187
}
8288
],
8389
"headers": {

‎src/Symfony/Bridge/Twig/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/composer.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"symfony/security-core": "^5.4|^6.0",
4444
"symfony/security-csrf": "^5.4|^6.0",
4545
"symfony/security-http": "^5.4|^6.0",
46-
"symfony/serializer": "^5.4|^6.0",
46+
"symfony/serializer": "^6.2",
4747
"symfony/stopwatch": "^5.4|^6.0",
4848
"symfony/console": "^5.4|^6.0",
4949
"symfony/expression-language": "^5.4|^6.0",

‎src/Symfony/Component/Mailer/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/composer.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"psr/event-dispatcher": "^1",
2222
"psr/log": "^1|^2|^3",
2323
"symfony/event-dispatcher": "^5.4|^6.0",
24-
"symfony/mime": "^5.4|^6.0",
24+
"symfony/mime": "^6.2",
2525
"symfony/service-contracts": "^1.1|^2|^3"
2626
},
2727
"require-dev": {

‎src/Symfony/Component/Mime/Email.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mime/Email.php
+15-75Lines changed: 15 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Mime\Exception\LogicException;
1515
use Symfony\Component\Mime\Part\AbstractPart;
16+
use Symfony\Component\Mime\Part\BodyFile;
1617
use Symfony\Component\Mime\Part\DataPart;
1718
use Symfony\Component\Mime\Part\Multipart\AlternativePart;
1819
use Symfony\Component\Mime\Part\Multipart\MixedPart;
@@ -326,25 +327,15 @@ public function getHtmlCharset(): ?string
326327
*/
327328
public function attach($body, string $name = null, string $contentType = null): static
328329
{
329-
if (!\is_string($body) && !\is_resource($body)) {
330-
throw new \TypeError(sprintf('The body must be a string or a resource (got "%s").', get_debug_type($body)));
331-
}
332-
333-
$this->cachedBody = null;
334-
$this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => false];
335-
336-
return $this;
330+
return $this->attachPart(new DataPart($body, $name, $contentType));
337331
}
338332

339333
/**
340334
* @return $this
341335
*/
342336
public function attachFromPath(string $path, string $name = null, string $contentType = null): static
343337
{
344-
$this->cachedBody = null;
345-
$this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => false];
346-
347-
return $this;
338+
return $this->attachPart(new DataPart(new BodyFile($path), $name, $contentType));
348339
}
349340

350341
/**
@@ -354,25 +345,15 @@ public function attachFromPath(string $path, string $name = null, string $conten
354345
*/
355346
public function embed($body, string $name = null, string $contentType = null): static
356347
{
357-
if (!\is_string($body) && !\is_resource($body)) {
358-
throw new \TypeError(sprintf('The body must be a string or a resource (got "%s").', get_debug_type($body)));
359-
}
360-
361-
$this->cachedBody = null;
362-
$this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => true];
363-
364-
return $this;
348+
return $this->attachPart((new DataPart($body, $name, $contentType))->asInline());
365349
}
366350

367351
/**
368352
* @return $this
369353
*/
370354
public function embedFromPath(string $path, string $name = null, string $contentType = null): static
371355
{
372-
$this->cachedBody = null;
373-
$this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => true];
374-
375-
return $this;
356+
return $this->attachPart((new DataPart(new BodyFile($path), $name, $contentType))->asInline());
376357
}
377358

378359
/**
@@ -381,22 +362,17 @@ public function embedFromPath(string $path, string $name = null, string $content
381362
public function attachPart(DataPart $part): static
382363
{
383364
$this->cachedBody = null;
384-
$this->attachments[] = ['part' => $part];
365+
$this->attachments[] = $part;
385366

386367
return $this;
387368
}
388369

389370
/**
390-
* @return array|DataPart[]
371+
* @return DataPart[]
391372
*/
392373
public function getAttachments(): array
393374
{
394-
$parts = [];
395-
foreach ($this->attachments as $attachment) {
396-
$parts[] = $this->createDataPart($attachment);
397-
}
398-
399-
return $parts;
375+
return $this->attachments;
400376
}
401377

402378
public function getBody(): AbstractPart
@@ -502,35 +478,23 @@ private function prepareParts(): ?array
502478
}
503479

504480
$otherParts = $relatedParts = [];
505-
foreach ($this->attachments as $attachment) {
506-
$part = $this->createDataPart($attachment);
507-
if (isset($attachment['part'])) {
508-
$attachment['name'] = $part->getName();
509-
}
510-
511-
$related = false;
481+
foreach ($this->attachments as $part) {
512482
foreach ($names as $name) {
513-
if ($name !== $attachment['name']) {
483+
if ($name !== $part->getName()) {
514484
continue;
515485
}
516486
if (isset($relatedParts[$name])) {
517487
continue 2;
518488
}
519-
$part->setDisposition('inline');
489+
520490
$html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count);
521-
if ($count) {
522-
$related = true;
523-
}
524-
$part->setName($part->getContentId());
491+
$relatedParts[$name] = $part;
492+
$part->setName($part->getContentId())->asInline();
525493

526-
break;
494+
continue 2;
527495
}
528496

529-
if ($related) {
530-
$relatedParts[$attachment['name']] = $part;
531-
} else {
532-
$otherParts[] = $part;
533-
}
497+
$otherParts[] = $part;
534498
}
535499
if (null !== $htmlPart) {
536500
$htmlPart = new TextPart($html, $this->htmlCharset, 'html');
@@ -539,24 +503,6 @@ private function prepareParts(): ?array
539503
return [$htmlPart, $otherParts, array_values($relatedParts)];
540504
}
541505

542-
private function createDataPart(array $attachment): DataPart
543-
{
544-
if (isset($attachment['part'])) {
545-
return $attachment['part'];
546-
}
547-
548-
if (isset($attachment['body'])) {
549-
$part = new DataPart($attachment['body'], $attachment['name'] ?? null, $attachment['content-type'] ?? null);
550-
} else {
551-
$part = DataPart::fromPath($attachment['path'] ?? '', $attachment['name'] ?? null, $attachment['content-type'] ?? null);
552-
}
553-
if ($attachment['inline']) {
554-
$part->asInline();
555-
}
556-
557-
return $part;
558-
}
559-
560506
/**
561507
* @return $this
562508
*/
@@ -606,12 +552,6 @@ public function __serialize(): array
606552
$this->html = (new TextPart($this->html))->getBody();
607553
}
608554

609-
foreach ($this->attachments as $i => $attachment) {
610-
if (isset($attachment['body']) && \is_resource($attachment['body'])) {
611-
$this->attachments[$i]['body'] = (new TextPart($attachment['body']))->getBody();
612-
}
613-
}
614-
615555
return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()];
616556
}
617557

‎src/Symfony/Component/Mime/MessageConverter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mime/MessageConverter.php
+1-4Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,7 @@ private static function attachParts(Email $email, array $parts): Email
114114
throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', get_debug_type($email)));
115115
}
116116

117-
$headers = $part->getPreparedHeaders();
118-
$method = 'inline' === $headers->getHeaderBody('Content-Disposition') ? 'embed' : 'attach';
119-
$name = $headers->getHeaderParameter('Content-Disposition', 'filename');
120-
$email->$method($part->getBody(), $name, $part->getMediaType().'/'.$part->getMediaSubtype());
117+
$email->attachPart($part);
121118
}
122119

123120
return $email;
+42Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mime\Part;
13+
14+
use Symfony\Component\Mime\MimeTypes;
15+
16+
/**
17+
* @author Fabien Potencier <fabien@symfony.com>
18+
*/
19+
final class BodyFile
20+
{
21+
private static $mimeTypes;
22+
23+
public function __construct(
24+
private string $path,
25+
) {
26+
}
27+
28+
public function getPath(): string
29+
{
30+
return $this->path;
31+
}
32+
33+
public function getContentType(): string
34+
{
35+
$ext = strtolower(substr($this->path, strrpos($this->path, '.') + 1));
36+
if (null === self::$mimeTypes) {
37+
self::$mimeTypes = new MimeTypes();
38+
}
39+
40+
return self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream';
41+
}
42+
}

‎src/Symfony/Component/Mime/Part/DataPart.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mime/Part/DataPart.php
+6-41Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
use Symfony\Component\Mime\Exception\InvalidArgumentException;
1515
use Symfony\Component\Mime\Header\Headers;
16-
use Symfony\Component\Mime\MimeTypes;
1716

1817
/**
1918
* @author Fabien Potencier <fabien@symfony.com>
@@ -23,22 +22,20 @@ class DataPart extends TextPart
2322
/** @internal */
2423
protected $_parent;
2524

26-
private static $mimeTypes;
27-
2825
private $filename;
2926
private $mediaType;
3027
private $cid;
31-
private $handle;
3228

33-
/**
34-
* @param resource|string $body
35-
*/
3629
public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null)
3730
{
3831
unset($this->_parent);
3932

33+
if ($body instanceof BodyFile && !$filename) {
34+
$filename = basename($body->getPath());
35+
}
36+
4037
if (null === $contentType) {
41-
$contentType = 'application/octet-stream';
38+
$contentType = $body instanceof BodyFile ? $body->getContentType() : 'application/octet-stream';
4239
}
4340
[$this->mediaType, $subtype] = explode('/', $contentType);
4441

@@ -53,32 +50,7 @@ public function __construct($body, string $filename = null, string $contentType
5350

5451
public static function fromPath(string $path, string $name = null, string $contentType = null): self
5552
{
56-
if (null === $contentType) {
57-
$ext = strtolower(substr($path, strrpos($path, '.') + 1));
58-
if (null === self::$mimeTypes) {
59-
self::$mimeTypes = new MimeTypes();
60-
}
61-
$contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream';
62-
}
63-
64-
if ((is_file($path) && !is_readable($path)) || is_dir($path)) {
65-
throw new InvalidArgumentException(sprintf('Path "%s" is not readable.', $path));
66-
}
67-
68-
if (false === $handle = @fopen($path, 'r', false)) {
69-
throw new InvalidArgumentException(sprintf('Unable to open path "%s".', $path));
70-
}
71-
72-
if (!is_file($path)) {
73-
$cache = fopen('php://temp', 'r+');
74-
stream_copy_to_stream($handle, $cache);
75-
$handle = $cache;
76-
}
77-
78-
$p = new self($handle, $name ?: basename($path), $contentType);
79-
$p->handle = $handle;
80-
81-
return $p;
53+
return new self(new BodyFile($path), $name, $contentType);
8254
}
8355

8456
/**
@@ -158,13 +130,6 @@ private function generateContentId(): string
158130
return bin2hex(random_bytes(16)).'@symfony';
159131
}
160132

161-
public function __destruct()
162-
{
163-
if (null !== $this->handle && \is_resource($this->handle)) {
164-
fclose($this->handle);
165-
}
166-
}
167-
168133
public function __sleep(): array
169134
{
170135
// converts the body to a string

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.