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

Item::resolve()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 20
ccs 0
cts 13
cp 0
rs 9.2
cc 4
eloc 14
nc 4
nop 1
crap 20
1
<?php
2
3
namespace CHMLib\TOCIndex;
4
5
use CHMLib\CHM;
6
use CHMLib\Map;
7
use DOMElement;
8
use Exception;
9
10
/**
11
 * A list of items in the TOC or in the Index of an CHM file.
12
 */
13
class Item
14
{
15
    /**
16
     * The parent CHM instance.
17
     *
18
     * @var CHM
19
     */
20
    protected $chm;
21
22
    /**
23
     * The name of the tree item.
24
     *
25
     * @var string
26
     */
27
    protected $name;
28
29
    /**
30
     * The keyword of the tree item.
31
     *
32
     * @var string
33
     */
34
    protected $keyword;
35
36
    /**
37
     * The local path to the tree item.
38
     *
39
     * @var string
40
     */
41
    protected $local;
42
43
    /**
44
     * The path to an entry in another CHM file.
45
     *
46
     * @var array|null If not null, it's an array with two keys: 'chm' and 'entry'.
47
     */
48
    protected $merge;
49
50
    /**
51
     * The image number attribute.
52
     *
53
     * @var int|null
54
     */
55
    protected $imageNumber;
56
57
    /**
58
     * The sub-elements of this Item.
59
     *
60
     * @var Tree|null
61
     */
62
    protected $subTree;
63
64
    /**
65
     * Initializes the instance.
66
     *
67
     * @param CHM $chm The parent CHM instance.
68
     */
69
    protected function __construct(CHM $chm)
70
    {
71
        $this->chm = $chm;
72
        $this->name = '';
73
        $this->keyword = '';
74
        $this->local = '';
75
        $this->merge = null;
76
        $this->imageNumber = null;
77
        $this->subTree = null;
78
    }
79
80
    /**
81
     * Get the name of the tree item.
82
     *
83
     * @return string
84
     */
85
    public function getName()
86
    {
87
        return $this->name;
88
    }
89
90
    /**
91
     * Get the keyword of the tree item.
92
     *
93
     * @return string
94
     */
95
    public function getKeyword()
96
    {
97
        return $this->keyword;
98
    }
99
100
    /**
101
     * Get the local path to the tree item.
102
     *
103
     * @return string
104
     */
105
    public function getLocal()
106
    {
107
        return $this->local;
108
    }
109
110
    /**
111
     * Get the path to an entry in another CHM file.
112
     *
113
     * @var array|null If not null, it's an array with two keys: 'chm' and 'entry'.
114
     */
115
    public function getMerge()
116
    {
117
        return $this->merge;
118
    }
119
120
    /**
121
     * Get the image number attribute.
122
     *
123
     * @return int|null
124
     */
125
    public function getImageNumber()
126
    {
127
        return $this->imageNumber;
128
    }
129
130
    /**
131
     * Get the sub-elements of this Item.
132
     *
133
     * @return Tree|null
134
     */
135
    public function getSubTree()
136
    {
137
        return $this->subTree;
138
    }
139
140
    /**
141
     * Resolve the items contained in other CHM files.
142
     *
143
     * @param Map $map
144
     *
145
     * @throws Exception Throw an Exception in case of errors.
146
     *
147
     * @return static[]
148
     */
149
    public function resolve(Map $map)
150
    {
151
        if ($this->merge === null) {
152
            $result = array($this);
153
        } else {
154
            $chm = $map->get($this->merge['chm']);
155
            if ($chm === null) {
156
                throw new Exception("Missing CHM reference from map: {$this->merge['chm']}");
157
            }
158
            $entry = $chm->getEntryByPath($this->merge['entry']);
159
            if ($entry === null) {
160
                throw new Exception("Missing entry '{$this->merge['entry']}' in CHM file {$this->merge['chm']}");
161
            }
162
            $tree = Tree::fromString($chm, $entry->getContents());
163
            $tree->resolve($map);
164
            $result = $tree->getItems();
165
        }
166
167
        return $result;
168
    }
169
170
    /**
171
     * Create a new instance starting from a LI element.
172
     *
173
     * @param CHM $chm The parent CHM instance.
174
     * @param DOMElement $li
175
     *
176
     * @throws Exception Throw an Exception in case of errors.
177
     *
178
     * @return static
179
     */
180
    public static function fromLI(CHM $chm, DOMElement $li)
181
    {
182
        $result = array();
183
        $itemForUL = null;
184
        foreach ($li->childNodes as $c) {
185
            if ($c instanceof DOMElement) {
186
                switch (strtolower($c->tagName)) {
187
                    case 'object':
188
                        if (strcasecmp((string) $c->getAttribute('type'), 'text/sitemap') === 0) {
189
                            $itemForUL = static::fromObject($chm, $c);
190
                            $result[] = $itemForUL;
191
                        }
192
                        break;
193
                    case 'ul':
194
                        if ($itemForUL === null) {
195
                            throw new Exception('No sitemap object found for a tree item');
196
                        }
197
                        $itemForUL->subTree = Tree::fromUL($chm, $c);
198
                        $itemForUL = null;
199
                        break;
200
                }
201
            }
202
        }
203
        if (empty($result)) {
204
            throw new Exception('No sitemap object found for a tree item');
205
        }
206
207
        return $result;
208
    }
209
210
    /**
211
     * Create a new instance starting from a LI element or from an OBJECT.
212
     *
213
     * @param CHM $chm The parent CHM instance.
214
     * @param DOMElement $object
215
     *
216
     * @throws Exception Throw an Exception in case of errors.
217
     *
218
     * @return static
219
     */
220
    public static function fromObject(CHM $chm, DOMElement $object)
221
    {
222
        $result = new static($chm);
223
        foreach ($object->childNodes as $p) {
224
            if ($p instanceof DOMElement && strcasecmp($p->tagName, 'param') === 0) {
225
                $name = trim((string) $p->getAttribute('name'));
226
                $value = trim((string) $p->getAttribute('value'));
227
                switch (strtolower($name)) {
228
                    case 'name':
229
                        $result->name = $value;
230
                        break;
231
                    case 'keyword':
232
                        $result->keyword = $value;
233
                        break;
234
                    case 'local':
235
                        $result->local = '/'.str_replace('\\', '/', $value);
236
                        break;
237
                    case 'merge':
238
                        if (!preg_match('%^([^:\\\\/]+)::(.+\.hh[ck])$%i', $value, $matches)) {
239
                            throw new Exception("Invalid value of the '$name' attribute: $value");
240
                        }
241
                        $result->merge = array('chm' => $matches[1], 'entry' => '/'.ltrim(str_replace('\\', '/', $matches[2]), '/'));
242
                        break;
243
                    case 'imagenumber':
244
                        if (is_numeric($value)) {
245
                            $result->imageNumber = (int) $value;
246
                        } elseif ($value !== '') {
247
                            throw new Exception("Invalid value of the '$name' attribute: $value");
248
                        }
249
                        break;
250
                    default:
251
                        throw new Exception("Unknown parameter name '$name' of a tree item (value: '$value')");
252
                }
253
            }
254
        }
255
        if ($result->name === 'dlg_vector_image') {
256
            $result->name = 'dlg_vector_image';
257
        }
258
259
        return $result;
260
    }
261
}
262