MediaWiki master
PPNode_Hash_Tree.php
Go to the documentation of this file.
1<?php
25// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
26class PPNode_Hash_Tree implements PPNode {
27
29 public $name;
30
37 private $rawChildren;
38
43 private $store;
44
49 private $index;
50
55 public const NAME = 0;
56
61 public const CHILDREN = 1;
62
70 public function __construct( array $store, $index ) {
71 $this->store = $store;
72 $this->index = $index;
73 [ $this->name, $this->rawChildren ] = $this->store[$index];
74 }
75
84 public static function factory( array $store, $index ) {
85 if ( !isset( $store[$index] ) ) {
86 return false;
87 }
88
89 $descriptor = $store[$index];
90 if ( is_string( $descriptor ) ) {
91 $class = PPNode_Hash_Text::class;
92 } elseif ( is_array( $descriptor ) ) {
93 if ( $descriptor[self::NAME][0] === '@' ) {
94 $class = PPNode_Hash_Attr::class;
95 } else {
96 $class = self::class;
97 }
98 } else {
99 throw new InvalidArgumentException( __METHOD__ . ': invalid node descriptor' );
100 }
101 return new $class( $store, $index );
102 }
103
108 public function __toString() {
109 $inner = '';
110 $attribs = '';
111 for ( $node = $this->getFirstChild(); $node; $node = $node->getNextSibling() ) {
112 if ( $node instanceof PPNode_Hash_Attr ) {
113 $attribs .= ' ' . $node->name .
114 '="' . htmlspecialchars( $node->value, ENT_COMPAT ) . '"';
115 } else {
116 $inner .= $node->__toString();
117 }
118 }
119 if ( $inner === '' ) {
120 return "<{$this->name}$attribs/>";
121 } else {
122 return "<{$this->name}$attribs>$inner</{$this->name}>";
123 }
124 }
125
129 public function getChildren() {
130 $children = [];
131 foreach ( $this->rawChildren as $i => $child ) {
132 $children[] = self::factory( $this->rawChildren, $i );
133 }
134 return new PPNode_Hash_Array( $children );
135 }
136
144 public function getFirstChild() {
145 if ( !isset( $this->rawChildren[0] ) ) {
146 return false;
147 } else {
148 return self::factory( $this->rawChildren, 0 );
149 }
150 }
151
159 public function getNextSibling() {
160 return self::factory( $this->store, $this->index + 1 );
161 }
162
169 public function getChildrenOfType( $name ) {
170 $children = [];
171 foreach ( $this->rawChildren as $i => $child ) {
172 if ( is_array( $child ) && $child[self::NAME] === $name ) {
173 $children[] = self::factory( $this->rawChildren, $i );
174 }
175 }
176 return new PPNode_Hash_Array( $children );
177 }
178
183 public function getRawChildren() {
184 return $this->rawChildren;
185 }
186
190 public function getLength() {
191 return false;
192 }
193
198 public function item( $i ) {
199 return false;
200 }
201
205 public function getName() {
206 return $this->name;
207 }
208
217 public function splitArg() {
218 return self::splitRawArg( $this->rawChildren );
219 }
220
226 public static function splitRawArg( array $children ) {
227 $bits = [];
228 foreach ( $children as $i => $child ) {
229 if ( !is_array( $child ) ) {
230 continue;
231 }
232 if ( $child[self::NAME] === 'name' ) {
233 $bits['name'] = new self( $children, $i );
234 if ( isset( $child[self::CHILDREN][0][self::NAME] )
235 && $child[self::CHILDREN][0][self::NAME] === '@index'
236 ) {
237 $bits['index'] = $child[self::CHILDREN][0][self::CHILDREN][0];
238 }
239 } elseif ( $child[self::NAME] === 'value' ) {
240 $bits['value'] = new self( $children, $i );
241 }
242 }
243
244 if ( !isset( $bits['name'] ) ) {
245 throw new InvalidArgumentException( 'Invalid brace node passed to ' . __METHOD__ );
246 }
247 if ( !isset( $bits['index'] ) ) {
248 $bits['index'] = '';
249 }
250 return $bits;
251 }
252
259 public function splitExt() {
260 return self::splitRawExt( $this->rawChildren );
261 }
262
268 public static function splitRawExt( array $children ) {
269 $bits = [];
270 foreach ( $children as $i => $child ) {
271 if ( !is_array( $child ) ) {
272 continue;
273 }
274 switch ( $child[self::NAME] ) {
275 case 'name':
276 $bits['name'] = new self( $children, $i );
277 break;
278 case 'attr':
279 $bits['attr'] = new self( $children, $i );
280 break;
281 case 'inner':
282 $bits['inner'] = new self( $children, $i );
283 break;
284 case 'close':
285 $bits['close'] = new self( $children, $i );
286 break;
287 }
288 }
289 if ( !isset( $bits['name'] ) ) {
290 throw new InvalidArgumentException( 'Invalid ext node passed to ' . __METHOD__ );
291 }
292 return $bits;
293 }
294
300 public function splitHeading() {
301 if ( $this->name !== 'h' ) {
302 throw new BadMethodCallException( 'Invalid h node passed to ' . __METHOD__ );
303 }
304 return self::splitRawHeading( $this->rawChildren );
305 }
306
312 public static function splitRawHeading( array $children ) {
313 $bits = [];
314 foreach ( $children as $child ) {
315 if ( !is_array( $child ) ) {
316 continue;
317 }
318 if ( $child[self::NAME] === '@i' ) {
319 $bits['i'] = $child[self::CHILDREN][0];
320 } elseif ( $child[self::NAME] === '@level' ) {
321 $bits['level'] = $child[self::CHILDREN][0];
322 }
323 }
324 if ( !isset( $bits['i'] ) ) {
325 throw new InvalidArgumentException( 'Invalid h node passed to ' . __METHOD__ );
326 }
327 return $bits;
328 }
329
335 public function splitTemplate() {
336 return self::splitRawTemplate( $this->rawChildren );
337 }
338
345 public static function splitRawTemplate( array $children ) {
346 $parts = [];
347 $bits = [ 'lineStart' => '' ];
348 foreach ( $children as $i => $child ) {
349 if ( !is_array( $child ) ) {
350 continue;
351 }
352 switch ( $child[self::NAME] ) {
353 case 'title':
354 $bits['title'] = new self( $children, $i );
355 break;
356 case 'part':
357 $parts[] = new self( $children, $i );
358 break;
359 case '@lineStart':
360 $bits['lineStart'] = '1';
361 break;
362 }
363 }
364 if ( !isset( $bits['title'] ) ) {
365 throw new InvalidArgumentException( 'Invalid node passed to ' . __METHOD__ );
366 }
367 $bits['parts'] = new PPNode_Hash_Array( $parts );
368 return $bits;
369 }
370}
static factory(array $store, $index)
Construct an appropriate PPNode_Hash_* object with a class that depends on what is at the relevant st...
splitExt()
Split an "<ext>" node into an associative array containing name, attr, inner and close All values in ...
static splitRawArg(array $children)
Like splitArg() but for a raw child array.
splitArg()
Split a "<part>" node into an associative array containing:
getNextSibling()
Get the next sibling, or false if there is none.
static splitRawTemplate(array $children)
Like splitTemplate() but for a raw child array.
splitHeading()
Split an "<h>" node.
splitTemplate()
Split a "<template>" or "<tplarg>" node.
static splitRawHeading(array $children)
Like splitHeading() but for a raw child array.
static splitRawExt(array $children)
Like splitExt() but for a raw child array.
__construct(array $store, $index)
Construct an object using the data from $store[$index].
getChildrenOfType( $name)
Get an array of the children with a given node name.
__toString()
Convert a node to XML, for debugging.
const CHILDREN
The offset of the child list within descriptors, used in some places for readability.
getFirstChild()
Get the first child, or false if there is none.
getRawChildren()
Get the raw child array.
const NAME
The offset of the name within descriptors, used in some places for readability.
There are three types of nodes:
Definition PPNode.php:35