NodeCollectionBuilder::mergeNodeCollections()   C
last analyzed

Complexity

Conditions 16
Paths 29

Size

Total Lines 48
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 30
c 1
b 0
f 0
dl 0
loc 48
rs 5.5666
cc 16
nc 29
nop 2

How to fix   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
declare(strict_types=1);
3
4
namespace Pluswerk\TypoScriptAutoFixer\Fixer\NestingConsistency;
5
6
class NodeCollectionBuilder
7
{
8
    /**
9
     * @param NodeCollection $nodesA
10
     * @param NodeCollection $nodesB
11
     *
12
     * @return NodeCollection
13
     */
14
    public function mergeNodeCollections(NodeCollection $nodesA, NodeCollection $nodesB): NodeCollection
15
    {
16
        foreach ($nodesB as $node) {
17
            if (!$nodesA->hasNode($node->identifier())) {
18
                $nodesA->add($node);
19
                continue;
20
            }
21
22
            if ($nodesA->getNode($node->identifier())->hasValue() && $nodesB->getNode($node->identifier())->hasValue()) {
23
                throw new \RuntimeException('Overwrite assignment!');
24
            }
25
26
            if ($nodesA->getNode($node->identifier())->hasChildren() && $nodesB->getNode($node->identifier())->hasChildren()) {
27
                $col = $this->mergeNodeCollections($nodesA->getNode($node->identifier())->children(), $nodesB->getNode($node->identifier())->children());
28
29
                $value = '';
30
                $operator = null;
31
32
                if ($nodesA->getNode($node->identifier())->value() !== null) {
33
                    $value = $nodesA->getNode($node->identifier())->value();
34
                } elseif ($nodesB->getNode($node->identifier())->value() !== null) {
35
                    $value = $nodesB->getNode($node->identifier())->value();
36
                }
37
38
                if ($nodesA->getNode($node->identifier())->operator() !== null) {
39
                    $operator = $nodesA->getNode($node->identifier())->operator();
40
                } elseif ($nodesB->getNode($node->identifier())->value() !== null) {
41
                    $operator = $nodesB->getNode($node->identifier())->operator();
42
                }
43
44
                $subNode = new Node($node->identifier(), $value, $operator);
45
                $subNode->updateCollection($col);
46
                $nodesA->add($subNode);
47
            } elseif ($nodesA->getNode($node->identifier())->hasValue() && $nodesB->getNode($node->identifier())->hasChildren()) {
48
                $nodesA->getNode($node->identifier())->updateCollection($nodesB->getNode($node->identifier())->children());
49
            } elseif ($nodesA->getNode($node->identifier())->hasChildren() && $nodesB->getNode($node->identifier())->hasValue()) {
50
                $newNode = new Node($node->identifier(), $nodesB->getNode($node->identifier())->value(), $nodesB->getNode($node->identifier())->operator());
51
                $newNode->updateCollection($nodesA->getNode($node->identifier())->children());
52
                $nodesA->add($newNode);
53
            }
54
        }
55
56
        // Update node levels for whole tree
57
        foreach ($nodesA as $node) {
58
            $node->updateLevel(0);
59
        }
60
61
        return $nodesA;
62
    }
63
64
    /**
65
     * @param string $string
66
     *
67
     * @return NodeCollection
68
     */
69
    public function buildNodeCollectionFromSingleAssignment(string $string): NodeCollection
70
    {
71
        $assignment = new Assignment($string);
72
        return $this->buildNodeCollectionFromAssignment($assignment);
73
    }
74
75
    /**
76
     * @param array $lines
77
     *
78
     * @return NodeCollection
79
     * @todo Refactor this method somehow... it's still ugly
80
     */
81
    public function buildNodeCollectionFromMultiLine(array $lines): NodeCollection
82
    {
83
        $nodeCollection = new NodeCollection();
84
85
        $assignments = [];
86
        $prefixes = [];
87
        $level = 0;
88
        $inMultiLineValue = false;
89
        $multiLineValue = '';
90
        $leftValue = '';
91
        foreach ($lines as $line) {
92
            if (!$inMultiLineValue) {
93
                $line = trim($line);
94
            }
95
            if ($inMultiLineValue) {
96
                if (substr(trim($line), -1, 1) === ')') {
97
                    $lineString = (empty($prefixes))
98
                        ? $leftValue . '(' . PHP_EOL . $multiLineValue . ')'
99
                        : implode('.', $prefixes) . '.' . $leftValue . '(' . PHP_EOL . $multiLineValue . ')';
100
                    $assignments[] = new Assignment($lineString);
101
                    $multiLineValue = '';
102
                    $leftValue = '';
103
                    $inMultiLineValue = false;
104
                } else {
105
                    $multiLineValue .= $line;
106
                }
107
            } elseif (substr(trim($line), -1, 1) === '{') {
108
                $prefixes[$level] = trim(rtrim($line, '{'));
109
                $level++;
110
            } elseif (substr(trim($line), -1, 1) === '}') {
111
                $level--;
112
                unset($prefixes[$level]);
113
            } elseif (substr(trim($line), -1, 1) === '(') {
114
                $leftValue = trim(rtrim(trim($line), '('));
115
                $inMultiLineValue = true;
116
            } elseif (trim($line) !== '') {
117
                $lineString = (empty($prefixes))
118
                    ? trim(rtrim($line, '{'))
119
                    : implode('.', $prefixes) . '.' . trim(rtrim($line, '{'));
120
                $assignments[] = new Assignment($lineString);
121
            }
122
        }
123
124
        foreach ($assignments as $assignment) {
125
            $nodeCollection = $this->mergeNodeCollections($nodeCollection, $this->buildNodeCollectionFromAssignment($assignment));
126
        }
127
128
        return $nodeCollection;
129
    }
130
131
    /**
132
     * @param \Pluswerk\TypoScriptAutoFixer\Fixer\NestingConsistency\Assignment $assignment
133
     *
134
     * @return NodeCollection
135
     */
136
    private function buildNodeCollectionFromAssignment(Assignment $assignment): NodeCollection
137
    {
138
        $node = null;
139
        $childNode = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $childNode is dead and can be removed.
Loading history...
140
        $nodeCollection = new NodeCollection();
141
142
        foreach ($assignment->identifier()->reverseItems() as $item) {
143
            if ($node === null) {
144
                $tmpNode = new Node($item, $assignment->value(), $assignment->operator());
145
                $node = $tmpNode;
146
            } else {
147
                $tmpNode = new Node($item);
148
                $tmpNode->addChildNode($node);
0 ignored issues
show
Bug introduced by
$node of type null is incompatible with the type Pluswerk\TypoScriptAutoF...NestingConsistency\Node expected by parameter $childNode of Pluswerk\TypoScriptAutoF...cy\Node::addChildNode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

148
                $tmpNode->addChildNode(/** @scrutinizer ignore-type */ $node);
Loading history...
149
                $node = $tmpNode;
150
            }
151
        }
152
153
        $nodeCollection->add($node);
0 ignored issues
show
Bug introduced by
It seems like $node can also be of type null; however, parameter $node of Pluswerk\TypoScriptAutoF...y\NodeCollection::add() does only seem to accept Pluswerk\TypoScriptAutoF...NestingConsistency\Node, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

153
        $nodeCollection->add(/** @scrutinizer ignore-type */ $node);
Loading history...
154
        return $nodeCollection;
155
    }
156
}
157