Skip to content

Commit

Permalink
Method to get all html parts and complete html body (#557)
Browse files Browse the repository at this point in the history
Co-authored-by: Arwin <[email protected]>
  • Loading branch information
arwinvdv and arwinvdv authored Feb 17, 2023
1 parent 92647fd commit 392fa57
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ composer.lock
phpunit.xml
wait-for-it
coverage/

.DS_Store
14 changes: 8 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,19 @@
],
"require": {
"php": "~8.1.0 || ~8.2.0",
"ext-dom": "*",
"ext-iconv": "*",
"ext-imap": "*",
"ext-libxml": "*",
"ext-mbstring": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.13.2",
"laminas/laminas-mail": "^2.21.1",
"phpstan/phpstan": "^1.9.8",
"phpstan/phpstan-phpunit": "^1.3.3",
"phpstan/phpstan-strict-rules": "^1.4.4",
"phpunit/phpunit": "^9.5.27"
"friendsofphp/php-cs-fixer": "^3.14.4",
"laminas/laminas-mail": "^2.22.0",
"phpstan/phpstan": "^1.9.17",
"phpstan/phpstan-phpunit": "^1.3.4",
"phpstan/phpstan-strict-rules": "^1.4.5",
"phpunit/phpunit": "^9.6.3"
},
"autoload": {
"psr-4": {
Expand Down
62 changes: 57 additions & 5 deletions src/Message/AbstractMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,23 +203,75 @@ final public function getReferences(): array
}

/**
* Get body HTML.
* Get first body HTML part.
*/
final public function getBodyHtml(): ?string
{
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
$htmlParts = $this->getBodyHtmlParts();

return $htmlParts[0] ?? null;
}

/**
* Get body HTML parts.
*
* @return string[]
*/
final public function getBodyHtmlParts(): array
{
$iterator = new \RecursiveIteratorIterator($this, \RecursiveIteratorIterator::SELF_FIRST);
$htmlParts = [];
foreach ($iterator as $part) {
if (self::SUBTYPE_HTML === $part->getSubtype()) {
return $part->getDecodedContent();
$htmlParts[] = $part->getDecodedContent();
}
}
if (\count($htmlParts) > 0) {
return $htmlParts;
}

// If message has no parts and is HTML, return content of message itself.
if (self::SUBTYPE_HTML === $this->getSubtype()) {
return $this->getDecodedContent();
return [$this->getDecodedContent()];
}

return null;
return [];
}

/**
* Get all body HTML parts merged into 1 html.
*/
final public function getCompleteBodyHtml(): ?string
{
$htmlParts = $this->getBodyHtmlParts();

if (1 === \count($htmlParts)) {
return $htmlParts[0];
}
if (0 === \count($htmlParts)) {
return null;
}
\libxml_use_internal_errors(true); // Suppress parse errors, get errors with libxml_get_errors();

$newDom = new \DOMDocument();

$newBody = '';
$newDom->loadHTML(\implode('', $htmlParts));

$bodyTags = $newDom->getElementsByTagName('body');

foreach ($bodyTags as $body) {
foreach ($body->childNodes as $node) {
$newBody .= $newDom->saveHTML($node);
}
}

$newDom = new \DOMDocument();
$newDom->loadHTML($newBody);

$completeHtml = $newDom->saveHTML();

return false === $completeHtml ? null : $completeHtml;
}

/**
Expand Down
16 changes: 15 additions & 1 deletion src/Message/BasicMessageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,26 @@ public function getInReplyTo(): array;
public function getReferences(): array;

/**
* Get body HTML.
* Get first body HTML part.
*
* @return null|string Null if message has no HTML message part
*/
public function getBodyHtml(): ?string;

/**
* Get all body HTML parts as array.
*
* @return string[]
*/
public function getBodyHtmlParts(): array;

/**
* Get all body HTML parts merged into 1 html.
*
* @return null|string Null if message has no HTML message part
*/
public function getCompleteBodyHtml(): ?string;

/**
* Get body text.
*/
Expand Down
51 changes: 51 additions & 0 deletions tests/MessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,57 @@ public function testNestesEmbeddedWithAttachment(): void
}
}

public function testMultipleHtmlParts(): void
{
$this->mailbox->addMessage($this->getFixture('multiple_html_parts_and_attachments'));

$message = $this->mailbox->getMessage(1);

// Test attachments
$expectedFileNames = [
'attachment1.pdf',
'attachment2.pdf',
];
$attachments = $message->getAttachments();
static::assertCount(2, $attachments);
foreach ($attachments as $attachment) {
static::assertContains($attachment->getFilename(), $expectedFileNames);
}

// Test html parts
static::assertCount(3, $message->getBodyHtmlParts());

// Test html parts
$completeBody = $message->getCompleteBodyHtml();
$completeBody = null === $completeBody ? '' : $completeBody;

static::assertStringContainsString('first', $completeBody);
static::assertStringContainsString('second', $completeBody);
static::assertStringContainsString('last', $completeBody);
}

public function testBodyHtmlEmpty(): void
{
$this->mailbox->addMessage($this->getFixture('plain_only'));

$message = $this->mailbox->getMessage(1);

static::assertCount(0, $message->getBodyHtmlParts());

static::assertNull($message->getCompleteBodyHtml());
}

public function testBodyHtmlOnePart(): void
{
$this->mailbox->addMessage($this->getFixture('html_only'));

$message = $this->mailbox->getMessage(1);

static::assertCount(1, $message->getBodyHtmlParts());

static::assertNotNull($message->getCompleteBodyHtml());
}

public function testImapMimeHeaderDecodeReturnsFalse(): void
{
$this->mailbox->addMessage($this->getFixture('imap_mime_header_decode_returns_false'));
Expand Down
Loading

0 comments on commit 392fa57

Please sign in to comment.