Completed
Push — master ( ddfb7b...c3a867 )
by Michele
04:20
created

Tree::fromString()   D

Complexity

Conditions 10
Paths 16

Size

Total Lines 41
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 41
ccs 0
cts 29
cp 0
rs 4.8196
cc 10
eloc 31
nc 16
nop 2
crap 110

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
3
namespace CHMLib\TOCIndex;
4
5
use CHMLib\CHM;
6
use CHMLib\Map;
7
use DOMDocument;
8
use DOMElement;
9
use DOMXpath;
10
use Exception;
11
12
/**
13
 * A list of items in the TOC or in the Index of an CHM file.
14
 */
15
class Tree
16
{
17
    /**
18
     * The parent CHM instance.
19
     *
20
     * @var CHM
21
     */
22
    protected $chm;
23
24
    /**
25
     * List of Item instances children of this tree.
26
     *
27
     * @var Item[]
28
     */
29
    protected $items;
30
31
    /**
32
     * Initializes the instance.
33
     */
34
    protected function __construct(CHM $chm)
35
    {
36
        $this->chm = $chm;
37
        $this->items = array();
38
    }
39
40
    /**
41
     * Get the items contained in this tree.
42
     *
43
     * @return Item[]
44
     */
45
    public function getItems()
46
    {
47
        return $this->items;
48
    }
49
50
    /**
51
     * Resolve the items contained in other CHM files.
52
     *
53
     * @param Map $map
54
     *
55
     * @throws Exception Throw an Exception in case of errors.
56
     */
57
    public function resolve(Map $map)
58
    {
59
        $result = array();
60
        foreach ($this->items as $item) {
61
            $merge = $item->getMerge();
62
            if ($merge === null) {
63
                $result[] = $item;
64
            } else {
65
                $result = array_merge($result, $item->resolve($map));
66
            }
67
        }
68
69
        $this->items = $result;
70
    }
71
72
    /**
73
     * Create a new instance starting from an UL element.
74
     *
75
     * @param CHM $chm The parent CHM instance.
76
     * @param DOMElement $ul The UL element to be parsed.
77
     *
78
     * @throws Exception Throw an Exception in case of errors.
79
     *
80
     * @return static
81
     */
82
    public static function fromUL(CHM $chm, DOMElement $ul)
83
    {
84
        $result = new static($chm);
85
        foreach ($ul->childNodes as $li) {
86
            if ($li instanceof DOMElement && strcasecmp($li->tagName, 'li') === 0) {
87
                $result->items = array_merge($result->items, Item::fromLI($chm, $li));
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($result->ite...tem::fromLI($chm, $li)) of type array is incompatible with the declared type array<integer,object<CHMLib\TOCIndex\Item>> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
88
            }
89
        }
90
91
        return $result;
92
    }
93
94
    /**
95
     * Create a new instance starting from the whole TOC/Index source 'HTML'.
96
     *
97
     * @param CHM $chm The parent CHM instance.
98
     * @param string $data The contents of the .hhc/.hhk file.
99
     *
100
     * @throws Exception Throw an Exception in case of errors.
101
     *
102
     * @return static
103
     */
104
    public static function fromString(CHM $chm, $data)
105
    {
106
        if (!class_exists('DOMDocument', false) || !class_exists('DOMXpath', false)) {
107
            throw new Exception('Missing PHP extension: php-xml');
108
        }
109
        $data = trim((string) $data);
110
        $doc = new DOMDocument();
111
        $charset = 'UTF-8';
112
        if (preg_match('/^<\?xml\s+encoding\s*=\s*"([^"]+)"/i', $data, $m)) {
113
            $charset = $m[1];
0 ignored issues
show
Unused Code introduced by
$charset is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
114
        } else {
115
            if (preg_match('/<meta\s+http-equiv\s*=\s*"Content-Type"\s+content\s*=\s*"text\/html;\s*charset=([^"]+)">/i', $data, $m)) {
116
                $charset = $m[1];
117
            }
118
            $data = '<?xml encoding="'.$charset.'">'.$data;
119
        }
120
        if (@$doc->loadHTML($data) !== true) {
121
            throw new Exception('Failed to parse the .hhc/.hhk file contents');
122
        }
123
        $xpath = new DOMXpath($doc);
124
        $elements = $xpath->query('/html/body/ul');
125
        switch ($elements->length) {
126
            case 0:
127
                $elements = $xpath->query('/html/body/object[@type="text/sitemap"]');
128
                if ($elements->length === 0) {
129
                    throw new Exception('No root list in the .hhc/.hhk file contents');
130
                }
131
                $result = new static($chm);
132
                foreach ($elements as $object) {
133
                    $result->items[] = Item::fromObject($chm, $object);
134
                }
135
                break;
136
            case 1:
137
                $result = static::fromUL($chm, $elements->item(0));
138
                break;
139
            default:
140
                throw new Exception('More that one root list in the .hhc/.hhk file contents');
141
        }
142
143
        return $result;
144
    }
145
}
146