Issues (9)

src/Helper.php (1 issue)

Severity
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
     *
25
     * @return string
26
     */
27 80
    public static function toXpath(
28
        string $selector,
29
        string $prefix = 'descendant::'
30
    ): string {
31 80
        static $converter;
32 80
        $converter = $converter ?: new CssSelectorConverter();
33
34 80
        return $converter->toXPath($selector, $prefix);
35
    }
36
37
    /**
38
     * Strict Array Unique
39
     *
40
     * @param array|Traversable $arr
41
     *
42
     * @return array
43
     */
44 83
    public static function strictArrayUnique($arr): array
45
    {
46 83
        $uniqueArr = [];
47 83
        foreach ($arr as $value) {
48 81
            if (!in_array($value, $uniqueArr, true)) {
49 81
                $uniqueArr[] = $value;
50
            }
51
        }
52
53 83
        return $uniqueArr;
54
    }
55
56
    /**
57
     * Strict array intersect
58
     *
59
     * @param array $arr1
60
     * @param array $arr2
61
     *
62
     * @return array
63
     */
64 5
    public static function strictArrayIntersect(array $arr1, array $arr2): array
65
    {
66 5
        $arr = array_filter($arr1, function ($val1) use ($arr2) {
67 5
            return in_array($val1, $arr2, true);
68 5
        });
69
70 5
        return array_values($arr);
71
    }
72
73
    /**
74
     * Strict array diff
75
     *
76
     * @param array $arr1
77
     * @param array $arr2
78
     *
79
     * @return array
80
     */
81 3
    public static function strictArrayDiff(array $arr1, array $arr2): array
82
    {
83 3
        $arr = array_filter($arr1, function ($val1) use ($arr2) {
84 3
            return !in_array($val1, $arr2, true);
85 3
        });
86
87 3
        return array_values($arr);
88
    }
89
90
    /**
91
     * Case insensitive search
92
     *
93
     * @param string   $needle
94
     * @param string[] $haystack
95
     *
96
     * @return array
97
     */
98 2
    public static function caseInsensitiveSearch(
99
        string $needle,
100
        array $haystack
101
    ): array {
102 2
        $needle = strtolower($needle);
103 2
        $match = array_filter($haystack, function ($value) use ($needle) {
104 2
            return $needle === strtolower($value);
105 2
        });
106
107 2
        return array_values($match);
108
    }
109
110
    /**
111
     * Split the class attr value to a class array
112
     *
113
     * @param string $className
114
     *
115
     * @return array
116
     */
117 6
    public static function splitClass(string $className): array
118
    {
119 6
        return preg_split('/\s+/', trim($className)) ?: [];
120
    }
121
122
    /**
123
     * Split style to css array
124
     *
125
     * @param string $style
126
     *
127
     * @return array
128
     */
129 2
    public static function splitCss(string $style): array
130
    {
131 2
        $arr = explode(';', $style);
132 2
        $arr = array_map('trim', $arr);
133
134 2
        $css = [];
135 2
        foreach ($arr as $value) {
136 2
            $row = explode(':', $value, 2);
137 2
            if (count($row) !== 2) {
138 1
                continue;
139
            }
140
141 2
            $css[trim($row[0])] = trim($row[1]);
142
        }
143
144 2
        return $css;
145
    }
146
147
    /**
148
     * Implode css array to style string
149
     *
150
     * @param array $css
151
     *
152
     * @return string
153
     */
154 2
    public static function implodeCss(array $css): string
155
    {
156 2
        $arr = [];
157 2
        foreach ($css as $key => $value) {
158 2
            $arr[] = $key . ': ' . $value;
159
        }
160
161 2
        $style = $arr ? implode('; ', $arr) . ';' : '';
162
163 2
        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
     *
172
     * @return bool
173
     */
174 37
    public static function isRawHtml(string $html): bool
175
    {
176 37
        if ($html[0] === '<' && $html[-1] === '>' && strlen($html) >= 3) {
177 8
            return true;
178
        }
179
180 35
        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
     *
189
     * @return bool
190
     */
191 79
    public static function isIdSelector(
192
        string $selector,
193
        ?string &$id = null
194
    ): bool {
195 79
        if (preg_match('/^#([\w-]+)$/', $selector, $match)) {
196 5
            $id = $match[1];
197
198 5
            return true;
199
        }
200
201 77
        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
     *
211
     * @return DOMNode[]
212
     */
213 79
    public static function xpathQuery(
214
        string $xpath,
215
        DOMDocument $doc,
216
        ?DOMNode $node = null
217
    ): array {
218 79
        $docXpath = new DOMXpath($doc);
219 79
        $nodeList = $docXpath->query($xpath, $node);
220
221 79
        if (!($nodeList instanceof DOMNodeList)) {
0 ignored issues
show
$nodeList is always a sub-type of DOMNodeList.
Loading history...
222 1
            return [];
223
        }
224
225 79
        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
     *
234
     * @return DOMNode|null
235
     */
236 4
    public static function getRelationNode(DOMNode $node, string $relation)
237
    {
238
        /** @var DOMNode $node */
239
        while (
240 4
            ($node = $node->$relation)
241 4
            && $node instanceof DOMNode
242 4
            && $node->nodeType !== XML_DOCUMENT_NODE
243
        ) {
244 4
            if ($node->nodeType !== XML_ELEMENT_NODE) {
245 3
                continue;
246
            }
247
248 4
            return $node;
249
        }
250
251 3
        return null;
252
    }
253
}
254