Passed
Push — master ( 0d07bf...dd4616 )
by Steve
35s
created

HtmlSaxDiffOutput::generateOutput()   F

Complexity

Conditions 38
Paths 1140

Size

Total Lines 95
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 65
CRAP Score 38.8712

Importance

Changes 0
Metric Value
cc 38
eloc 73
nc 1140
nop 1
dl 0
loc 95
ccs 65
cts 71
cp 0.9155
crap 38.8712
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
/**
3
 * (c) Steve Nebes <[email protected]>
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
declare(strict_types=1);
10
11
namespace SN\DaisyDiff\Html;
12
13
use SN\DaisyDiff\Html\Dom\ImageNode;
14
use SN\DaisyDiff\Html\Dom\TagNode;
15
use SN\DaisyDiff\Html\Dom\TextNode;
16
use SN\DaisyDiff\Html\Modification\Modification;
17
use SN\DaisyDiff\Html\Modification\ModificationType;
18
use SN\DaisyDiff\Output\DiffOutputInterface;
19
use SN\DaisyDiff\Xml\ContentHandlerInterface;
20
21
/**
22
 * Takes a branch root and creates an HTML file for it.
23
 *
24
 * @internal
25
 */
26
class HtmlSaxDiffOutput implements DiffOutputInterface
27
{
28
    /** @var ContentHandlerInterface */
29
    private $handler;
30
31
    /**
32
     * @param ContentHandlerInterface $handler
33
     */
34 29
    public function __construct(ContentHandlerInterface $handler)
35
    {
36 29
        $this->handler = $handler;
37 29
    }
38
39
    /**
40
     * @param TagNode $node
41
     */
42 29
    public function generateOutput(TagNode $node): void
43
    {
44 29
        if ('img' !== $node->getQName() && 'body' !== $node->getQName()) {
45 29
            $this->handler->startElement($node->getQName(), $node->getAttributes());
46
        }
47
48 29
        $newStarted = false;
49 29
        $remStarted = false;
50 29
        $changeStarted = false;
51 29
        $conflictStarted = false;
52 29
        $changeText = '';
53
54 29
        foreach ($node as $child) {
55 29
            if ($child instanceof TagNode) {
56 15
                if ($newStarted) {
57
                    $this->handler->endElement('ins');
58
                    $newStarted = false;
59 15
                } elseif ($changeStarted) {
60 1
                    $this->handler->endElement('span');
61 1
                    $changeStarted = false;
62 15
                } elseif ($remStarted) {
63
                    $this->handler->endElement('del');
64
                    $remStarted = false;
65 15
                } elseif ($conflictStarted) {
66
                    $this->handler->endElement('span');
67
                    $conflictStarted = false;
68
                }
69
70 15
                $this->generateOutput($child);
71 29
            } elseif ($child instanceof TextNode) {
72 29
                $mod = $child->getModification();
73
74 29
                if ($newStarted && ($mod->getOutputType() !== ModificationType::ADDED || $mod->isFirstOfId())) {
75 7
                    $this->handler->endElement('ins');
76 7
                    $newStarted = false;
77
                } elseif (
78 29
                    $changeStarted && (
79 2
                        $mod->getOutputType() !== ModificationType::CHANGED ||
80 1
                        $mod->getChanges() !== $changeText ||
81 29
                        $mod->isFirstOfId()
82
                    )
83
                ) {
84 2
                    $this->handler->endElement('span');
85 2
                    $changeStarted = false;
86 29
                } elseif ($remStarted && ($mod->getOutputType() !== ModificationType::REMOVED || $mod->isFirstOfId())) {
87 6
                    $this->handler->endElement('del');
88 6
                    $remStarted = false;
89
                } elseif (
90 29
                    $conflictStarted &&
91 29
                    ($mod->getOutputType() !== ModificationType::CONFLICT || $mod->isFirstOfId())
92
                ) {
93 2
                    $this->handler->endElement('span');
94 2
                    $conflictStarted = false;
95
                }
96
97
                // No else because a removed part can just be closed and a new part can start.
98 29
                if (!$newStarted && $mod->getOutputType() === ModificationType::ADDED) {
99 12
                    $attrs = ['class' => 'diff-html-added'];
100 12
                    $this->handler->startElement('ins', $attrs);
101 12
                    $newStarted = true;
102 28
                } elseif (!$changeStarted && $mod->getOutputType() === ModificationType::CHANGED) {
103 3
                    $attrs = ['class' => 'diff-html-changed'];
104 3
                    $this->handler->startElement('span', $attrs);
105 3
                    $changeStarted = true;
106 3
                    $changeText = $mod->getChanges();
107 27
                } elseif (!$remStarted && $mod->getOutputType() === ModificationType::REMOVED) {
108 12
                    $attrs = ['class' => 'diff-html-removed'];
109 12
                    $this->handler->startElement('del', $attrs);
110 12
                    $remStarted = true;
111 23
                } elseif (!$conflictStarted && $mod->getOutputType() === ModificationType::CONFLICT) {
112 4
                    $attrs = ['class' => 'diff-html-conflict'];
113 4
                    $this->handler->startElement('span', $attrs);
114 4
                    $conflictStarted = true;
115
                }
116
117 29
                if ($child instanceof ImageNode) {
118 9
                    $this->writeImage($child);
119
                } else {
120 29
                    $this->handler->characters($child->getText());
121
                }
122
            }
123
        }
124
125 29
        if ($newStarted) {
126 6
            $this->handler->endElement('ins');
127 27
        } elseif ($changeStarted) {
128 3
            $this->handler->endElement('span');
129 27
        } elseif ($remStarted) {
130 7
            $this->handler->endElement('del');
131 24
        } elseif ($conflictStarted) {
132 2
            $this->handler->endElement('span');
133
        }
134
135 29
        if ('img' !== $node->getQName() && 'body' !== $node->getQName()) {
136 29
            $this->handler->endElement($node->getQName());
137
        }
138 29
    }
139
140
    /**
141
     * @param ImageNode $imageNode
142
     */
143 9
    private function writeImage(ImageNode $imageNode): void
144
    {
145 9
        $attrs = $imageNode->getAttributes();
146
147 9
        if ($imageNode->getModification()->getOutputType() === ModificationType::REMOVED) {
148 2
            $attrs['changeType'] = 'diff-removed-image';
149 7
        } elseif ($imageNode->getModification()->getOutputType() === ModificationType::ADDED) {
150 3
            $attrs['changeType'] = 'diff-added-image';
151 4
        } elseif ($imageNode->getModification()->getOutputType() === ModificationType::CONFLICT) {
152 2
            $attrs['changeType'] = 'diff-conflict-image';
153
        }
154
155 9
        $this->handler->startElement('img', $attrs);
156 9
        $this->handler->endElement('img');
157 9
    }
158
}
159