Skip to content

Commit f98d17b

Browse files
committed
Support lazy loading headers and header attributes
1 parent c3ec00d commit f98d17b

File tree

6 files changed

+490
-192
lines changed

6 files changed

+490
-192
lines changed

src/FileMessage.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
class FileMessage implements MessageInterface
99
{
10-
use HasFlags, HasParsedMessage;
10+
use HasFlags, HasMessageAccessors, HasParsedMessage;
1111

1212
/**
1313
* Constructor.

src/HasMessageAccessors.php

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<?php
2+
3+
namespace DirectoryTree\ImapEngine;
4+
5+
use Carbon\Carbon;
6+
use Carbon\CarbonInterface;
7+
use GuzzleHttp\Psr7\Utils;
8+
use ZBateson\MailMimeParser\Header\DateHeader;
9+
use ZBateson\MailMimeParser\Header\HeaderConsts;
10+
use ZBateson\MailMimeParser\Header\IHeader;
11+
use ZBateson\MailMimeParser\Header\IHeaderPart;
12+
use ZBateson\MailMimeParser\IMessage;
13+
use ZBateson\MailMimeParser\Message\IMessagePart;
14+
15+
trait HasMessageAccessors
16+
{
17+
/**
18+
* Parse the message into a MailMimeMessage instance.
19+
*/
20+
abstract public function parse(): IMessage;
21+
22+
/**
23+
* Get addresses from the given header.
24+
*
25+
* @return Address[]
26+
*/
27+
abstract public function addresses(string $header): array;
28+
29+
/**
30+
* Get a header from the message.
31+
*/
32+
abstract public function header(string $name, int $offset = 0): ?IHeader;
33+
34+
/**
35+
* Determine if the attachment should be treated as an embedded forwarded message.
36+
*/
37+
abstract protected function isForwardedMessage(IMessagePart $part): bool;
38+
39+
/**
40+
* Get the message date and time.
41+
*/
42+
public function date(): ?CarbonInterface
43+
{
44+
if (! $header = $this->header(HeaderConsts::DATE)) {
45+
return null;
46+
}
47+
48+
if (! $header instanceof DateHeader) {
49+
return null;
50+
}
51+
52+
if (! $date = $header->getDateTime()) {
53+
return null;
54+
}
55+
56+
return Carbon::instance($date);
57+
}
58+
59+
/**
60+
* Get the message's message-id.
61+
*/
62+
public function messageId(): ?string
63+
{
64+
return $this->header(HeaderConsts::MESSAGE_ID)?->getValue();
65+
}
66+
67+
/**
68+
* Get the message's subject.
69+
*/
70+
public function subject(): ?string
71+
{
72+
return $this->header(HeaderConsts::SUBJECT)?->getValue();
73+
}
74+
75+
/**
76+
* Get the FROM address.
77+
*/
78+
public function from(): ?Address
79+
{
80+
return head($this->addresses(HeaderConsts::FROM)) ?: null;
81+
}
82+
83+
/**
84+
* Get the SENDER address.
85+
*/
86+
public function sender(): ?Address
87+
{
88+
return head($this->addresses(HeaderConsts::SENDER)) ?: null;
89+
}
90+
91+
/**
92+
* Get the REPLY-TO address.
93+
*/
94+
public function replyTo(): ?Address
95+
{
96+
return head($this->addresses(HeaderConsts::REPLY_TO)) ?: null;
97+
}
98+
99+
/**
100+
* Get the IN-REPLY-TO message identifier(s).
101+
*
102+
* @return string[]
103+
*/
104+
public function inReplyTo(): array
105+
{
106+
$parts = $this->header(HeaderConsts::IN_REPLY_TO)?->getParts() ?? [];
107+
108+
$values = array_map(function (IHeaderPart $part) {
109+
return $part->getValue();
110+
}, $parts);
111+
112+
return array_values(array_filter($values));
113+
}
114+
115+
/**
116+
* Get the TO addresses.
117+
*
118+
* @return Address[]
119+
*/
120+
public function to(): array
121+
{
122+
return $this->addresses(HeaderConsts::TO);
123+
}
124+
125+
/**
126+
* Get the CC addresses.
127+
*
128+
* @return Address[]
129+
*/
130+
public function cc(): array
131+
{
132+
return $this->addresses(HeaderConsts::CC);
133+
}
134+
135+
/**
136+
* Get the BCC addresses.
137+
*
138+
* @return Address[]
139+
*/
140+
public function bcc(): array
141+
{
142+
return $this->addresses(HeaderConsts::BCC);
143+
}
144+
145+
/**
146+
* Get the message's HTML content.
147+
*/
148+
public function html(): ?string
149+
{
150+
return $this->parse()->getHtmlContent();
151+
}
152+
153+
/**
154+
* Get the message's text content.
155+
*/
156+
public function text(): ?string
157+
{
158+
return $this->parse()->getTextContent();
159+
}
160+
161+
/**
162+
* Get the message's attachments.
163+
*
164+
* @return Attachment[]
165+
*/
166+
public function attachments(): array
167+
{
168+
$attachments = [];
169+
170+
foreach ($this->parse()->getAllAttachmentParts() as $part) {
171+
if ($this->isForwardedMessage($part)) {
172+
$attachments = array_merge($attachments, (new FileMessage($part->getContent()))->attachments());
173+
} else {
174+
$attachments[] = new Attachment(
175+
$part->getFilename(),
176+
$part->getContentId(),
177+
$part->getContentType(),
178+
$part->getContentDisposition(),
179+
$part->getBinaryContentStream() ?? Utils::streamFor(''),
180+
);
181+
}
182+
}
183+
184+
return $attachments;
185+
}
186+
187+
/**
188+
* Determine if the message has attachments.
189+
*/
190+
public function hasAttachments(): bool
191+
{
192+
return $this->attachmentCount() > 0;
193+
}
194+
195+
/**
196+
* Get the count of attachments.
197+
*/
198+
public function attachmentCount(): int
199+
{
200+
return $this->parse()->getAttachmentCount();
201+
}
202+
}

0 commit comments

Comments
 (0)