These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Create list of nodes for a FluentDOM\Nodes object from different values |
||
4 | * |
||
5 | * @license http://www.opensource.org/licenses/mit-license.php The MIT License |
||
6 | * @copyright Copyright (c) 2009-2014 Bastian Feder, Thomas Weinert |
||
7 | */ |
||
8 | |||
9 | namespace FluentDOM\Nodes { |
||
10 | |||
11 | use FluentDOM\Constraints; |
||
12 | use FluentDOM\Nodes; |
||
13 | use FluentDOM\Exceptions; |
||
14 | |||
15 | /** |
||
16 | * Create list of nodes for a FluentDOM\Nodes object from different values |
||
17 | */ |
||
18 | class Builder { |
||
19 | |||
20 | /** |
||
21 | * @var Nodes |
||
22 | */ |
||
23 | private $_nodes; |
||
24 | |||
25 | /** |
||
26 | * @param Nodes $nodes |
||
27 | */ |
||
28 | 32 | public function __construct(Nodes $nodes) { |
|
29 | 32 | $this->_nodes = $nodes; |
|
30 | 32 | } |
|
31 | |||
32 | /** |
||
33 | * @return Nodes |
||
34 | */ |
||
35 | 23 | public function getOwner() { |
|
36 | 23 | return $this->_nodes; |
|
37 | } |
||
38 | |||
39 | /** |
||
40 | * @param mixed $content |
||
41 | * @param bool $includeTextNodes |
||
42 | * @param int $limit |
||
43 | * @return array|\Traversable null |
||
44 | */ |
||
45 | 22 | private function getNodeList( |
|
46 | $content, |
||
47 | $includeTextNodes = TRUE, |
||
48 | $limit = -1 |
||
49 | ) { |
||
50 | 22 | if ($callback = Constraints::isCallable($content)) { |
|
51 | 1 | $content = $callback(); |
|
52 | 1 | } |
|
53 | 22 | if ($content instanceof \DOMElement) { |
|
54 | 2 | return array($content); |
|
55 | 20 | } elseif ($includeTextNodes && Constraints::isNode($content)) { |
|
56 | 2 | return array($content); |
|
57 | 18 | } elseif (Constraints::isNodeList($content)) { |
|
58 | 6 | return $this->getLimitedArray($content, $limit); |
|
59 | } |
||
60 | 12 | return NULL; |
|
61 | } |
||
62 | |||
63 | /** |
||
64 | * Match selector against context and return matched elements. |
||
65 | * |
||
66 | * @param mixed $selector |
||
67 | * @param \DOMNode $context optional, default value NULL |
||
68 | * @throws \InvalidArgumentException |
||
69 | * @return array |
||
70 | */ |
||
71 | 16 | public function getTargetNodes($selector, \DOMNode $context = NULL) { |
|
72 | 8 | if ($nodes = $this->getNodeList($selector)) { |
|
73 | 4 | return $nodes; |
|
74 | 4 | } elseif (is_string($selector)) { |
|
75 | 16 | $result = $this->getOwner()->xpath( |
|
76 | 3 | $this->getOwner()->prepareSelector( |
|
77 | 3 | $selector, |
|
78 | Nodes::CONTEXT_SELF |
||
79 | 3 | ), |
|
80 | $context |
||
81 | 3 | ); |
|
82 | 3 | if (!($result instanceof \Traversable)) { |
|
83 | 1 | throw new \InvalidArgumentException('Given selector did not return an node list.'); |
|
84 | } |
||
85 | 2 | return iterator_to_array($result); |
|
86 | } |
||
87 | 1 | throw new \InvalidArgumentException('Invalid selector'); |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * Convert a given content into and array of nodes |
||
92 | * |
||
93 | * @param mixed $content |
||
94 | * @param boolean $includeTextNodes |
||
95 | * @param integer $limit |
||
96 | * @throws Exceptions\LoadingError\EmptyResult |
||
97 | * @return array |
||
98 | */ |
||
99 | 14 | public function getContentNodes($content, $includeTextNodes = TRUE, $limit = -1) { |
|
100 | 14 | $result = FALSE; |
|
101 | 14 | if ($nodes = $this->getNodeList($content, $includeTextNodes, $limit)) { |
|
102 | 5 | $result = $nodes; |
|
103 | 14 | } elseif (is_string($content)) { |
|
104 | 7 | $result = $this->getFragment($content, $this->getOwner()->contentType, $includeTextNodes, $limit); |
|
105 | 7 | } |
|
106 | 14 | if (!is_array($result) || empty($result)) { |
|
107 | 3 | throw new Exceptions\LoadingError\EmptyResult(); |
|
108 | } else { |
||
109 | //if a node is not in the current document import it |
||
110 | 11 | $document = $this->getOwner()->getDocument(); |
|
111 | 11 | foreach ($result as $index => $node) { |
|
112 | 11 | if ($node->ownerDocument !== $document) { |
|
113 | 1 | $result[$index] = $document->importNode($node, TRUE); |
|
114 | 1 | } |
|
115 | 11 | } |
|
116 | } |
||
117 | 11 | return $result; |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * Convert $content to a DOMElement. If $content contains several elements use the first. |
||
122 | * |
||
123 | * @param mixed $content |
||
124 | * @return \DOMElement |
||
125 | */ |
||
126 | 4 | public function getContentElement($content) { |
|
127 | 4 | $contentNodes = $this->getContentNodes($content, FALSE, 1); |
|
128 | 4 | return $contentNodes[0]; |
|
129 | } |
||
130 | |||
131 | /** |
||
132 | * Convert a given content string into and array of nodes |
||
133 | * |
||
134 | * @param string $xml |
||
135 | * @param string $contentType |
||
136 | * @param boolean $includeTextNodes |
||
137 | * @param integer $limit |
||
138 | * @throws Exceptions\InvalidFragmentLoader |
||
139 | * @return array |
||
140 | */ |
||
141 | 15 | public function getFragment($xml, $contentType = 'text/xml', $includeTextNodes = TRUE, $limit = -1) { |
|
142 | 15 | $xml = $this->getContentAsString($xml); |
|
143 | 13 | $loader = $this->getOwner()->loaders(); |
|
144 | 13 | if (!$loader->supports($contentType)) { |
|
145 | 1 | throw new Exceptions\InvalidFragmentLoader(get_class($loader)); |
|
146 | } |
||
147 | 12 | if (!$xml) { |
|
148 | 4 | return array(); |
|
149 | } |
||
150 | 8 | $result = array(); |
|
151 | 8 | $fragment = $loader->loadFragment( |
|
152 | 8 | $xml, $contentType, $this->getOwner()->getLoadingOptions($contentType) |
|
153 | 8 | ); |
|
154 | 8 | if ($fragment) { |
|
155 | 8 | $fragment = $this->getOwner()->document->importNode($fragment, TRUE); |
|
156 | 8 | for ($i = $fragment->childNodes->length - 1; $i >= 0; $i--) { |
|
157 | 8 | $element = $fragment->childNodes->item($i); |
|
158 | 8 | if ($element instanceof \DOMElement || |
|
159 | 8 | ($includeTextNodes && Constraints::isNode($element))) { |
|
160 | 8 | array_unshift($result, $element); |
|
161 | 8 | $element->parentNode->removeChild($element); |
|
162 | 8 | } |
|
163 | 8 | } |
|
164 | 8 | } |
|
165 | 8 | return $this->getLimitedArray($result, $limit); |
|
166 | } |
||
167 | |||
168 | /** |
||
169 | * @param string $content |
||
170 | * @return string bool |
||
171 | * @throws \UnexpectedValueException |
||
172 | */ |
||
173 | 15 | private function getContentAsString($content) { |
|
174 | 15 | if (is_scalar($content) || method_exists($content, '__toString')) { |
|
175 | 13 | $content = (string)$content; |
|
176 | 13 | return ($content === '') ? FALSE : $content; |
|
177 | } |
||
178 | 2 | throw new Exceptions\LoadingError\EmptySource('Invalid document fragment'); |
|
0 ignored issues
–
show
|
|||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Get the inner xml of a given node or in other words the xml of all children. |
||
183 | * |
||
184 | * @param \DOMNode $context |
||
185 | * @return string |
||
186 | */ |
||
187 | 1 | public function getInnerXml($context) { |
|
188 | 1 | $result = ''; |
|
189 | 1 | $dom = $this->getOwner()->getDocument(); |
|
190 | 1 | $nodes = $this->getOwner()->xpath( |
|
191 | 1 | '*|text()[normalize-space(.) != ""]|self::text()[normalize-space(.) != ""]', |
|
192 | $context |
||
193 | 1 | ); |
|
194 | 1 | foreach ($nodes as $child) { |
|
195 | 1 | $result .= $dom->saveXML($child); |
|
196 | 1 | } |
|
197 | 1 | return $result; |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * Get the inner and outer wrapper nodes. Simple means that they are the |
||
202 | * same nodes. |
||
203 | * |
||
204 | * @param \DOMElement $template |
||
205 | * @param bool $simple |
||
206 | * @return \DOMElement[] |
||
207 | */ |
||
208 | 2 | public function getWrapperNodes($template, &$simple) { |
|
209 | 2 | $wrapper = $template->cloneNode(TRUE); |
|
210 | 2 | $targets = NULL; |
|
211 | 2 | $target = NULL; |
|
212 | 2 | if (!$simple) { |
|
213 | // get the first element without child elements. |
||
214 | 2 | $targets = $this->getOwner()->xpath('.//*[count(*) = 0]', $wrapper); |
|
215 | 2 | } |
|
216 | 2 | if ($simple || $targets->length === 0) { |
|
217 | 1 | $target = $wrapper; |
|
218 | 1 | $simple = TRUE; |
|
219 | 2 | } elseif ($targets instanceof \DOMNodeList) { |
|
220 | 1 | $target = $targets->item(0); |
|
221 | 1 | } |
|
222 | 2 | return array($target, $wrapper); |
|
223 | } |
||
224 | |||
225 | /** |
||
226 | * @param array|\Traversable $nodes |
||
227 | * @param int $limit |
||
228 | * @return array |
||
229 | */ |
||
230 | 14 | private function getLimitedArray($nodes, $limit = -1) { |
|
231 | 14 | if ($limit > 0) { |
|
232 | 7 | if (is_array($nodes)) { |
|
233 | 5 | return array_slice($nodes, 0, $limit); |
|
234 | } else { |
||
235 | 2 | return iterator_to_array( |
|
236 | 2 | new \LimitIterator( |
|
237 | 2 | new \IteratorIterator($nodes), 0, $limit |
|
238 | 2 | ), |
|
239 | FALSE |
||
240 | 2 | ); |
|
241 | } |
||
242 | } |
||
243 | 7 | return is_array($nodes) ? $nodes : iterator_to_array($nodes, FALSE); |
|
244 | } |
||
245 | } |
||
246 | } |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.