Completed
Pull Request — master (#50)
by Frederik
02:46
created

FixedQuotation::quoteHtml()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 55
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 7.2269

Importance

Changes 0
Metric Value
dl 0
loc 55
ccs 30
cts 36
cp 0.8333
rs 7.8235
c 0
b 0
f 0
cc 7
eloc 37
nc 10
nop 3
crap 7.2269

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace Genkgo\Mail\Quote;
5
6
use Genkgo\Mail\Address;
7
use Genkgo\Mail\AlternativeText;
8
use Genkgo\Mail\MessageBodyCollection;
9
use Genkgo\Mail\MessageInterface;
10
use Genkgo\Mail\QuotationInterface;
11
12
final class FixedQuotation implements QuotationInterface
13
{
14
    /**
15
     * @var string
16
     */
17
    private $headerText;
18
19
    /**
20
     * @param string $headerText
21
     */
22 8
    public function __construct(string $headerText = '%s (%s):')
23
    {
24 8
        $this->headerText = $headerText;
25 8
    }
26
27
    /**
28
     * @param MessageBodyCollection $body
29
     * @param MessageInterface $originalMessage
30
     * @return MessageBodyCollection
31
     * @throws \DOMException
32
     */
33 8
    public function quote(MessageBodyCollection $body, MessageInterface $originalMessage): MessageBodyCollection
34
    {
35 8
        $originalBody = MessageBodyCollection::extract($originalMessage);
36 8
        $dateString = 'unknown';
37 8
        foreach ($originalMessage->getHeader('Date') as $header) {
38
            try {
39 1
                $date = new \DateTimeImmutable($header->getValue()->getRaw());
40 1
                $dateString = \IntlDateFormatter::create(
41 1
                    \Locale::getDefault(),
42 1
                    \IntlDateFormatter::MEDIUM,
43 1
                    \IntlDateFormatter::MEDIUM
44 1
                )->format($date);
45 1
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
46
            }
47
        }
48
49 8
        $fromString = '';
50 8
        foreach ($originalMessage->getHeader('From') as $header) {
51 8
            $from = Address::fromString($header->getValue()->getRaw());
52 8
            $fromString = $from->getName() ? $from->getName() : (string)$from->getAddress();
53
        }
54
55 8
        $headerText = \sprintf($this->headerText, $fromString, $dateString);
56
57
        return $body
58 8
            ->withHtmlAndNoGeneratedAlternativeText(
59 8
                $this->quoteHtml(
60 8
                    $body->getHtml(),
61 8
                    $originalBody->getHtml(),
62 8
                    $headerText
63
                )
64
            )
65 8
            ->withAlternativeText($this->quoteText($body->getText(), $originalBody->getText()));
66
    }
67
68
    /**
69
     * @param string $newHtml
70
     * @param string $originalHtml
71
     * @param string $headerText
72
     * @return string
73
     * @throws \DOMException
74
     */
75 8
    private function quoteHtml(string $newHtml, string $originalHtml, string $headerText): string
76
    {
77 8
        $originalHtml = \trim($originalHtml);
78 8
        if ($originalHtml === '') {
79
            return '';
80
        }
81
82 8
        $document = new \DOMDocument();
83 8
        $document->substituteEntities = false;
84 8
        $document->resolveExternals = false;
85
86 8
        $result = @$document->loadHTML($originalHtml);
87 8
        if ($result === false) {
88
            throw new \DOMException('Incorrect HTML');
89
        }
90
91 8
        $query = new \DOMXPath($document);
92 8
        $removeItems = $query->query('//head|//script|//body/@style|//html/@style', $document->documentElement);
93
        /** @var \DOMElement $removeItem */
94 8
        foreach ($removeItems as $removeItem) {
95
            $parent = $removeItem->parentNode;
96
            $parent->removeChild($removeItem);
97
        }
98
99 8
        $body = $document->getElementsByTagName('body');
100 8
        $quote = $document->createElement('blockquote');
101 8
        $quote->setAttribute('type', 'cite');
102
103 8
        if ($body->length === 0) {
104
            $quote->appendChild($document->removeChild($document->documentElement));
105
        } else {
106 8
            $root = $body->item(0);
107 8
            while ($root->childNodes->length !== 0) {
108 8
                $quote->appendChild($root->childNodes->item(0));
109
            }
110
        }
111
112 8
        $newDocument = new \DOMDocument();
113 8
        $newDocument->substituteEntities = false;
114 8
        $newDocument->resolveExternals = false;
115 8
        $result = @$newDocument->loadHTML($newHtml, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
116 8
        if ($result === false) {
117
            throw new \DOMException('Incorrect HTML');
118
        }
119
120 8
        $quotedNode = $newDocument->importNode($quote, true);
121 8
        $newBody = $this->prepareBody($newDocument);
122 8
        $newBody->appendChild($quotedNode);
123
124 8
        $header = $newDocument->createElement('p');
125 8
        $header->textContent = $headerText;
126
127 8
        $quotedNode->parentNode->insertBefore($header, $quotedNode);
128 8
        return \trim($newDocument->saveHTML());
129
    }
130
131
    /**
132
     * @param \DOMDocument $document
133
     * @return \DOMElement
134
     */
135 8
    private function prepareBody(\DOMDocument $document): \DOMElement
136
    {
137 8
        $bodyList = $document->getElementsByTagName('body');
138 8
        if ($bodyList->length === 0) {
139
            $html = $document->createElement('html');
140
            $body = $document->createElement('body');
141
            $html->appendChild($body);
142
            $body->appendChild($document->documentElement);
143
            $document->removeChild($document->documentElement);
144
            $document->appendChild($html);
145
            return $body;
146
        }
147
148 8
        $body = $bodyList->item(0);
149
150 8
        $queryHtml = new \DOMXPath($document);
151 8
        $htmlTags = $queryHtml->query('//html');
152 8
        if ($htmlTags->length > 0) {
153 8
            $html = $htmlTags->item(0);
154 8
            $html->appendChild($body);
155 8
            $document->removeChild($document->documentElement);
156 8
            $document->appendChild($html);
157 8
            return $body;
158
        }
159
160
        $html = $document->createElement('html');
161
        $html->appendChild($body);
162
        $document->removeChild($document->documentElement);
163
        $document->appendChild($html);
164
        return $body;
165
    }
166
167
    /**
168
     * @param AlternativeText $newText
169
     * @param AlternativeText $originalText
170
     * @return AlternativeText
171
     */
172 8
    private function quoteText(AlternativeText $newText, AlternativeText $originalText): AlternativeText
0 ignored issues
show
Unused Code introduced by
The parameter $newText is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
173
    {
174 8
        return $originalText;
175
    }
176
}
177