Skip to content

Commit

Permalink
bug swiftmailer#907 Fix sorting MIME children when their types are eq…
Browse files Browse the repository at this point in the history
…ual (Hans Adema)

This PR was squashed before being merged into the 5.x branch (closes swiftmailer#907).

Discussion
----------

Fix sorting MIME children when their types are equal

Currently, if a message has two MIME children with the same content type, they will be added in their inverted order. In most cases, this won't matter, but for some e-mails (like X-ARF, which has two text/plain parts, one with human readable and one with YAML content), this is problematic.

This small fix ensures the original ordering is preserved when the typePrefs are identical.

Commits
-------

fe6f150 Fix sorting MIME children when their types are equal
  • Loading branch information
fabpot committed May 1, 2017
2 parents 06541c8 + fe6f150 commit a2caa64
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 11 deletions.
25 changes: 14 additions & 11 deletions lib/classes/Swift/Mime/SimpleMimeEntity.php
Expand Up @@ -786,20 +786,23 @@ private function _sortChildren()

// Sort in order of preference, if there is one
if ($shouldSort) {
usort($this->_immediateChildren, array($this, '_childSortAlgorithm'));
}
}
// Group the messages by order of preference
$sorted = array();
foreach ($this->_immediateChildren as $child) {
$type = $child->getContentType();
$level = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1;

private function _childSortAlgorithm($a, $b)
{
$typePrefs = array();
$types = array(strtolower($a->getContentType()), strtolower($b->getContentType()));
if (empty($sorted[$level])) {
$sorted[$level] = array();
}

foreach ($types as $type) {
$typePrefs[] = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1;
}
$sorted[$level][] = $child;
}

return $typePrefs[0] >= $typePrefs[1] ? 1 : -1;
ksort($sorted);

$this->_immediateChildren = array_reduce($sorted, 'array_merge', array());
}
}

/**
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/Swift/Mime/AbstractMimeEntityTest.php
Expand Up @@ -740,6 +740,46 @@ public function testOrderingTextBeforeHtml()
);
}

public function testOrderingEqualContentTypesMaintainsOriginalOrdering()
{
$firstChild = new MimeEntityFixture(Swift_Mime_MimeEntity::LEVEL_ALTERNATIVE,
"Content-Type: text/plain\r\n".
"\r\n".
'PART 1',
'text/plain'
);
$secondChild = new MimeEntityFixture(Swift_Mime_MimeEntity::LEVEL_ALTERNATIVE,
"Content-Type: text/plain\r\n".
"\r\n".
'PART 2',
'text/plain'
);
$headers = $this->_createHeaderSet(array(), false);
$headers->shouldReceive('toString')
->zeroOrMoreTimes()
->andReturn("Content-Type: multipart/alternative; boundary=\"xxx\"\r\n");

$entity = $this->_createEntity($headers, $this->_createEncoder(),
$this->_createCache()
);
$entity->setBoundary('xxx');
$entity->setChildren(array($firstChild, $secondChild));

$this->assertEquals(
"Content-Type: multipart/alternative; boundary=\"xxx\"\r\n".
"\r\n\r\n--xxx\r\n".
"Content-Type: text/plain\r\n".
"\r\n".
'PART 1'.
"\r\n\r\n--xxx\r\n".
"Content-Type: text/plain\r\n".
"\r\n".
'PART 2'.
"\r\n\r\n--xxx--\r\n",
$entity->toString()
);
}

public function testUnsettingChildrenRestoresContentType()
{
$cType = $this->_createHeader('Content-Type', 'text/plain', array(), false);
Expand Down

0 comments on commit a2caa64

Please sign in to comment.