Passed
Branch scrutinizer (8fc54b)
by Thomas
02:27
created

Resolver::contentResolve()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
eloc 3
c 1
b 1
f 0
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMDocument, DOMNode, DOMNodeList;
6
7
/**
8
 * Trait Selector
9
 *
10
 * @package Sulao\HtmlQuery
11
 */
12
trait Resolver
13
{
14
    /**
15
     * @var DOMDocument
16
     */
17
    protected $doc;
18
19
    /**
20
     * @var DOMNode[]
21
     */
22
    protected $nodes;
23
24
    /**
25
     * Selector constructor.
26
     *
27
     * @param DOMDocument                          $doc
28
     * @param DOMNode|DOMNode[]|DOMNodeList|static $nodes
29
     *
30
     * @return static
31
     */
32
    abstract public function __construct(DOMDocument $doc, $nodes);
33
34
    /**
35
     * Get the descendants of each matched node, filtered by a selector.
36
     *
37
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $selector
38
     *
39
     * @return static
40
     */
41
    abstract public function find($selector);
42
43
    /**
44
     * Resolve DOMNode(s) to a static instance.
45
     *
46
     * @param DOMNode|DOMNode[]|DOMNodeList|static $nodes
47
     *
48
     * @return static
49
     */
50 62
    protected function resolve($nodes)
51
    {
52 62
        if ($nodes instanceof static) {
53 21
            return $nodes;
54
        }
55
56 62
        return new static($this->doc, $nodes);
57
    }
58
59
    /**
60
     * If the parameter is a css selector, get the descendants
61
     * of dom document filtered by the css selector.
62
     * If the parameter is selection, resolve that selection to static object.
63
     *
64
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $selector
65
     *
66
     * @return static
67
     */
68 19
    protected function targetResolve($selector)
69
    {
70 19
        if (is_string($selector)) {
71 16
            return $this->resolve($this->doc)->find($selector);
72
        }
73
74 8
        return $this->resolve($selector);
75
    }
76
77
    /**
78
     * If the parameter is string, consider it as raw html,
79
     * then create document fragment for it.
80
     * If the parameter is selection, resolve that selection to static instance.
81
     *
82
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
83
     *
84
     * @return static
85
     */
86 17
    protected function contentResolve($content)
87
    {
88 17
        if (is_string($content)) {
89 12
            return $this->htmlResolve($content);
90
        }
91
92 15
        return $this->resolve($content);
93
    }
94
95
    /**
96
     * Resolve the html content to static instance.
97
     *
98
     * @param string $html
99
     *
100
     * @return static
101
     */
102 14
    protected function htmlResolve(string $html)
103
    {
104 14
        $frag = $this->doc->createDocumentFragment();
105 14
        $frag->appendXML($html);
106
107 14
        return $this->resolve($frag);
108
    }
109
110
    /**
111
     * Resolve the nodes under the relation to static instance.
112
     * up to but not including the node matched by the $until selector.
113
     *
114
     * @param string $relation
115
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $until
116
     *
117
     * @return static
118
     */
119 4
    protected function relationResolve(string $relation, ?string $until = null)
120
    {
121 4
        $untilNodes = !is_null($until)
122 4
            ? $this->targetResolve($until)->nodes
123 4
            : [];
124
125 4
        $nodes = [];
126 4
        foreach ($this->nodes as $node) {
127 4
            while ($node = $this->getRelationNode($node, $relation)) {
128 4
                if (in_array($node, $untilNodes, true)) {
129 4
                    break;
130
                }
131
132 4
                if (!in_array($node, $nodes, true)) {
133 4
                    $nodes[] = $node;
134
                }
135
            }
136
        }
137
138 4
        return $this->resolve($nodes);
139
    }
140
141
    /**
142
     * Get the node with the relationship of current node.
143
     *
144
     * @param DOMNode $node
145
     * @param string  $relation
146
     *
147
     * @return DOMNode|null
148
     */
149 4
    protected function getRelationNode(DOMNode $node, string $relation)
150
    {
151 4
        while (($node = $node->$relation)
152 4
            && $node->nodeType !== XML_DOCUMENT_NODE
153
        ) {
154 4
            if ($node->nodeType !== XML_ELEMENT_NODE) {
155 3
                continue;
156
            }
157
158 4
            return $node;
159
        }
160
161 3
        return null;
162
    }
163
164
    /**
165
     * Resolve the xpath to static instance.
166
     *
167
     * @param string $xpath
168
     *
169
     * @return static
170
     */
171 31
    protected function xpathResolve(string $xpath)
172
    {
173 31
        $nodes = [];
174 31
        foreach ($this->nodes as $node) {
175 30
            $nodes = array_merge($nodes, $this->xpathQuery($xpath, $node));
176
        }
177
178 31
        $nodes = Helper::strictArrayUnique($nodes);
179
180 31
        return $this->resolve($nodes);
181
    }
182
183
    /**
184
     * Query xpath to an array of DOMNode
185
     *
186
     * @param string       $xpath
187
     * @param DOMNode|null $node
188
     *
189
     * @return DOMNode[]
190
     */
191 35
    protected function xpathQuery(
192
        string $xpath,
193
        ?DOMNode $node = null
194
    ): array {
195 35
        return Helper::xpathQuery($xpath, $this->doc, $node);
196
    }
197
}
198