Helper   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 235
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 235
ccs 64
cts 64
cp 1
rs 10
wmc 29

12 Methods

Rating   Name   Duplication   Size   Complexity  
A strictArrayDiff() 0 7 1
A strictArrayIntersect() 0 7 1
A strictArrayUnique() 0 10 3
A xpathQuery() 0 13 2
A caseInsensitiveSearch() 0 10 1
A splitClass() 0 3 2
A isIdSelector() 0 11 2
A getRelationNode() 0 16 5
A implodeCss() 0 10 3
A toXpath() 0 8 2
A splitCss() 0 16 3
A isRawHtml() 0 7 4
1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMDocument;
6
use DOMNode;
7
use DOMNodeList;
8
use DOMXPath;
9
use Symfony\Component\CssSelector\CssSelectorConverter;
10
use Traversable;
11
12
/**
13
 * Class Helper
14
 *
15
 * @package Sulao\HtmlQuery
16
 */
17
class Helper
18
{
19
    /**
20
     * Convert a css selector to xpath
21
     *
22
     * @param string $selector
23
     * @param string $prefix
24 80
     *
25
     * @return string
26
     */
27
    public static function toXpath(
28 80
        string $selector,
29 80
        string $prefix = 'descendant::'
30
    ): string {
31 80
        static $converter;
32
        $converter = $converter ?: new CssSelectorConverter();
33
34
        return $converter->toXPath($selector, $prefix);
35
    }
36
37
    /**
38
     * Strict Array Unique
39
     *
40
     * @param array|Traversable $arr
41 83
     *
42
     * @return array
43 83
     */
44 83
    public static function strictArrayUnique($arr): array
45 81
    {
46 81
        $uniqueArr = [];
47
        foreach ($arr as $value) {
48
            if (!in_array($value, $uniqueArr, true)) {
49
                $uniqueArr[] = $value;
50 83
            }
51
        }
52
53
        return $uniqueArr;
54
    }
55
56
    /**
57
     * Strict array intersect
58
     *
59
     * @param array $arr1
60
     * @param array $arr2
61 5
     *
62
     * @return array
63
     */
64 5
    public static function strictArrayIntersect(array $arr1, array $arr2): array
65 5
    {
66
        $arr = array_filter($arr1, function ($val1) use ($arr2) {
67 5
            return in_array($val1, $arr2, true);
68
        });
69
70
        return array_values($arr);
71
    }
72
73
    /**
74
     * Strict array diff
75
     *
76
     * @param array $arr1
77
     * @param array $arr2
78 3
     *
79
     * @return array
80
     */
81 3
    public static function strictArrayDiff(array $arr1, array $arr2): array
82 3
    {
83
        $arr = array_filter($arr1, function ($val1) use ($arr2) {
84 3
            return !in_array($val1, $arr2, true);
85
        });
86
87
        return array_values($arr);
88
    }
89
90
    /**
91
     * Case insensitive search
92
     *
93
     * @param string   $needle
94
     * @param string[] $haystack
95 2
     *
96
     * @return array
97
     */
98
    public static function caseInsensitiveSearch(
99 2
        string $needle,
100
        array $haystack
101 2
    ): array {
102 2
        $needle = strtolower($needle);
103
        $match = array_filter($haystack, function ($value) use ($needle) {
104 2
            return $needle === strtolower($value);
105
        });
106
107
        return array_values($match);
108
    }
109
110
    /**
111
     * Split the class attr value to a class array
112
     *
113
     * @param string $className
114 6
     *
115
     * @return array
116 6
     */
117
    public static function splitClass(string $className): array
118
    {
119
        return preg_split('/\s+/', trim($className)) ?: [];
120
    }
121
122
    /**
123
     * Split style to css array
124
     *
125
     * @param string $style
126 2
     *
127
     * @return array
128 2
     */
129 2
    public static function splitCss(string $style): array
130
    {
131 2
        $arr = explode(';', $style);
132 2
        $arr = array_map('trim', $arr);
133 2
134 2
        $css = [];
135 1
        foreach ($arr as $value) {
136
            $row = explode(':', $value, 2);
137
            if (count($row) !== 2) {
138 2
                continue;
139
            }
140
141 2
            $css[trim($row[0])] = trim($row[1]);
142
        }
143
144
        return $css;
145
    }
146
147
    /**
148
     * Implode css array to style string
149
     *
150
     * @param array $css
151 2
     *
152
     * @return string
153 2
     */
154 2
    public static function implodeCss(array $css): string
155 2
    {
156
        $arr = [];
157
        foreach ($css as $key => $value) {
158 2
            $arr[] = $key . ': ' . $value;
159
        }
160 2
161
        $style = $arr ? implode('; ', $arr) . ';' : '';
162
163
        return $style;
164
    }
165
166
    /**
167
     * Determine whether the string is raw html,
168
     * otherwise consider it as a css selector
169
     *
170
     * @param string $html
171 37
     *
172
     * @return bool
173 37
     */
174 8
    public static function isRawHtml(string $html): bool
175
    {
176
        if ($html[0] === '<' && $html[-1] === '>' && strlen($html) >= 3) {
177 35
            return true;
178
        }
179
180
        return (bool) preg_match('/^\s*(<[\w\W]+>)[^>]*$/', $html);
181
    }
182
183
    /**
184
     * Determine whether the selector is a id selector
185
     *
186
     * @param string      $selector
187
     * @param string|null $id
188 79
     *
189
     * @return bool
190
     */
191
    public static function isIdSelector(
192 79
        string $selector,
193 5
        string &$id = null
194
    ): bool {
195 5
        if (preg_match('/^#([\w-]+)$/', $selector, $match)) {
196
            $id = $match[1];
197
198 77
            return true;
199
        }
200
201
        return false;
202
    }
203
204
    /**
205
     * Query xpath to an array of DOMNode
206
     *
207
     * @param string       $xpath
208
     * @param DOMDocument  $doc
209
     * @param DOMNode|null $node
210 79
     *
211
     * @return DOMNode[]
212
     */
213
    public static function xpathQuery(
214
        string $xpath,
215 79
        DOMDocument $doc,
216 79
        ?DOMNode $node = null
217
    ): array {
218 79
        $docXpath = new DOMXpath($doc);
219 1
        $nodeList = $docXpath->query($xpath, $node);
220
221
        if (!($nodeList instanceof DOMNodeList)) {
0 ignored issues
show
introduced by
$nodeList is always a sub-type of DOMNodeList.
Loading history...
222 79
            return [];
223
        }
224
225
        return iterator_to_array($nodeList);
226
    }
227
228
    /**
229
     * Get the node with the relationship of current node.
230
     *
231
     * @param DOMNode $node
232
     * @param string  $relation
233 4
     *
234
     * @return DOMNode|null
235
     */
236 4
    public static function getRelationNode(DOMNode $node, string $relation)
237 4
    {
238 4
        /** @var DOMNode $node */
239
        while (
240 4
            ($node = $node->$relation)
241 3
            && $node instanceof DOMNode
242
            && $node->nodeType !== XML_DOCUMENT_NODE
243
        ) {
244 4
            if ($node->nodeType !== XML_ELEMENT_NODE) {
245
                continue;
246
            }
247 3
248
            return $node;
249
        }
250
251
        return null;
252
    }
253
}
254