MediaWiki  1.29.2
Preprocessor_Hash.php
Go to the documentation of this file.
1 <?php
42 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
44  // @codingStandardsIgnoreEnd
45 
49  public $parser;
50 
51  const CACHE_PREFIX = 'preprocess-hash';
52  const CACHE_VERSION = 2;
53 
54  public function __construct( $parser ) {
55  $this->parser = $parser;
56  }
57 
61  public function newFrame() {
62  return new PPFrame_Hash( $this );
63  }
64 
69  public function newCustomFrame( $args ) {
70  return new PPCustomFrame_Hash( $this, $args );
71  }
72 
77  public function newPartNodeArray( $values ) {
78  $list = [];
79 
80  foreach ( $values as $k => $val ) {
81  if ( is_int( $k ) ) {
82  $store = [ [ 'part', [
83  [ 'name', [ [ '@index', [ $k ] ] ] ],
84  [ 'value', [ strval( $val ) ] ],
85  ] ] ];
86  } else {
87  $store = [ [ 'part', [
88  [ 'name', [ strval( $k ) ] ],
89  '=',
90  [ 'value', [ strval( $val ) ] ],
91  ] ] ];
92  }
93 
94  $list[] = new PPNode_Hash_Tree( $store, 0 );
95  }
96 
97  $node = new PPNode_Hash_Array( $list );
98  return $node;
99  }
100 
119  public function preprocessToObj( $text, $flags = 0 ) {
120  global $wgDisableLangConversion;
121 
122  $tree = $this->cacheGetTree( $text, $flags );
123  if ( $tree !== false ) {
124  $store = json_decode( $tree );
125  if ( is_array( $store ) ) {
126  return new PPNode_Hash_Tree( $store, 0 );
127  }
128  }
129 
130  $forInclusion = $flags & Parser::PTD_FOR_INCLUSION;
131 
132  $xmlishElements = $this->parser->getStripList();
133  $xmlishAllowMissingEndTag = [ 'includeonly', 'noinclude', 'onlyinclude' ];
134  $enableOnlyinclude = false;
135  if ( $forInclusion ) {
136  $ignoredTags = [ 'includeonly', '/includeonly' ];
137  $ignoredElements = [ 'noinclude' ];
138  $xmlishElements[] = 'noinclude';
139  if ( strpos( $text, '<onlyinclude>' ) !== false
140  && strpos( $text, '</onlyinclude>' ) !== false
141  ) {
142  $enableOnlyinclude = true;
143  }
144  } else {
145  $ignoredTags = [ 'noinclude', '/noinclude', 'onlyinclude', '/onlyinclude' ];
146  $ignoredElements = [ 'includeonly' ];
147  $xmlishElements[] = 'includeonly';
148  }
149  $xmlishRegex = implode( '|', array_merge( $xmlishElements, $ignoredTags ) );
150 
151  // Use "A" modifier (anchored) instead of "^", because ^ doesn't work with an offset
152  $elementsRegex = "~($xmlishRegex)(?:\s|\/>|>)|(!--)~iA";
153 
154  $stack = new PPDStack_Hash;
155 
156  $searchBase = "[{<\n";
157  if ( !$wgDisableLangConversion ) {
158  // FIXME: disabled due to T153761
159  // $searchBase .= '-';
160  }
161 
162  // For fast reverse searches
163  $revText = strrev( $text );
164  $lengthText = strlen( $text );
165 
166  // Input pointer, starts out pointing to a pseudo-newline before the start
167  $i = 0;
168  // Current accumulator. See the doc comment for Preprocessor_Hash for the format.
169  $accum =& $stack->getAccum();
170  // True to find equals signs in arguments
171  $findEquals = false;
172  // True to take notice of pipe characters
173  $findPipe = false;
174  $headingIndex = 1;
175  // True if $i is inside a possible heading
176  $inHeading = false;
177  // True if there are no more greater-than (>) signs right of $i
178  $noMoreGT = false;
179  // Map of tag name => true if there are no more closing tags of given type right of $i
180  $noMoreClosingTag = [];
181  // True to ignore all input up to the next <onlyinclude>
182  $findOnlyinclude = $enableOnlyinclude;
183  // Do a line-start run without outputting an LF character
184  $fakeLineStart = true;
185 
186  while ( true ) {
187  // $this->memCheck();
188 
189  if ( $findOnlyinclude ) {
190  // Ignore all input up to the next <onlyinclude>
191  $startPos = strpos( $text, '<onlyinclude>', $i );
192  if ( $startPos === false ) {
193  // Ignored section runs to the end
194  $accum[] = [ 'ignore', [ substr( $text, $i ) ] ];
195  break;
196  }
197  $tagEndPos = $startPos + strlen( '<onlyinclude>' ); // past-the-end
198  $accum[] = [ 'ignore', [ substr( $text, $i, $tagEndPos - $i ) ] ];
199  $i = $tagEndPos;
200  $findOnlyinclude = false;
201  }
202 
203  if ( $fakeLineStart ) {
204  $found = 'line-start';
205  $curChar = '';
206  } else {
207  # Find next opening brace, closing brace or pipe
208  $search = $searchBase;
209  if ( $stack->top === false ) {
210  $currentClosing = '';
211  } else {
212  $currentClosing = $stack->top->close;
213  $search .= $currentClosing;
214  }
215  if ( $findPipe ) {
216  $search .= '|';
217  }
218  if ( $findEquals ) {
219  // First equals will be for the template
220  $search .= '=';
221  }
222  $rule = null;
223  # Output literal section, advance input counter
224  $literalLength = strcspn( $text, $search, $i );
225  if ( $literalLength > 0 ) {
226  self::addLiteral( $accum, substr( $text, $i, $literalLength ) );
227  $i += $literalLength;
228  }
229  if ( $i >= $lengthText ) {
230  if ( $currentClosing == "\n" ) {
231  // Do a past-the-end run to finish off the heading
232  $curChar = '';
233  $found = 'line-end';
234  } else {
235  # All done
236  break;
237  }
238  } else {
239  $curChar = $curTwoChar = $text[$i];
240  if ( ( $i + 1 ) < $lengthText ) {
241  $curTwoChar .= $text[$i + 1];
242  }
243  if ( $curChar == '|' ) {
244  $found = 'pipe';
245  } elseif ( $curChar == '=' ) {
246  $found = 'equals';
247  } elseif ( $curChar == '<' ) {
248  $found = 'angle';
249  } elseif ( $curChar == "\n" ) {
250  if ( $inHeading ) {
251  $found = 'line-end';
252  } else {
253  $found = 'line-start';
254  }
255  } elseif ( $curTwoChar == $currentClosing ) {
256  $found = 'close';
257  $curChar = $curTwoChar;
258  } elseif ( $curChar == $currentClosing ) {
259  $found = 'close';
260  } elseif ( isset( $this->rules[$curTwoChar] ) ) {
261  $curChar = $curTwoChar;
262  $found = 'open';
263  $rule = $this->rules[$curChar];
264  } elseif ( isset( $this->rules[$curChar] ) ) {
265  $found = 'open';
266  $rule = $this->rules[$curChar];
267  } elseif ( $curChar == '-' ) {
268  $found = 'dash';
269  } else {
270  # Some versions of PHP have a strcspn which stops on null characters
271  # Ignore and continue
272  ++$i;
273  continue;
274  }
275  }
276  }
277 
278  if ( $found == 'angle' ) {
279  $matches = false;
280  // Handle </onlyinclude>
281  if ( $enableOnlyinclude
282  && substr( $text, $i, strlen( '</onlyinclude>' ) ) == '</onlyinclude>'
283  ) {
284  $findOnlyinclude = true;
285  continue;
286  }
287 
288  // Determine element name
289  if ( !preg_match( $elementsRegex, $text, $matches, 0, $i + 1 ) ) {
290  // Element name missing or not listed
291  self::addLiteral( $accum, '<' );
292  ++$i;
293  continue;
294  }
295  // Handle comments
296  if ( isset( $matches[2] ) && $matches[2] == '!--' ) {
297 
298  // To avoid leaving blank lines, when a sequence of
299  // space-separated comments is both preceded and followed by
300  // a newline (ignoring spaces), then
301  // trim leading and trailing spaces and the trailing newline.
302 
303  // Find the end
304  $endPos = strpos( $text, '-->', $i + 4 );
305  if ( $endPos === false ) {
306  // Unclosed comment in input, runs to end
307  $inner = substr( $text, $i );
308  $accum[] = [ 'comment', [ $inner ] ];
309  $i = $lengthText;
310  } else {
311  // Search backwards for leading whitespace
312  $wsStart = $i ? ( $i - strspn( $revText, " \t", $lengthText - $i ) ) : 0;
313 
314  // Search forwards for trailing whitespace
315  // $wsEnd will be the position of the last space (or the '>' if there's none)
316  $wsEnd = $endPos + 2 + strspn( $text, " \t", $endPos + 3 );
317 
318  // Keep looking forward as long as we're finding more
319  // comments.
320  $comments = [ [ $wsStart, $wsEnd ] ];
321  while ( substr( $text, $wsEnd + 1, 4 ) == '<!--' ) {
322  $c = strpos( $text, '-->', $wsEnd + 4 );
323  if ( $c === false ) {
324  break;
325  }
326  $c = $c + 2 + strspn( $text, " \t", $c + 3 );
327  $comments[] = [ $wsEnd + 1, $c ];
328  $wsEnd = $c;
329  }
330 
331  // Eat the line if possible
332  // TODO: This could theoretically be done if $wsStart == 0, i.e. for comments at
333  // the overall start. That's not how Sanitizer::removeHTMLcomments() did it, but
334  // it's a possible beneficial b/c break.
335  if ( $wsStart > 0 && substr( $text, $wsStart - 1, 1 ) == "\n"
336  && substr( $text, $wsEnd + 1, 1 ) == "\n"
337  ) {
338  // Remove leading whitespace from the end of the accumulator
339  $wsLength = $i - $wsStart;
340  $endIndex = count( $accum ) - 1;
341 
342  // Sanity check
343  if ( $wsLength > 0
344  && $endIndex >= 0
345  && is_string( $accum[$endIndex] )
346  && strspn( $accum[$endIndex], " \t", -$wsLength ) === $wsLength
347  ) {
348  $accum[$endIndex] = substr( $accum[$endIndex], 0, -$wsLength );
349  }
350 
351  // Dump all but the last comment to the accumulator
352  foreach ( $comments as $j => $com ) {
353  $startPos = $com[0];
354  $endPos = $com[1] + 1;
355  if ( $j == ( count( $comments ) - 1 ) ) {
356  break;
357  }
358  $inner = substr( $text, $startPos, $endPos - $startPos );
359  $accum[] = [ 'comment', [ $inner ] ];
360  }
361 
362  // Do a line-start run next time to look for headings after the comment
363  $fakeLineStart = true;
364  } else {
365  // No line to eat, just take the comment itself
366  $startPos = $i;
367  $endPos += 2;
368  }
369 
370  if ( $stack->top ) {
371  $part = $stack->top->getCurrentPart();
372  if ( !( isset( $part->commentEnd ) && $part->commentEnd == $wsStart - 1 ) ) {
373  $part->visualEnd = $wsStart;
374  }
375  // Else comments abutting, no change in visual end
376  $part->commentEnd = $endPos;
377  }
378  $i = $endPos + 1;
379  $inner = substr( $text, $startPos, $endPos - $startPos + 1 );
380  $accum[] = [ 'comment', [ $inner ] ];
381  }
382  continue;
383  }
384  $name = $matches[1];
385  $lowerName = strtolower( $name );
386  $attrStart = $i + strlen( $name ) + 1;
387 
388  // Find end of tag
389  $tagEndPos = $noMoreGT ? false : strpos( $text, '>', $attrStart );
390  if ( $tagEndPos === false ) {
391  // Infinite backtrack
392  // Disable tag search to prevent worst-case O(N^2) performance
393  $noMoreGT = true;
394  self::addLiteral( $accum, '<' );
395  ++$i;
396  continue;
397  }
398 
399  // Handle ignored tags
400  if ( in_array( $lowerName, $ignoredTags ) ) {
401  $accum[] = [ 'ignore', [ substr( $text, $i, $tagEndPos - $i + 1 ) ] ];
402  $i = $tagEndPos + 1;
403  continue;
404  }
405 
406  $tagStartPos = $i;
407  if ( $text[$tagEndPos - 1] == '/' ) {
408  // Short end tag
409  $attrEnd = $tagEndPos - 1;
410  $inner = null;
411  $i = $tagEndPos + 1;
412  $close = null;
413  } else {
414  $attrEnd = $tagEndPos;
415  // Find closing tag
416  if (
417  !isset( $noMoreClosingTag[$name] ) &&
418  preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
419  $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 )
420  ) {
421  $inner = substr( $text, $tagEndPos + 1, $matches[0][1] - $tagEndPos - 1 );
422  $i = $matches[0][1] + strlen( $matches[0][0] );
423  $close = $matches[0][0];
424  } else {
425  // No end tag
426  if ( in_array( $name, $xmlishAllowMissingEndTag ) ) {
427  // Let it run out to the end of the text.
428  $inner = substr( $text, $tagEndPos + 1 );
429  $i = $lengthText;
430  $close = null;
431  } else {
432  // Don't match the tag, treat opening tag as literal and resume parsing.
433  $i = $tagEndPos + 1;
434  self::addLiteral( $accum,
435  substr( $text, $tagStartPos, $tagEndPos + 1 - $tagStartPos ) );
436  // Cache results, otherwise we have O(N^2) performance for input like <foo><foo><foo>...
437  $noMoreClosingTag[$name] = true;
438  continue;
439  }
440  }
441  }
442  // <includeonly> and <noinclude> just become <ignore> tags
443  if ( in_array( $lowerName, $ignoredElements ) ) {
444  $accum[] = [ 'ignore', [ substr( $text, $tagStartPos, $i - $tagStartPos ) ] ];
445  continue;
446  }
447 
448  if ( $attrEnd <= $attrStart ) {
449  $attr = '';
450  } else {
451  // Note that the attr element contains the whitespace between name and attribute,
452  // this is necessary for precise reconstruction during pre-save transform.
453  $attr = substr( $text, $attrStart, $attrEnd - $attrStart );
454  }
455 
456  $children = [
457  [ 'name', [ $name ] ],
458  [ 'attr', [ $attr ] ] ];
459  if ( $inner !== null ) {
460  $children[] = [ 'inner', [ $inner ] ];
461  }
462  if ( $close !== null ) {
463  $children[] = [ 'close', [ $close ] ];
464  }
465  $accum[] = [ 'ext', $children ];
466  } elseif ( $found == 'line-start' ) {
467  // Is this the start of a heading?
468  // Line break belongs before the heading element in any case
469  if ( $fakeLineStart ) {
470  $fakeLineStart = false;
471  } else {
472  self::addLiteral( $accum, $curChar );
473  $i++;
474  }
475 
476  $count = strspn( $text, '=', $i, 6 );
477  if ( $count == 1 && $findEquals ) {
478  // DWIM: This looks kind of like a name/value separator.
479  // Let's let the equals handler have it and break the potential
480  // heading. This is heuristic, but AFAICT the methods for
481  // completely correct disambiguation are very complex.
482  } elseif ( $count > 0 ) {
483  $piece = [
484  'open' => "\n",
485  'close' => "\n",
486  'parts' => [ new PPDPart_Hash( str_repeat( '=', $count ) ) ],
487  'startPos' => $i,
488  'count' => $count ];
489  $stack->push( $piece );
490  $accum =& $stack->getAccum();
491  extract( $stack->getFlags() );
492  $i += $count;
493  }
494  } elseif ( $found == 'line-end' ) {
495  $piece = $stack->top;
496  // A heading must be open, otherwise \n wouldn't have been in the search list
497  assert( $piece->open === "\n" );
498  $part = $piece->getCurrentPart();
499  // Search back through the input to see if it has a proper close.
500  // Do this using the reversed string since the other solutions
501  // (end anchor, etc.) are inefficient.
502  $wsLength = strspn( $revText, " \t", $lengthText - $i );
503  $searchStart = $i - $wsLength;
504  if ( isset( $part->commentEnd ) && $searchStart - 1 == $part->commentEnd ) {
505  // Comment found at line end
506  // Search for equals signs before the comment
507  $searchStart = $part->visualEnd;
508  $searchStart -= strspn( $revText, " \t", $lengthText - $searchStart );
509  }
510  $count = $piece->count;
511  $equalsLength = strspn( $revText, '=', $lengthText - $searchStart );
512  if ( $equalsLength > 0 ) {
513  if ( $searchStart - $equalsLength == $piece->startPos ) {
514  // This is just a single string of equals signs on its own line
515  // Replicate the doHeadings behavior /={count}(.+)={count}/
516  // First find out how many equals signs there really are (don't stop at 6)
517  $count = $equalsLength;
518  if ( $count < 3 ) {
519  $count = 0;
520  } else {
521  $count = min( 6, intval( ( $count - 1 ) / 2 ) );
522  }
523  } else {
524  $count = min( $equalsLength, $count );
525  }
526  if ( $count > 0 ) {
527  // Normal match, output <h>
528  $element = [ [ 'possible-h',
529  array_merge(
530  [
531  [ '@level', [ $count ] ],
532  [ '@i', [ $headingIndex++ ] ]
533  ],
534  $accum
535  )
536  ] ];
537  } else {
538  // Single equals sign on its own line, count=0
539  $element = $accum;
540  }
541  } else {
542  // No match, no <h>, just pass down the inner text
543  $element = $accum;
544  }
545  // Unwind the stack
546  $stack->pop();
547  $accum =& $stack->getAccum();
548  extract( $stack->getFlags() );
549 
550  // Append the result to the enclosing accumulator
551  array_splice( $accum, count( $accum ), 0, $element );
552 
553  // Note that we do NOT increment the input pointer.
554  // This is because the closing linebreak could be the opening linebreak of
555  // another heading. Infinite loops are avoided because the next iteration MUST
556  // hit the heading open case above, which unconditionally increments the
557  // input pointer.
558  } elseif ( $found == 'open' ) {
559  # count opening brace characters
560  $curLen = strlen( $curChar );
561  $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i );
562 
563  # we need to add to stack only if opening brace count is enough for one of the rules
564  if ( $count >= $rule['min'] ) {
565  # Add it to the stack
566  $piece = [
567  'open' => $curChar,
568  'close' => $rule['end'],
569  'count' => $count,
570  'lineStart' => ( $i > 0 && $text[$i - 1] == "\n" ),
571  ];
572 
573  $stack->push( $piece );
574  $accum =& $stack->getAccum();
575  extract( $stack->getFlags() );
576  } else {
577  # Add literal brace(s)
578  self::addLiteral( $accum, str_repeat( $curChar, $count ) );
579  }
580  $i += $curLen * $count;
581  } elseif ( $found == 'close' ) {
582  $piece = $stack->top;
583  # lets check if there are enough characters for closing brace
584  $maxCount = $piece->count;
585  $curLen = strlen( $curChar );
586  $count = ( $curLen > 1 ) ? 1 : strspn( $text, $curChar, $i, $maxCount );
587 
588  # check for maximum matching characters (if there are 5 closing
589  # characters, we will probably need only 3 - depending on the rules)
590  $rule = $this->rules[$piece->open];
591  if ( $count > $rule['max'] ) {
592  # The specified maximum exists in the callback array, unless the caller
593  # has made an error
594  $matchingCount = $rule['max'];
595  } else {
596  # Count is less than the maximum
597  # Skip any gaps in the callback array to find the true largest match
598  # Need to use array_key_exists not isset because the callback can be null
599  $matchingCount = $count;
600  while ( $matchingCount > 0 && !array_key_exists( $matchingCount, $rule['names'] ) ) {
601  --$matchingCount;
602  }
603  }
604 
605  if ( $matchingCount <= 0 ) {
606  # No matching element found in callback array
607  # Output a literal closing brace and continue
608  self::addLiteral( $accum, str_repeat( $curChar, $count ) );
609  $i += $curLen * $count;
610  continue;
611  }
612  $name = $rule['names'][$matchingCount];
613  if ( $name === null ) {
614  // No element, just literal text
615  $element = $piece->breakSyntax( $matchingCount );
616  self::addLiteral( $element, str_repeat( $rule['end'], $matchingCount ) );
617  } else {
618  # Create XML element
619  $parts = $piece->parts;
620  $titleAccum = $parts[0]->out;
621  unset( $parts[0] );
622 
623  $children = [];
624 
625  # The invocation is at the start of the line if lineStart is set in
626  # the stack, and all opening brackets are used up.
627  if ( $maxCount == $matchingCount && !empty( $piece->lineStart ) ) {
628  $children[] = [ '@lineStart', [ 1 ] ];
629  }
630  $titleNode = [ 'title', $titleAccum ];
631  $children[] = $titleNode;
632  $argIndex = 1;
633  foreach ( $parts as $part ) {
634  if ( isset( $part->eqpos ) ) {
635  $equalsNode = $part->out[$part->eqpos];
636  $nameNode = [ 'name', array_slice( $part->out, 0, $part->eqpos ) ];
637  $valueNode = [ 'value', array_slice( $part->out, $part->eqpos + 1 ) ];
638  $partNode = [ 'part', [ $nameNode, $equalsNode, $valueNode ] ];
639  $children[] = $partNode;
640  } else {
641  $nameNode = [ 'name', [ [ '@index', [ $argIndex++ ] ] ] ];
642  $valueNode = [ 'value', $part->out ];
643  $partNode = [ 'part', [ $nameNode, $valueNode ] ];
644  $children[] = $partNode;
645  }
646  }
647  $element = [ [ $name, $children ] ];
648  }
649 
650  # Advance input pointer
651  $i += $curLen * $matchingCount;
652 
653  # Unwind the stack
654  $stack->pop();
655  $accum =& $stack->getAccum();
656 
657  # Re-add the old stack element if it still has unmatched opening characters remaining
658  if ( $matchingCount < $piece->count ) {
659  $piece->parts = [ new PPDPart_Hash ];
660  $piece->count -= $matchingCount;
661  # do we still qualify for any callback with remaining count?
662  $min = $this->rules[$piece->open]['min'];
663  if ( $piece->count >= $min ) {
664  $stack->push( $piece );
665  $accum =& $stack->getAccum();
666  } else {
667  self::addLiteral( $accum, str_repeat( $piece->open, $piece->count ) );
668  }
669  }
670 
671  extract( $stack->getFlags() );
672 
673  # Add XML element to the enclosing accumulator
674  array_splice( $accum, count( $accum ), 0, $element );
675  } elseif ( $found == 'pipe' ) {
676  $findEquals = true; // shortcut for getFlags()
677  $stack->addPart();
678  $accum =& $stack->getAccum();
679  ++$i;
680  } elseif ( $found == 'equals' ) {
681  $findEquals = false; // shortcut for getFlags()
682  $accum[] = [ 'equals', [ '=' ] ];
683  $stack->getCurrentPart()->eqpos = count( $accum ) - 1;
684  ++$i;
685  } elseif ( $found == 'dash' ) {
686  self::addLiteral( $accum, '-' );
687  ++$i;
688  }
689  }
690 
691  # Output any remaining unclosed brackets
692  foreach ( $stack->stack as $piece ) {
693  array_splice( $stack->rootAccum, count( $stack->rootAccum ), 0, $piece->breakSyntax() );
694  }
695 
696  # Enable top-level headings
697  foreach ( $stack->rootAccum as &$node ) {
698  if ( is_array( $node ) && $node[PPNode_Hash_Tree::NAME] === 'possible-h' ) {
699  $node[PPNode_Hash_Tree::NAME] = 'h';
700  }
701  }
702 
703  $rootStore = [ [ 'root', $stack->rootAccum ] ];
704  $rootNode = new PPNode_Hash_Tree( $rootStore, 0 );
705 
706  // Cache
707  $tree = json_encode( $rootStore, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
708  if ( $tree !== false ) {
709  $this->cacheSetTree( $text, $flags, $tree );
710  }
711 
712  return $rootNode;
713  }
714 
715  private static function addLiteral( array &$accum, $text ) {
716  $n = count( $accum );
717  if ( $n && is_string( $accum[$n - 1] ) ) {
718  $accum[$n - 1] .= $text;
719  } else {
720  $accum[] = $text;
721  }
722  }
723 }
724 
729 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
730 class PPDStack_Hash extends PPDStack {
731  // @codingStandardsIgnoreEnd
732 
733  public function __construct() {
734  $this->elementClass = 'PPDStackElement_Hash';
735  parent::__construct();
736  $this->rootAccum = [];
737  }
738 }
739 
743 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
745  // @codingStandardsIgnoreEnd
746 
747  public function __construct( $data = [] ) {
748  $this->partClass = 'PPDPart_Hash';
749  parent::__construct( $data );
750  }
751 
758  public function breakSyntax( $openingCount = false ) {
759  if ( $this->open == "\n" ) {
760  $accum = $this->parts[0]->out;
761  } else {
762  if ( $openingCount === false ) {
763  $openingCount = $this->count;
764  }
765  $accum = [ str_repeat( $this->open, $openingCount ) ];
766  $lastIndex = 0;
767  $first = true;
768  foreach ( $this->parts as $part ) {
769  if ( $first ) {
770  $first = false;
771  } elseif ( is_string( $accum[$lastIndex] ) ) {
772  $accum[$lastIndex] .= '|';
773  } else {
774  $accum[++$lastIndex] = '|';
775  }
776  foreach ( $part->out as $node ) {
777  if ( is_string( $node ) && is_string( $accum[$lastIndex] ) ) {
778  $accum[$lastIndex] .= $node;
779  } else {
780  $accum[++$lastIndex] = $node;
781  }
782  }
783  }
784  }
785  return $accum;
786  }
787 }
788 
792 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
793 class PPDPart_Hash extends PPDPart {
794  // @codingStandardsIgnoreEnd
795 
796  public function __construct( $out = '' ) {
797  if ( $out !== '' ) {
798  $accum = [ $out ];
799  } else {
800  $accum = [];
801  }
802  parent::__construct( $accum );
803  }
804 }
805 
810 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
811 class PPFrame_Hash implements PPFrame {
812  // @codingStandardsIgnoreEnd
813 
817  public $parser;
818 
823 
827  public $title;
828  public $titleCache;
829 
835 
840  public $depth;
841 
842  private $volatile = false;
843  private $ttl = null;
844 
849 
854  public function __construct( $preprocessor ) {
855  $this->preprocessor = $preprocessor;
856  $this->parser = $preprocessor->parser;
857  $this->title = $this->parser->mTitle;
858  $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ];
859  $this->loopCheckHash = [];
860  $this->depth = 0;
861  $this->childExpansionCache = [];
862  }
863 
874  public function newChild( $args = false, $title = false, $indexOffset = 0 ) {
875  $namedArgs = [];
876  $numberedArgs = [];
877  if ( $title === false ) {
879  }
880  if ( $args !== false ) {
881  if ( $args instanceof PPNode_Hash_Array ) {
882  $args = $args->value;
883  } elseif ( !is_array( $args ) ) {
884  throw new MWException( __METHOD__ . ': $args must be array or PPNode_Hash_Array' );
885  }
886  foreach ( $args as $arg ) {
887  $bits = $arg->splitArg();
888  if ( $bits['index'] !== '' ) {
889  // Numbered parameter
890  $index = $bits['index'] - $indexOffset;
891  if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
892  $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
893  wfEscapeWikiText( $this->title ),
895  wfEscapeWikiText( $index ) )->text() );
896  $this->parser->addTrackingCategory( 'duplicate-args-category' );
897  }
898  $numberedArgs[$index] = $bits['value'];
899  unset( $namedArgs[$index] );
900  } else {
901  // Named parameter
902  $name = trim( $this->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) );
903  if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) {
904  $this->parser->getOutput()->addWarning( wfMessage( 'duplicate-args-warning',
905  wfEscapeWikiText( $this->title ),
907  wfEscapeWikiText( $name ) )->text() );
908  $this->parser->addTrackingCategory( 'duplicate-args-category' );
909  }
910  $namedArgs[$name] = $bits['value'];
911  unset( $numberedArgs[$name] );
912  }
913  }
914  }
915  return new PPTemplateFrame_Hash( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
916  }
917 
925  public function cachedExpand( $key, $root, $flags = 0 ) {
926  // we don't have a parent, so we don't have a cache
927  return $this->expand( $root, $flags );
928  }
929 
936  public function expand( $root, $flags = 0 ) {
937  static $expansionDepth = 0;
938  if ( is_string( $root ) ) {
939  return $root;
940  }
941 
942  if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
943  $this->parser->limitationWarn( 'node-count-exceeded',
944  $this->parser->mPPNodeCount,
945  $this->parser->mOptions->getMaxPPNodeCount()
946  );
947  return '<span class="error">Node-count limit exceeded</span>';
948  }
949  if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
950  $this->parser->limitationWarn( 'expansion-depth-exceeded',
951  $expansionDepth,
952  $this->parser->mOptions->getMaxPPExpandDepth()
953  );
954  return '<span class="error">Expansion depth limit exceeded</span>';
955  }
956  ++$expansionDepth;
957  if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
958  $this->parser->mHighestExpansionDepth = $expansionDepth;
959  }
960 
961  $outStack = [ '', '' ];
962  $iteratorStack = [ false, $root ];
963  $indexStack = [ 0, 0 ];
964 
965  while ( count( $iteratorStack ) > 1 ) {
966  $level = count( $outStack ) - 1;
967  $iteratorNode =& $iteratorStack[$level];
968  $out =& $outStack[$level];
969  $index =& $indexStack[$level];
970 
971  if ( is_array( $iteratorNode ) ) {
972  if ( $index >= count( $iteratorNode ) ) {
973  // All done with this iterator
974  $iteratorStack[$level] = false;
975  $contextNode = false;
976  } else {
977  $contextNode = $iteratorNode[$index];
978  $index++;
979  }
980  } elseif ( $iteratorNode instanceof PPNode_Hash_Array ) {
981  if ( $index >= $iteratorNode->getLength() ) {
982  // All done with this iterator
983  $iteratorStack[$level] = false;
984  $contextNode = false;
985  } else {
986  $contextNode = $iteratorNode->item( $index );
987  $index++;
988  }
989  } else {
990  // Copy to $contextNode and then delete from iterator stack,
991  // because this is not an iterator but we do have to execute it once
992  $contextNode = $iteratorStack[$level];
993  $iteratorStack[$level] = false;
994  }
995 
996  $newIterator = false;
997  $contextName = false;
998  $contextChildren = false;
999 
1000  if ( $contextNode === false ) {
1001  // nothing to do
1002  } elseif ( is_string( $contextNode ) ) {
1003  $out .= $contextNode;
1004  } elseif ( $contextNode instanceof PPNode_Hash_Array ) {
1005  $newIterator = $contextNode;
1006  } elseif ( $contextNode instanceof PPNode_Hash_Attr ) {
1007  // No output
1008  } elseif ( $contextNode instanceof PPNode_Hash_Text ) {
1009  $out .= $contextNode->value;
1010  } elseif ( $contextNode instanceof PPNode_Hash_Tree ) {
1011  $contextName = $contextNode->name;
1012  $contextChildren = $contextNode->getRawChildren();
1013  } elseif ( is_array( $contextNode ) ) {
1014  // Node descriptor array
1015  if ( count( $contextNode ) !== 2 ) {
1016  throw new MWException( __METHOD__.
1017  ': found an array where a node descriptor should be' );
1018  }
1019  list( $contextName, $contextChildren ) = $contextNode;
1020  } else {
1021  throw new MWException( __METHOD__ . ': Invalid parameter type' );
1022  }
1023 
1024  // Handle node descriptor array or tree object
1025  if ( $contextName === false ) {
1026  // Not a node, already handled above
1027  } elseif ( $contextName[0] === '@' ) {
1028  // Attribute: no output
1029  } elseif ( $contextName === 'template' ) {
1030  # Double-brace expansion
1031  $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
1032  if ( $flags & PPFrame::NO_TEMPLATES ) {
1033  $newIterator = $this->virtualBracketedImplode(
1034  '{{', '|', '}}',
1035  $bits['title'],
1036  $bits['parts']
1037  );
1038  } else {
1039  $ret = $this->parser->braceSubstitution( $bits, $this );
1040  if ( isset( $ret['object'] ) ) {
1041  $newIterator = $ret['object'];
1042  } else {
1043  $out .= $ret['text'];
1044  }
1045  }
1046  } elseif ( $contextName === 'tplarg' ) {
1047  # Triple-brace expansion
1048  $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren );
1049  if ( $flags & PPFrame::NO_ARGS ) {
1050  $newIterator = $this->virtualBracketedImplode(
1051  '{{{', '|', '}}}',
1052  $bits['title'],
1053  $bits['parts']
1054  );
1055  } else {
1056  $ret = $this->parser->argSubstitution( $bits, $this );
1057  if ( isset( $ret['object'] ) ) {
1058  $newIterator = $ret['object'];
1059  } else {
1060  $out .= $ret['text'];
1061  }
1062  }
1063  } elseif ( $contextName === 'comment' ) {
1064  # HTML-style comment
1065  # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
1066  # Not in RECOVER_COMMENTS mode (msgnw) though.
1067  if ( ( $this->parser->ot['html']
1068  || ( $this->parser->ot['pre'] && $this->parser->mOptions->getRemoveComments() )
1070  ) && !( $flags & PPFrame::RECOVER_COMMENTS )
1071  ) {
1072  $out .= '';
1073  } elseif ( $this->parser->ot['wiki'] && !( $flags & PPFrame::RECOVER_COMMENTS ) ) {
1074  # Add a strip marker in PST mode so that pstPass2() can
1075  # run some old-fashioned regexes on the result.
1076  # Not in RECOVER_COMMENTS mode (extractSections) though.
1077  $out .= $this->parser->insertStripItem( $contextChildren[0] );
1078  } else {
1079  # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
1080  $out .= $contextChildren[0];
1081  }
1082  } elseif ( $contextName === 'ignore' ) {
1083  # Output suppression used by <includeonly> etc.
1084  # OT_WIKI will only respect <ignore> in substed templates.
1085  # The other output types respect it unless NO_IGNORE is set.
1086  # extractSections() sets NO_IGNORE and so never respects it.
1087  if ( ( !isset( $this->parent ) && $this->parser->ot['wiki'] )
1088  || ( $flags & PPFrame::NO_IGNORE )
1089  ) {
1090  $out .= $contextChildren[0];
1091  } else {
1092  // $out .= '';
1093  }
1094  } elseif ( $contextName === 'ext' ) {
1095  # Extension tag
1096  $bits = PPNode_Hash_Tree::splitRawExt( $contextChildren ) +
1097  [ 'attr' => null, 'inner' => null, 'close' => null ];
1098  if ( $flags & PPFrame::NO_TAGS ) {
1099  $s = '<' . $bits['name']->getFirstChild()->value;
1100  if ( $bits['attr'] ) {
1101  $s .= $bits['attr']->getFirstChild()->value;
1102  }
1103  if ( $bits['inner'] ) {
1104  $s .= '>' . $bits['inner']->getFirstChild()->value;
1105  if ( $bits['close'] ) {
1106  $s .= $bits['close']->getFirstChild()->value;
1107  }
1108  } else {
1109  $s .= '/>';
1110  }
1111  $out .= $s;
1112  } else {
1113  $out .= $this->parser->extensionSubstitution( $bits, $this );
1114  }
1115  } elseif ( $contextName === 'h' ) {
1116  # Heading
1117  if ( $this->parser->ot['html'] ) {
1118  # Expand immediately and insert heading index marker
1119  $s = $this->expand( $contextChildren, $flags );
1120  $bits = PPNode_Hash_Tree::splitRawHeading( $contextChildren );
1121  $titleText = $this->title->getPrefixedDBkey();
1122  $this->parser->mHeadings[] = [ $titleText, $bits['i'] ];
1123  $serial = count( $this->parser->mHeadings ) - 1;
1124  $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
1125  $s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] );
1126  $this->parser->mStripState->addGeneral( $marker, '' );
1127  $out .= $s;
1128  } else {
1129  # Expand in virtual stack
1130  $newIterator = $contextChildren;
1131  }
1132  } else {
1133  # Generic recursive expansion
1134  $newIterator = $contextChildren;
1135  }
1136 
1137  if ( $newIterator !== false ) {
1138  $outStack[] = '';
1139  $iteratorStack[] = $newIterator;
1140  $indexStack[] = 0;
1141  } elseif ( $iteratorStack[$level] === false ) {
1142  // Return accumulated value to parent
1143  // With tail recursion
1144  while ( $iteratorStack[$level] === false && $level > 0 ) {
1145  $outStack[$level - 1] .= $out;
1146  array_pop( $outStack );
1147  array_pop( $iteratorStack );
1148  array_pop( $indexStack );
1149  $level--;
1150  }
1151  }
1152  }
1153  --$expansionDepth;
1154  return $outStack[0];
1155  }
1156 
1163  public function implodeWithFlags( $sep, $flags /*, ... */ ) {
1164  $args = array_slice( func_get_args(), 2 );
1165 
1166  $first = true;
1167  $s = '';
1168  foreach ( $args as $root ) {
1169  if ( $root instanceof PPNode_Hash_Array ) {
1170  $root = $root->value;
1171  }
1172  if ( !is_array( $root ) ) {
1173  $root = [ $root ];
1174  }
1175  foreach ( $root as $node ) {
1176  if ( $first ) {
1177  $first = false;
1178  } else {
1179  $s .= $sep;
1180  }
1181  $s .= $this->expand( $node, $flags );
1182  }
1183  }
1184  return $s;
1185  }
1186 
1194  public function implode( $sep /*, ... */ ) {
1195  $args = array_slice( func_get_args(), 1 );
1196 
1197  $first = true;
1198  $s = '';
1199  foreach ( $args as $root ) {
1200  if ( $root instanceof PPNode_Hash_Array ) {
1201  $root = $root->value;
1202  }
1203  if ( !is_array( $root ) ) {
1204  $root = [ $root ];
1205  }
1206  foreach ( $root as $node ) {
1207  if ( $first ) {
1208  $first = false;
1209  } else {
1210  $s .= $sep;
1211  }
1212  $s .= $this->expand( $node );
1213  }
1214  }
1215  return $s;
1216  }
1217 
1226  public function virtualImplode( $sep /*, ... */ ) {
1227  $args = array_slice( func_get_args(), 1 );
1228  $out = [];
1229  $first = true;
1230 
1231  foreach ( $args as $root ) {
1232  if ( $root instanceof PPNode_Hash_Array ) {
1233  $root = $root->value;
1234  }
1235  if ( !is_array( $root ) ) {
1236  $root = [ $root ];
1237  }
1238  foreach ( $root as $node ) {
1239  if ( $first ) {
1240  $first = false;
1241  } else {
1242  $out[] = $sep;
1243  }
1244  $out[] = $node;
1245  }
1246  }
1247  return new PPNode_Hash_Array( $out );
1248  }
1249 
1259  public function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
1260  $args = array_slice( func_get_args(), 3 );
1261  $out = [ $start ];
1262  $first = true;
1263 
1264  foreach ( $args as $root ) {
1265  if ( $root instanceof PPNode_Hash_Array ) {
1266  $root = $root->value;
1267  }
1268  if ( !is_array( $root ) ) {
1269  $root = [ $root ];
1270  }
1271  foreach ( $root as $node ) {
1272  if ( $first ) {
1273  $first = false;
1274  } else {
1275  $out[] = $sep;
1276  }
1277  $out[] = $node;
1278  }
1279  }
1280  $out[] = $end;
1281  return new PPNode_Hash_Array( $out );
1282  }
1283 
1284  public function __toString() {
1285  return 'frame{}';
1286  }
1287 
1292  public function getPDBK( $level = false ) {
1293  if ( $level === false ) {
1294  return $this->title->getPrefixedDBkey();
1295  } else {
1296  return isset( $this->titleCache[$level] ) ? $this->titleCache[$level] : false;
1297  }
1298  }
1299 
1303  public function getArguments() {
1304  return [];
1305  }
1306 
1310  public function getNumberedArguments() {
1311  return [];
1312  }
1313 
1317  public function getNamedArguments() {
1318  return [];
1319  }
1320 
1326  public function isEmpty() {
1327  return true;
1328  }
1329 
1334  public function getArgument( $name ) {
1335  return false;
1336  }
1337 
1345  public function loopCheck( $title ) {
1346  return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
1347  }
1348 
1354  public function isTemplate() {
1355  return false;
1356  }
1357 
1363  public function getTitle() {
1364  return $this->title;
1365  }
1366 
1372  public function setVolatile( $flag = true ) {
1373  $this->volatile = $flag;
1374  }
1375 
1381  public function isVolatile() {
1382  return $this->volatile;
1383  }
1384 
1390  public function setTTL( $ttl ) {
1391  if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
1392  $this->ttl = $ttl;
1393  }
1394  }
1395 
1401  public function getTTL() {
1402  return $this->ttl;
1403  }
1404 }
1405 
1410 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
1412  // @codingStandardsIgnoreEnd
1413 
1416 
1424  public function __construct( $preprocessor, $parent = false, $numberedArgs = [],
1425  $namedArgs = [], $title = false
1426  ) {
1427  parent::__construct( $preprocessor );
1428 
1429  $this->parent = $parent;
1430  $this->numberedArgs = $numberedArgs;
1431  $this->namedArgs = $namedArgs;
1432  $this->title = $title;
1433  $pdbk = $title ? $title->getPrefixedDBkey() : false;
1434  $this->titleCache = $parent->titleCache;
1435  $this->titleCache[] = $pdbk;
1436  $this->loopCheckHash = /*clone*/ $parent->loopCheckHash;
1437  if ( $pdbk !== false ) {
1438  $this->loopCheckHash[$pdbk] = true;
1439  }
1440  $this->depth = $parent->depth + 1;
1441  $this->numberedExpansionCache = $this->namedExpansionCache = [];
1442  }
1443 
1444  public function __toString() {
1445  $s = 'tplframe{';
1446  $first = true;
1447  $args = $this->numberedArgs + $this->namedArgs;
1448  foreach ( $args as $name => $value ) {
1449  if ( $first ) {
1450  $first = false;
1451  } else {
1452  $s .= ', ';
1453  }
1454  $s .= "\"$name\":\"" .
1455  str_replace( '"', '\\"', $value->__toString() ) . '"';
1456  }
1457  $s .= '}';
1458  return $s;
1459  }
1460 
1468  public function cachedExpand( $key, $root, $flags = 0 ) {
1469  if ( isset( $this->parent->childExpansionCache[$key] ) ) {
1470  return $this->parent->childExpansionCache[$key];
1471  }
1472  $retval = $this->expand( $root, $flags );
1473  if ( !$this->isVolatile() ) {
1474  $this->parent->childExpansionCache[$key] = $retval;
1475  }
1476  return $retval;
1477  }
1478 
1484  public function isEmpty() {
1485  return !count( $this->numberedArgs ) && !count( $this->namedArgs );
1486  }
1487 
1491  public function getArguments() {
1492  $arguments = [];
1493  foreach ( array_merge(
1494  array_keys( $this->numberedArgs ),
1495  array_keys( $this->namedArgs ) ) as $key ) {
1496  $arguments[$key] = $this->getArgument( $key );
1497  }
1498  return $arguments;
1499  }
1500 
1504  public function getNumberedArguments() {
1505  $arguments = [];
1506  foreach ( array_keys( $this->numberedArgs ) as $key ) {
1507  $arguments[$key] = $this->getArgument( $key );
1508  }
1509  return $arguments;
1510  }
1511 
1515  public function getNamedArguments() {
1516  $arguments = [];
1517  foreach ( array_keys( $this->namedArgs ) as $key ) {
1518  $arguments[$key] = $this->getArgument( $key );
1519  }
1520  return $arguments;
1521  }
1522 
1527  public function getNumberedArgument( $index ) {
1528  if ( !isset( $this->numberedArgs[$index] ) ) {
1529  return false;
1530  }
1531  if ( !isset( $this->numberedExpansionCache[$index] ) ) {
1532  # No trimming for unnamed arguments
1533  $this->numberedExpansionCache[$index] = $this->parent->expand(
1534  $this->numberedArgs[$index],
1536  );
1537  }
1538  return $this->numberedExpansionCache[$index];
1539  }
1540 
1545  public function getNamedArgument( $name ) {
1546  if ( !isset( $this->namedArgs[$name] ) ) {
1547  return false;
1548  }
1549  if ( !isset( $this->namedExpansionCache[$name] ) ) {
1550  # Trim named arguments post-expand, for backwards compatibility
1551  $this->namedExpansionCache[$name] = trim(
1552  $this->parent->expand( $this->namedArgs[$name], PPFrame::STRIP_COMMENTS ) );
1553  }
1554  return $this->namedExpansionCache[$name];
1555  }
1556 
1561  public function getArgument( $name ) {
1562  $text = $this->getNumberedArgument( $name );
1563  if ( $text === false ) {
1564  $text = $this->getNamedArgument( $name );
1565  }
1566  return $text;
1567  }
1568 
1574  public function isTemplate() {
1575  return true;
1576  }
1577 
1578  public function setVolatile( $flag = true ) {
1579  parent::setVolatile( $flag );
1580  $this->parent->setVolatile( $flag );
1581  }
1582 
1583  public function setTTL( $ttl ) {
1584  parent::setTTL( $ttl );
1585  $this->parent->setTTL( $ttl );
1586  }
1587 }
1588 
1593 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
1595  // @codingStandardsIgnoreEnd
1596 
1597  public $args;
1598 
1599  public function __construct( $preprocessor, $args ) {
1600  parent::__construct( $preprocessor );
1601  $this->args = $args;
1602  }
1603 
1604  public function __toString() {
1605  $s = 'cstmframe{';
1606  $first = true;
1607  foreach ( $this->args as $name => $value ) {
1608  if ( $first ) {
1609  $first = false;
1610  } else {
1611  $s .= ', ';
1612  }
1613  $s .= "\"$name\":\"" .
1614  str_replace( '"', '\\"', $value->__toString() ) . '"';
1615  }
1616  $s .= '}';
1617  return $s;
1618  }
1619 
1623  public function isEmpty() {
1624  return !count( $this->args );
1625  }
1626 
1631  public function getArgument( $index ) {
1632  if ( !isset( $this->args[$index] ) ) {
1633  return false;
1634  }
1635  return $this->args[$index];
1636  }
1637 
1638  public function getArguments() {
1639  return $this->args;
1640  }
1641 }
1642 
1646 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
1647 class PPNode_Hash_Tree implements PPNode {
1648  // @codingStandardsIgnoreEnd
1649 
1650  public $name;
1651 
1657  private $rawChildren;
1658 
1662  private $store;
1663 
1667  private $index;
1668 
1673  const NAME = 0;
1674 
1679  const CHILDREN = 1;
1680 
1688  public function __construct( array $store, $index ) {
1689  $this->store = $store;
1690  $this->index = $index;
1691  list( $this->name, $this->rawChildren ) = $this->store[$index];
1692  }
1693 
1702  public static function factory( array $store, $index ) {
1703  if ( !isset( $store[$index] ) ) {
1704  return false;
1705  }
1706 
1707  $descriptor = $store[$index];
1708  if ( is_string( $descriptor ) ) {
1709  $class = 'PPNode_Hash_Text';
1710  } elseif ( is_array( $descriptor ) ) {
1711  if ( $descriptor[self::NAME][0] === '@' ) {
1712  $class = 'PPNode_Hash_Attr';
1713  } else {
1714  $class = 'PPNode_Hash_Tree';
1715  }
1716  } else {
1717  throw new MWException( __METHOD__.': invalid node descriptor' );
1718  }
1719  return new $class( $store, $index );
1720  }
1721 
1725  public function __toString() {
1726  $inner = '';
1727  $attribs = '';
1728  for ( $node = $this->getFirstChild(); $node; $node = $node->getNextSibling() ) {
1729  if ( $node instanceof PPNode_Hash_Attr ) {
1730  $attribs .= ' ' . $node->name . '="' . htmlspecialchars( $node->value ) . '"';
1731  } else {
1732  $inner .= $node->__toString();
1733  }
1734  }
1735  if ( $inner === '' ) {
1736  return "<{$this->name}$attribs/>";
1737  } else {
1738  return "<{$this->name}$attribs>$inner</{$this->name}>";
1739  }
1740  }
1741 
1745  public function getChildren() {
1746  $children = [];
1747  foreach ( $this->rawChildren as $i => $child ) {
1748  $children[] = self::factory( $this->rawChildren, $i );
1749  }
1750  return new PPNode_Hash_Array( $children );
1751  }
1752 
1760  public function getFirstChild() {
1761  if ( !isset( $this->rawChildren[0] ) ) {
1762  return false;
1763  } else {
1764  return self::factory( $this->rawChildren, 0 );
1765  }
1766  }
1767 
1775  public function getNextSibling() {
1776  return self::factory( $this->store, $this->index + 1 );
1777  }
1778 
1785  public function getChildrenOfType( $name ) {
1786  $children = [];
1787  foreach ( $this->rawChildren as $i => $child ) {
1788  if ( is_array( $child ) && $child[self::NAME] === $name ) {
1789  $children[] = self::factory( $this->rawChildren, $i );
1790  }
1791  }
1792  return new PPNode_Hash_Array( $children );
1793  }
1794 
1799  public function getRawChildren() {
1800  return $this->rawChildren;
1801  }
1802 
1806  public function getLength() {
1807  return false;
1808  }
1809 
1814  public function item( $i ) {
1815  return false;
1816  }
1817 
1821  public function getName() {
1822  return $this->name;
1823  }
1824 
1834  public function splitArg() {
1835  return self::splitRawArg( $this->rawChildren );
1836  }
1837 
1841  public static function splitRawArg( array $children ) {
1842  $bits = [];
1843  foreach ( $children as $i => $child ) {
1844  if ( !is_array( $child ) ) {
1845  continue;
1846  }
1847  if ( $child[self::NAME] === 'name' ) {
1848  $bits['name'] = new self( $children, $i );
1849  if ( isset( $child[self::CHILDREN][0][self::NAME] )
1850  && $child[self::CHILDREN][0][self::NAME] === '@index'
1851  ) {
1852  $bits['index'] = $child[self::CHILDREN][0][self::CHILDREN][0];
1853  }
1854  } elseif ( $child[self::NAME] === 'value' ) {
1855  $bits['value'] = new self( $children, $i );
1856  }
1857  }
1858 
1859  if ( !isset( $bits['name'] ) ) {
1860  throw new MWException( 'Invalid brace node passed to ' . __METHOD__ );
1861  }
1862  if ( !isset( $bits['index'] ) ) {
1863  $bits['index'] = '';
1864  }
1865  return $bits;
1866  }
1867 
1875  public function splitExt() {
1876  return self::splitRawExt( $this->rawChildren );
1877  }
1878 
1882  public static function splitRawExt( array $children ) {
1883  $bits = [];
1884  foreach ( $children as $i => $child ) {
1885  if ( !is_array( $child ) ) {
1886  continue;
1887  }
1888  switch ( $child[self::NAME] ) {
1889  case 'name':
1890  $bits['name'] = new self( $children, $i );
1891  break;
1892  case 'attr':
1893  $bits['attr'] = new self( $children, $i );
1894  break;
1895  case 'inner':
1896  $bits['inner'] = new self( $children, $i );
1897  break;
1898  case 'close':
1899  $bits['close'] = new self( $children, $i );
1900  break;
1901  }
1902  }
1903  if ( !isset( $bits['name'] ) ) {
1904  throw new MWException( 'Invalid ext node passed to ' . __METHOD__ );
1905  }
1906  return $bits;
1907  }
1908 
1915  public function splitHeading() {
1916  if ( $this->name !== 'h' ) {
1917  throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
1918  }
1919  return self::splitRawHeading( $this->rawChildren );
1920  }
1921 
1925  public static function splitRawHeading( array $children ) {
1926  $bits = [];
1927  foreach ( $children as $i => $child ) {
1928  if ( !is_array( $child ) ) {
1929  continue;
1930  }
1931  if ( $child[self::NAME] === '@i' ) {
1932  $bits['i'] = $child[self::CHILDREN][0];
1933  } elseif ( $child[self::NAME] === '@level' ) {
1934  $bits['level'] = $child[self::CHILDREN][0];
1935  }
1936  }
1937  if ( !isset( $bits['i'] ) ) {
1938  throw new MWException( 'Invalid h node passed to ' . __METHOD__ );
1939  }
1940  return $bits;
1941  }
1942 
1949  public function splitTemplate() {
1950  return self::splitRawTemplate( $this->rawChildren );
1951  }
1952 
1956  public static function splitRawTemplate( array $children ) {
1957  $parts = [];
1958  $bits = [ 'lineStart' => '' ];
1959  foreach ( $children as $i => $child ) {
1960  if ( !is_array( $child ) ) {
1961  continue;
1962  }
1963  switch ( $child[self::NAME] ) {
1964  case 'title':
1965  $bits['title'] = new self( $children, $i );
1966  break;
1967  case 'part':
1968  $parts[] = new self( $children, $i );
1969  break;
1970  case '@lineStart':
1971  $bits['lineStart'] = '1';
1972  break;
1973  }
1974  }
1975  if ( !isset( $bits['title'] ) ) {
1976  throw new MWException( 'Invalid node passed to ' . __METHOD__ );
1977  }
1978  $bits['parts'] = new PPNode_Hash_Array( $parts );
1979  return $bits;
1980  }
1981 }
1982 
1986 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
1987 class PPNode_Hash_Text implements PPNode {
1988  // @codingStandardsIgnoreEnd
1989 
1990  public $value;
1991  private $store, $index;
1992 
2000  public function __construct( array $store, $index ) {
2001  $this->value = $store[$index];
2002  if ( !is_scalar( $this->value ) ) {
2003  throw new MWException( __CLASS__ . ' given object instead of string' );
2004  }
2005  $this->store = $store;
2006  $this->index = $index;
2007  }
2008 
2009  public function __toString() {
2010  return htmlspecialchars( $this->value );
2011  }
2012 
2013  public function getNextSibling() {
2014  return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
2015  }
2016 
2017  public function getChildren() {
2018  return false;
2019  }
2020 
2021  public function getFirstChild() {
2022  return false;
2023  }
2024 
2025  public function getChildrenOfType( $name ) {
2026  return false;
2027  }
2028 
2029  public function getLength() {
2030  return false;
2031  }
2032 
2033  public function item( $i ) {
2034  return false;
2035  }
2036 
2037  public function getName() {
2038  return '#text';
2039  }
2040 
2041  public function splitArg() {
2042  throw new MWException( __METHOD__ . ': not supported' );
2043  }
2044 
2045  public function splitExt() {
2046  throw new MWException( __METHOD__ . ': not supported' );
2047  }
2048 
2049  public function splitHeading() {
2050  throw new MWException( __METHOD__ . ': not supported' );
2051  }
2052 }
2053 
2057 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
2058 class PPNode_Hash_Array implements PPNode {
2059  // @codingStandardsIgnoreEnd
2060 
2061  public $value;
2062 
2063  public function __construct( $value ) {
2064  $this->value = $value;
2065  }
2066 
2067  public function __toString() {
2068  return var_export( $this, true );
2069  }
2070 
2071  public function getLength() {
2072  return count( $this->value );
2073  }
2074 
2075  public function item( $i ) {
2076  return $this->value[$i];
2077  }
2078 
2079  public function getName() {
2080  return '#nodelist';
2081  }
2082 
2083  public function getNextSibling() {
2084  return false;
2085  }
2086 
2087  public function getChildren() {
2088  return false;
2089  }
2090 
2091  public function getFirstChild() {
2092  return false;
2093  }
2094 
2095  public function getChildrenOfType( $name ) {
2096  return false;
2097  }
2098 
2099  public function splitArg() {
2100  throw new MWException( __METHOD__ . ': not supported' );
2101  }
2102 
2103  public function splitExt() {
2104  throw new MWException( __METHOD__ . ': not supported' );
2105  }
2106 
2107  public function splitHeading() {
2108  throw new MWException( __METHOD__ . ': not supported' );
2109  }
2110 }
2111 
2115 // @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
2116 class PPNode_Hash_Attr implements PPNode {
2117  // @codingStandardsIgnoreEnd
2118 
2119  public $name, $value;
2120  private $store, $index;
2121 
2129  public function __construct( array $store, $index ) {
2130  $descriptor = $store[$index];
2131  if ( $descriptor[PPNode_Hash_Tree::NAME][0] !== '@' ) {
2132  throw new MWException( __METHOD__.': invalid name in attribute descriptor' );
2133  }
2134  $this->name = substr( $descriptor[PPNode_Hash_Tree::NAME], 1 );
2135  $this->value = $descriptor[PPNode_Hash_Tree::CHILDREN][0];
2136  $this->store = $store;
2137  $this->index = $index;
2138  }
2139 
2140  public function __toString() {
2141  return "<@{$this->name}>" . htmlspecialchars( $this->value ) . "</@{$this->name}>";
2142  }
2143 
2144  public function getName() {
2145  return $this->name;
2146  }
2147 
2148  public function getNextSibling() {
2149  return PPNode_Hash_Tree::factory( $this->store, $this->index + 1 );
2150  }
2151 
2152  public function getChildren() {
2153  return false;
2154  }
2155 
2156  public function getFirstChild() {
2157  return false;
2158  }
2159 
2160  public function getChildrenOfType( $name ) {
2161  return false;
2162  }
2163 
2164  public function getLength() {
2165  return false;
2166  }
2167 
2168  public function item( $i ) {
2169  return false;
2170  }
2171 
2172  public function splitArg() {
2173  throw new MWException( __METHOD__ . ': not supported' );
2174  }
2175 
2176  public function splitExt() {
2177  throw new MWException( __METHOD__ . ': not supported' );
2178  }
2179 
2180  public function splitHeading() {
2181  throw new MWException( __METHOD__ . ': not supported' );
2182  }
2183 }
PPFrame_Hash\getArguments
getArguments()
Definition: Preprocessor_Hash.php:1303
PPNode_Hash_Tree\getLength
getLength()
Definition: Preprocessor_Hash.php:1806
PPFrame\STRIP_COMMENTS
const STRIP_COMMENTS
Definition: Preprocessor.php:168
PPDPart
Definition: Preprocessor_DOM.php:945
PPNode_Hash_Tree\getChildrenOfType
getChildrenOfType( $name)
Get an array of the children with a given node name.
Definition: Preprocessor_Hash.php:1785
PPCustomFrame_Hash\__toString
__toString()
Definition: Preprocessor_Hash.php:1604
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
PPFrame_Hash\$depth
$depth
Recursion depth of this frame, top = 0 Note that this is NOT the same as expansion depth in expand()
Definition: Preprocessor_Hash.php:840
PPNode_Hash_Tree\item
item( $i)
Definition: Preprocessor_Hash.php:1814
PPFrame_Hash\$childExpansionCache
array $childExpansionCache
Definition: Preprocessor_Hash.php:848
PPDPart\$out
string $out
Output accumulator string.
Definition: Preprocessor_DOM.php:949
PPTemplateFrame_Hash\setVolatile
setVolatile( $flag=true)
Set the volatile flag.
Definition: Preprocessor_Hash.php:1578
PPFrame_Hash\getPDBK
getPDBK( $level=false)
Definition: Preprocessor_Hash.php:1292
PPDPart_Hash
Definition: Preprocessor_Hash.php:793
PPNode_Hash_Tree\$store
$store
The store array for the siblings of this node, including this node itself.
Definition: Preprocessor_Hash.php:1662
PPFrame_Hash\getNumberedArguments
getNumberedArguments()
Definition: Preprocessor_Hash.php:1310
PPNode_Hash_Array\splitHeading
splitHeading()
Split an "<h>" node.
Definition: Preprocessor_Hash.php:2107
PPFrame_Hash\expand
expand( $root, $flags=0)
Definition: Preprocessor_Hash.php:936
PPNode_Hash_Tree\getFirstChild
getFirstChild()
Get the first child, or false if there is none.
Definition: Preprocessor_Hash.php:1760
PPTemplateFrame_Hash\$parent
$parent
Definition: Preprocessor_Hash.php:1414
PPFrame\NO_ARGS
const NO_ARGS
Definition: Preprocessor.php:166
PPNode_Hash_Attr\$name
$name
Definition: Preprocessor_Hash.php:2119
PPTemplateFrame_Hash\$numberedArgs
$numberedArgs
Definition: Preprocessor_Hash.php:1414
captcha-old.count
count
Definition: captcha-old.py:225
PPNode_Hash_Tree\splitRawExt
static splitRawExt(array $children)
Like splitExt() but for a raw child array.
Definition: Preprocessor_Hash.php:1882
Title\getPrefixedDBkey
getPrefixedDBkey()
Get the prefixed database key form.
Definition: Title.php:1439
PPTemplateFrame_Hash\$numberedExpansionCache
$numberedExpansionCache
Definition: Preprocessor_Hash.php:1415
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
Preprocessor_Hash\__construct
__construct( $parser)
Definition: Preprocessor_Hash.php:54
PPFrame_Hash
An expansion frame, used as a context to expand the result of preprocessToObj()
Definition: Preprocessor_Hash.php:811
PPFrame\NO_IGNORE
const NO_IGNORE
Definition: Preprocessor.php:169
PPNode_Hash_Text\splitHeading
splitHeading()
Split an "<h>" node.
Definition: Preprocessor_Hash.php:2049
PPNode_Hash_Tree\splitHeading
splitHeading()
Split an "<h>" node.
Definition: Preprocessor_Hash.php:1915
PPNode_Hash_Attr\splitExt
splitExt()
Split an "<ext>" node into an associative array containing name, attr, inner and close All values in ...
Definition: Preprocessor_Hash.php:2176
PPCustomFrame_Hash\isEmpty
isEmpty()
Definition: Preprocessor_Hash.php:1623
PPNode_Hash_Text\getChildrenOfType
getChildrenOfType( $name)
Get all children of this tree node which have a given name.
Definition: Preprocessor_Hash.php:2025
PPNode_Hash_Tree\splitExt
splitExt()
Split an "<ext>" node into an associative array containing name, attr, inner and close All values in ...
Definition: Preprocessor_Hash.php:1875
PPFrame_Hash\getNamedArguments
getNamedArguments()
Definition: Preprocessor_Hash.php:1317
PPFrame_Hash\getTTL
getTTL()
Get the TTL.
Definition: Preprocessor_Hash.php:1401
PPTemplateFrame_Hash\__construct
__construct( $preprocessor, $parent=false, $numberedArgs=[], $namedArgs=[], $title=false)
Definition: Preprocessor_Hash.php:1424
PPNode_Hash_Text\getLength
getLength()
Returns the length of the array, or false if this is not an array-type node.
Definition: Preprocessor_Hash.php:2029
PPNode_Hash_Tree\splitRawArg
static splitRawArg(array $children)
Like splitArg() but for a raw child array.
Definition: Preprocessor_Hash.php:1841
Preprocessor_Hash\newFrame
newFrame()
Definition: Preprocessor_Hash.php:61
PPFrame_Hash\__construct
__construct( $preprocessor)
Construct a new preprocessor frame.
Definition: Preprocessor_Hash.php:854
PPTemplateFrame_Hash\getNumberedArgument
getNumberedArgument( $index)
Definition: Preprocessor_Hash.php:1527
$s
$s
Definition: mergeMessageFileList.php:188
PPNode_Hash_Tree\splitRawHeading
static splitRawHeading(array $children)
Like splitHeading() but for a raw child array.
Definition: Preprocessor_Hash.php:1925
PPDStackElement
Definition: Preprocessor_DOM.php:850
PPFrame_Hash\$loopCheckHash
$loopCheckHash
Hashtable listing templates which are disallowed for expansion in this frame, having been encountered...
Definition: Preprocessor_Hash.php:834
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
Preprocessor_Hash
Differences from DOM schema:
Definition: Preprocessor_Hash.php:43
PPTemplateFrame_Hash\isEmpty
isEmpty()
Returns true if there are no arguments in this frame.
Definition: Preprocessor_Hash.php:1484
PPNode_Hash_Text\__construct
__construct(array $store, $index)
Construct an object using the data from $store[$index].
Definition: Preprocessor_Hash.php:2000
Makefile.open
open
Definition: Makefile.py:18
PPNode_Hash_Array\splitExt
splitExt()
Split an "<ext>" node into an associative array containing name, attr, inner and close All values in ...
Definition: Preprocessor_Hash.php:2103
PPTemplateFrame_Hash\$namedArgs
$namedArgs
Definition: Preprocessor_Hash.php:1414
PPNode_Hash_Attr\$store
$store
Definition: Preprocessor_Hash.php:2120
PPFrame\RECOVER_COMMENTS
const RECOVER_COMMENTS
Definition: Preprocessor.php:170
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
PPFrame\NO_TEMPLATES
const NO_TEMPLATES
Definition: Preprocessor.php:167
Preprocessor
Definition: Preprocessor.php:29
PPNode_Hash_Array\splitArg
splitArg()
Split a "<part>" node into an associative array containing: name PPNode name index String index value...
Definition: Preprocessor_Hash.php:2099
Preprocessor_Hash\newCustomFrame
newCustomFrame( $args)
Definition: Preprocessor_Hash.php:69
PPFrame_Hash\$titleCache
$titleCache
Definition: Preprocessor_Hash.php:828
PPFrame_Hash\setVolatile
setVolatile( $flag=true)
Set the volatile flag.
Definition: Preprocessor_Hash.php:1372
PPNode_Hash_Array\getFirstChild
getFirstChild()
Get the first child of a tree node.
Definition: Preprocessor_Hash.php:2091
PPNode_Hash_Attr\item
item( $i)
Returns an item of an array-type node.
Definition: Preprocessor_Hash.php:2168
PPNode_Hash_Attr\getFirstChild
getFirstChild()
Get the first child of a tree node.
Definition: Preprocessor_Hash.php:2156
PPNode_Hash_Attr\splitHeading
splitHeading()
Split an "<h>" node.
Definition: Preprocessor_Hash.php:2180
PPNode_Hash_Tree\$name
$name
Definition: Preprocessor_Hash.php:1650
PPFrame_Hash\virtualBracketedImplode
virtualBracketedImplode( $start, $sep, $end)
Virtual implode with brackets.
Definition: Preprocessor_Hash.php:1259
PPNode_Hash_Attr\getChildrenOfType
getChildrenOfType( $name)
Get all children of this tree node which have a given name.
Definition: Preprocessor_Hash.php:2160
MWException
MediaWiki exception.
Definition: MWException.php:26
PPNode_Hash_Tree\CHILDREN
const CHILDREN
The offset of the child list within descriptors, used in some places for readability.
Definition: Preprocessor_Hash.php:1679
PPNode_Hash_Array\getChildrenOfType
getChildrenOfType( $name)
Get all children of this tree node which have a given name.
Definition: Preprocessor_Hash.php:2095
PPTemplateFrame_Hash\getArguments
getArguments()
Definition: Preprocessor_Hash.php:1491
PPNode_Hash_Tree\getNextSibling
getNextSibling()
Get the next sibling, or false if there is none.
Definition: Preprocessor_Hash.php:1775
PPNode_Hash_Text\getNextSibling
getNextSibling()
Get the next sibling of any node.
Definition: Preprocessor_Hash.php:2013
PPNode_Hash_Text\__toString
__toString()
Definition: Preprocessor_Hash.php:2009
PPNode_Hash_Array\getLength
getLength()
Returns the length of the array, or false if this is not an array-type node.
Definition: Preprocessor_Hash.php:2071
Preprocessor_Hash\newPartNodeArray
newPartNodeArray( $values)
Definition: Preprocessor_Hash.php:77
PPNode_Hash_Tree\splitTemplate
splitTemplate()
Split a "<template>" or "<tplarg>" node.
Definition: Preprocessor_Hash.php:1949
PPDStackElement\$count
int $count
Number of opening characters found (number of "=" for heading)
Definition: Preprocessor_DOM.php:864
PPNode_Hash_Tree\__toString
__toString()
Convert a node to XML, for debugging.
Definition: Preprocessor_Hash.php:1725
$matches
$matches
Definition: NoLocalSettings.php:24
PPFrame_Hash\__toString
__toString()
Definition: Preprocessor_Hash.php:1284
PPDStackElement_Hash
Definition: Preprocessor_Hash.php:744
PPCustomFrame_Hash\__construct
__construct( $preprocessor, $args)
Definition: Preprocessor_Hash.php:1599
PPTemplateFrame_Hash\getNamedArgument
getNamedArgument( $name)
Definition: Preprocessor_Hash.php:1545
PPNode
There are three types of nodes:
Definition: Preprocessor.php:358
$attribs
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing & $attribs
Definition: hooks.txt:1956
Preprocessor_Hash\CACHE_VERSION
const CACHE_VERSION
Definition: Preprocessor_Hash.php:52
PPFrame_Hash\setTTL
setTTL( $ttl)
Set the TTL.
Definition: Preprocessor_Hash.php:1390
store
MediaWiki s SiteStore can be cached and stored in a flat in a json format If the SiteStore is frequently the file cache may provide a performance benefit over a database store
Definition: sitescache.txt:1
Preprocessor_Hash\$parser
Parser $parser
Definition: Preprocessor_Hash.php:49
PPFrame_Hash\isEmpty
isEmpty()
Returns true if there are no arguments in this frame.
Definition: Preprocessor_Hash.php:1326
PPNode_Hash_Attr\$value
$value
Definition: Preprocessor_Hash.php:2119
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
PPFrame_Hash\getArgument
getArgument( $name)
Definition: Preprocessor_Hash.php:1334
PPTemplateFrame_Hash\getNamedArguments
getNamedArguments()
Definition: Preprocessor_Hash.php:1515
PPNode_Hash_Tree\splitRawTemplate
static splitRawTemplate(array $children)
Like splitTemplate() but for a raw child array.
Definition: Preprocessor_Hash.php:1956
PPDStackElement_Hash\__construct
__construct( $data=[])
Definition: Preprocessor_Hash.php:747
PPNode_Hash_Attr\getLength
getLength()
Returns the length of the array, or false if this is not an array-type node.
Definition: Preprocessor_Hash.php:2164
PPNode_Hash_Tree\__construct
__construct(array $store, $index)
Construct an object using the data from $store[$index].
Definition: Preprocessor_Hash.php:1688
Preprocessor_Hash\CACHE_PREFIX
const CACHE_PREFIX
Definition: Preprocessor_Hash.php:51
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
PPTemplateFrame_Hash\cachedExpand
cachedExpand( $key, $root, $flags=0)
Definition: Preprocessor_Hash.php:1468
PPDPart_Hash\__construct
__construct( $out='')
Definition: Preprocessor_Hash.php:796
PPNode_Hash_Text\splitExt
splitExt()
Split an "<ext>" node into an associative array containing name, attr, inner and close All values in ...
Definition: Preprocessor_Hash.php:2045
PPNode_Hash_Text\$value
$value
Definition: Preprocessor_Hash.php:1990
PPNode_Hash_Array
Definition: Preprocessor_Hash.php:2058
PPTemplateFrame_Hash
Expansion frame with template arguments.
Definition: Preprocessor_Hash.php:1411
value
$status value
Definition: SyntaxHighlight_GeSHi.class.php:311
PPNode_Hash_Text\getFirstChild
getFirstChild()
Get the first child of a tree node.
Definition: Preprocessor_Hash.php:2021
PPNode_Hash_Tree\getRawChildren
getRawChildren()
Get the raw child array.
Definition: Preprocessor_Hash.php:1799
PPNode_Hash_Text\$store
$store
Definition: Preprocessor_Hash.php:1991
PPNode_Hash_Tree\getName
getName()
Definition: Preprocessor_Hash.php:1821
$value
$value
Definition: styleTest.css.php:45
PPNode_Hash_Attr\$index
$index
Definition: Preprocessor_Hash.php:2120
PPFrame_Hash\getTitle
getTitle()
Get a title of frame.
Definition: Preprocessor_Hash.php:1363
$retval
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account incomplete not yet checked for validity & $retval
Definition: hooks.txt:246
PPFrame_Hash\$preprocessor
Preprocessor $preprocessor
Definition: Preprocessor_Hash.php:822
Preprocessor_Hash\preprocessToObj
preprocessToObj( $text, $flags=0)
Preprocess some wikitext and return the document tree.
Definition: Preprocessor_Hash.php:119
title
title
Definition: parserTests.txt:211
PPDStack
Stack class to help Preprocessor::preprocessToObj()
Definition: Preprocessor_DOM.php:761
PPFrame\NO_TAGS
const NO_TAGS
Definition: Preprocessor.php:171
PPFrame
Definition: Preprocessor.php:165
PPNode_Hash_Tree\getChildren
getChildren()
Definition: Preprocessor_Hash.php:1745
PPNode_Hash_Array\__construct
__construct( $value)
Definition: Preprocessor_Hash.php:2063
PPFrame_Hash\$volatile
$volatile
Definition: Preprocessor_Hash.php:842
PPNode_Hash_Text\getName
getName()
Get the name of this node.
Definition: Preprocessor_Hash.php:2037
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1657
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1956
PPNode_Hash_Text\getChildren
getChildren()
Get an array-type node containing the children of this node.
Definition: Preprocessor_Hash.php:2017
PPNode_Hash_Tree\$index
$index
The index into $this->store which contains the descriptor of this node.
Definition: Preprocessor_Hash.php:1667
PPNode_Hash_Array\item
item( $i)
Returns an item of an array-type node.
Definition: Preprocessor_Hash.php:2075
PPFrame_Hash\implodeWithFlags
implodeWithFlags( $sep, $flags)
Definition: Preprocessor_Hash.php:1163
PPCustomFrame_Hash\$args
$args
Definition: Preprocessor_Hash.php:1597
PPNode_Hash_Array\getChildren
getChildren()
Get an array-type node containing the children of this node.
Definition: Preprocessor_Hash.php:2087
PPNode_Hash_Attr\getChildren
getChildren()
Get an array-type node containing the children of this node.
Definition: Preprocessor_Hash.php:2152
PPFrame_Hash\implode
implode( $sep)
Implode with no flags specified This previously called implodeWithFlags but has now been inlined to r...
Definition: Preprocessor_Hash.php:1194
PPNode_Hash_Array\getName
getName()
Get the name of this node.
Definition: Preprocessor_Hash.php:2079
PPNode_Hash_Attr\getNextSibling
getNextSibling()
Get the next sibling of any node.
Definition: Preprocessor_Hash.php:2148
PPNode_Hash_Attr
Definition: Preprocessor_Hash.php:2116
PPFrame_Hash\newChild
newChild( $args=false, $title=false, $indexOffset=0)
Create a new child frame $args is optionally a multi-root PPNode or array containing the template arg...
Definition: Preprocessor_Hash.php:874
$args
if( $line===false) $args
Definition: cdb.php:63
PPTemplateFrame_Hash\$namedExpansionCache
$namedExpansionCache
Definition: Preprocessor_Hash.php:1415
Preprocessor\cacheSetTree
cacheSetTree( $text, $flags, $tree)
Store a document tree in the cache.
Definition: Preprocessor.php:66
Title
Represents a title within MediaWiki.
Definition: Title.php:39
PPNode_Hash_Text
Definition: Preprocessor_Hash.php:1987
PPCustomFrame_Hash\getArgument
getArgument( $index)
Definition: Preprocessor_Hash.php:1631
PPNode_Hash_Tree\$rawChildren
$rawChildren
The store array for children of this node.
Definition: Preprocessor_Hash.php:1657
PPFrame_Hash\isVolatile
isVolatile()
Get the volatile flag.
Definition: Preprocessor_Hash.php:1381
PPNode_Hash_Text\item
item( $i)
Returns an item of an array-type node.
Definition: Preprocessor_Hash.php:2033
PPNode_Hash_Attr\getName
getName()
Get the name of this node.
Definition: Preprocessor_Hash.php:2144
PPDStack_Hash
Stack class to help Preprocessor::preprocessToObj()
Definition: Preprocessor_Hash.php:730
PPNode_Hash_Array\$value
$value
Definition: Preprocessor_Hash.php:2061
PPNode_Hash_Text\$index
$index
Definition: Preprocessor_Hash.php:1991
Preprocessor_Hash\addLiteral
static addLiteral(array &$accum, $text)
Definition: Preprocessor_Hash.php:715
PPFrame_Hash\$parser
Parser $parser
Definition: Preprocessor_Hash.php:817
PPNode_Hash_Attr\splitArg
splitArg()
Split a "<part>" node into an associative array containing: name PPNode name index String index value...
Definition: Preprocessor_Hash.php:2172
PPFrame_Hash\virtualImplode
virtualImplode( $sep)
Makes an object that, when expand()ed, will be the same as one obtained with implode()
Definition: Preprocessor_Hash.php:1226
PPDStackElement_Hash\breakSyntax
breakSyntax( $openingCount=false)
Get the accumulator that would result if the close is not found.
Definition: Preprocessor_Hash.php:758
PPNode_Hash_Array\getNextSibling
getNextSibling()
Get the next sibling of any node.
Definition: Preprocessor_Hash.php:2083
PPNode_Hash_Array\__toString
__toString()
Definition: Preprocessor_Hash.php:2067
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
PPFrame_Hash\$ttl
$ttl
Definition: Preprocessor_Hash.php:843
PPCustomFrame_Hash\getArguments
getArguments()
Definition: Preprocessor_Hash.php:1638
PPCustomFrame_Hash
Expansion frame with custom arguments.
Definition: Preprocessor_Hash.php:1594
PPFrame_Hash\loopCheck
loopCheck( $title)
Returns true if the infinite loop check is OK, false if a loop is detected.
Definition: Preprocessor_Hash.php:1345
PPTemplateFrame_Hash\isTemplate
isTemplate()
Return true if the frame is a template frame.
Definition: Preprocessor_Hash.php:1574
captcha-old.parser
parser
Definition: captcha-old.py:187
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
PPTemplateFrame_Hash\getArgument
getArgument( $name)
Definition: Preprocessor_Hash.php:1561
PPNode_Hash_Attr\__construct
__construct(array $store, $index)
Construct an object using the data from $store[$index].
Definition: Preprocessor_Hash.php:2129
PPFrame_Hash\isTemplate
isTemplate()
Return true if the frame is a template frame.
Definition: Preprocessor_Hash.php:1354
Preprocessor\cacheGetTree
cacheGetTree( $text, $flags)
Attempt to load a precomputed document tree for some given wikitext from the cache.
Definition: Preprocessor.php:95
PPNode_Hash_Text\splitArg
splitArg()
Split a "<part>" node into an associative array containing: name PPNode name index String index value...
Definition: Preprocessor_Hash.php:2041
PPNode_Hash_Tree
Definition: Preprocessor_Hash.php:1647
PPFrame_Hash\$title
Title $title
Definition: Preprocessor_Hash.php:827
PPDStack_Hash\__construct
__construct()
Definition: Preprocessor_Hash.php:733
PPTemplateFrame_Hash\__toString
__toString()
Definition: Preprocessor_Hash.php:1444
PPNode_Hash_Attr\__toString
__toString()
Definition: Preprocessor_Hash.php:2140
captcha-old.args
args
Definition: captcha-old.py:203
PPNode_Hash_Tree\factory
static factory(array $store, $index)
Construct an appropriate PPNode_Hash_* object with a class that depends on what is at the relevant st...
Definition: Preprocessor_Hash.php:1702
PPNode_Hash_Tree\NAME
const NAME
The offset of the name within descriptors, used in some places for readability.
Definition: Preprocessor_Hash.php:1673
PPTemplateFrame_Hash\getNumberedArguments
getNumberedArguments()
Definition: Preprocessor_Hash.php:1504
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2749
PPFrame_Hash\cachedExpand
cachedExpand( $key, $root, $flags=0)
Definition: Preprocessor_Hash.php:925
PPTemplateFrame_Hash\setTTL
setTTL( $ttl)
Set the TTL.
Definition: Preprocessor_Hash.php:1583
PPNode_Hash_Tree\splitArg
splitArg()
Split a "<part>" node into an associative array containing:
Definition: Preprocessor_Hash.php:1834
array
the array() calling protocol came about after MediaWiki 1.4rc1.
$out
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:783