67 foreach ( $values
as $k => $val ) {
73 $partNode->addChild( $nameNode );
76 $partNode->addChild( $nameNode );
82 $partNode->addChild( $valueNode );
116 if ( $tree !==
false ) {
122 $xmlishElements = $this->parser->getStripList();
123 $xmlishAllowMissingEndTag = [
'includeonly',
'noinclude',
'onlyinclude' ];
124 $enableOnlyinclude =
false;
125 if ( $forInclusion ) {
126 $ignoredTags = [
'includeonly',
'/includeonly' ];
127 $ignoredElements = [
'noinclude' ];
128 $xmlishElements[] =
'noinclude';
129 if ( strpos( $text,
'<onlyinclude>' ) !==
false
130 && strpos( $text,
'</onlyinclude>' ) !==
false
132 $enableOnlyinclude =
true;
135 $ignoredTags = [
'noinclude',
'/noinclude',
'onlyinclude',
'/onlyinclude' ];
136 $ignoredElements = [
'includeonly' ];
137 $xmlishElements[] =
'includeonly';
139 $xmlishRegex = implode(
'|', array_merge( $xmlishElements, $ignoredTags ) );
142 $elementsRegex =
"~($xmlishRegex)(?:\s|\/>|>)|(!--)~iA";
146 $searchBase =
"[{<\n";
148 $revText = strrev( $text );
149 $lengthText = strlen( $text );
154 $accum =& $stack->getAccum();
165 $noMoreClosingTag = [];
167 $findOnlyinclude = $enableOnlyinclude;
169 $fakeLineStart =
true;
174 if ( $findOnlyinclude ) {
176 $startPos = strpos( $text,
'<onlyinclude>', $i );
177 if ( $startPos ===
false ) {
179 $accum->addNodeWithText(
'ignore', substr( $text, $i ) );
182 $tagEndPos = $startPos + strlen(
'<onlyinclude>' );
183 $accum->addNodeWithText(
'ignore', substr( $text, $i, $tagEndPos - $i ) );
185 $findOnlyinclude =
false;
188 if ( $fakeLineStart ) {
189 $found =
'line-start';
192 # Find next opening brace, closing brace or pipe
193 $search = $searchBase;
194 if ( $stack->top ===
false ) {
195 $currentClosing =
'';
197 $currentClosing = $stack->top->close;
198 $search .= $currentClosing;
208 # Output literal section, advance input counter
209 $literalLength = strcspn( $text, $search, $i );
210 if ( $literalLength > 0 ) {
211 $accum->addLiteral( substr( $text, $i, $literalLength ) );
212 $i += $literalLength;
214 if ( $i >= $lengthText ) {
215 if ( $currentClosing ==
"\n" ) {
224 $curChar = $text[$i];
225 if ( $curChar ==
'|' ) {
227 } elseif ( $curChar ==
'=' ) {
229 } elseif ( $curChar ==
'<' ) {
231 } elseif ( $curChar ==
"\n" ) {
235 $found =
'line-start';
237 } elseif ( $curChar == $currentClosing ) {
239 } elseif ( isset( $this->rules[$curChar] ) ) {
241 $rule = $this->rules[$curChar];
243 # Some versions of PHP have a strcspn which stops on null characters
244 # Ignore and continue
251 if ( $found ==
'angle' ) {
254 if ( $enableOnlyinclude
255 && substr( $text, $i, strlen(
'</onlyinclude>' ) ) ==
'</onlyinclude>'
257 $findOnlyinclude =
true;
262 if ( !preg_match( $elementsRegex, $text,
$matches, 0, $i + 1 ) ) {
264 $accum->addLiteral(
'<' );
277 $endPos = strpos( $text,
'-->', $i + 4 );
278 if ( $endPos ===
false ) {
280 $inner = substr( $text, $i );
281 $accum->addNodeWithText(
'comment', $inner );
285 $wsStart = $i ? ( $i - strspn( $revText,
" \t", $lengthText - $i ) ) : 0;
289 $wsEnd = $endPos + 2 + strspn( $text,
" \t", $endPos + 3 );
293 $comments = [ [ $wsStart, $wsEnd ] ];
294 while ( substr( $text, $wsEnd + 1, 4 ) ==
'<!--' ) {
295 $c = strpos( $text,
'-->', $wsEnd + 4 );
296 if ( $c ===
false ) {
299 $c = $c + 2 + strspn( $text,
" \t", $c + 3 );
300 $comments[] = [ $wsEnd + 1, $c ];
308 if ( $wsStart > 0 && substr( $text, $wsStart - 1, 1 ) ==
"\n"
309 && substr( $text, $wsEnd + 1, 1 ) ==
"\n"
313 $wsLength = $i - $wsStart;
316 && strspn( $accum->lastNode->value,
" \t", -$wsLength ) === $wsLength
318 $accum->lastNode->value = substr( $accum->lastNode->value, 0, -$wsLength );
322 foreach ( $comments
as $j => $com ) {
324 $endPos = $com[1] + 1;
325 if ( $j == ( count( $comments ) - 1 ) ) {
328 $inner = substr( $text, $startPos, $endPos - $startPos );
329 $accum->addNodeWithText(
'comment', $inner );
333 $fakeLineStart =
true;
341 $part = $stack->top->getCurrentPart();
342 if ( !( isset( $part->commentEnd ) && $part->commentEnd == $wsStart - 1 ) ) {
343 $part->visualEnd = $wsStart;
346 $part->commentEnd = $endPos;
349 $inner = substr( $text, $startPos, $endPos - $startPos + 1 );
350 $accum->addNodeWithText(
'comment', $inner );
355 $lowerName = strtolower(
$name );
356 $attrStart = $i + strlen(
$name ) + 1;
359 $tagEndPos = $noMoreGT ?
false : strpos( $text,
'>', $attrStart );
360 if ( $tagEndPos ===
false ) {
364 $accum->addLiteral(
'<' );
370 if ( in_array( $lowerName, $ignoredTags ) ) {
371 $accum->addNodeWithText(
'ignore', substr( $text, $i, $tagEndPos - $i + 1 ) );
377 if ( $text[$tagEndPos - 1] ==
'/' ) {
379 $attrEnd = $tagEndPos - 1;
384 $attrEnd = $tagEndPos;
387 !isset( $noMoreClosingTag[
$name] ) &&
388 preg_match(
"/<\/" . preg_quote( $name,
'/' ) .
"\s*>/i",
389 $text,
$matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 )
391 $inner = substr( $text, $tagEndPos + 1,
$matches[0][1] - $tagEndPos - 1 );
396 if ( in_array( $name, $xmlishAllowMissingEndTag ) ) {
398 $inner = substr( $text, $tagEndPos + 1 );
404 $accum->addLiteral( substr( $text, $tagStartPos, $tagEndPos + 1 - $tagStartPos ) );
406 $noMoreClosingTag[
$name] =
true;
412 if ( in_array( $lowerName, $ignoredElements ) ) {
413 $accum->addNodeWithText(
'ignore', substr( $text, $tagStartPos, $i - $tagStartPos ) );
417 if ( $attrEnd <= $attrStart ) {
422 $attr = substr( $text, $attrStart, $attrEnd - $attrStart );
428 if ( $inner !== null ) {
431 if ( $close !== null ) {
434 $accum->addNode( $extNode );
435 } elseif ( $found ==
'line-start' ) {
438 if ( $fakeLineStart ) {
439 $fakeLineStart =
false;
441 $accum->addLiteral( $curChar );
445 $count = strspn( $text,
'=', $i, 6 );
446 if (
$count == 1 && $findEquals ) {
458 $stack->push( $piece );
459 $accum =& $stack->getAccum();
460 extract( $stack->getFlags() );
463 } elseif ( $found ==
'line-end' ) {
464 $piece = $stack->top;
466 assert(
'$piece->open == "\n"' );
467 $part = $piece->getCurrentPart();
471 $wsLength = strspn( $revText,
" \t", $lengthText - $i );
472 $searchStart = $i - $wsLength;
473 if ( isset( $part->commentEnd ) && $searchStart - 1 == $part->commentEnd ) {
476 $searchStart = $part->visualEnd;
477 $searchStart -= strspn( $revText,
" \t", $lengthText - $searchStart );
480 $equalsLength = strspn( $revText,
'=', $lengthText - $searchStart );
481 if ( $equalsLength > 0 ) {
482 if ( $searchStart - $equalsLength == $piece->startPos ) {
500 $element->lastChild->nextSibling = $accum->firstNode;
501 $element->lastChild = $accum->lastNode;
512 $accum =& $stack->getAccum();
513 extract( $stack->getFlags() );
516 if ( $element instanceof
PPNode ) {
517 $accum->addNode( $element );
519 $accum->addAccum( $element );
526 } elseif ( $found ==
'open' ) {
527 # count opening brace characters
528 $count = strspn( $text, $curChar, $i );
530 # we need to add to stack only if opening brace count is enough for one of the rules
531 if (
$count >= $rule[
'min'] ) {
532 # Add it to the stack
535 'close' => $rule[
'end'],
537 'lineStart' => ( $i > 0 && $text[$i - 1] ==
"\n" ),
540 $stack->push( $piece );
541 $accum =& $stack->getAccum();
542 extract( $stack->getFlags() );
544 # Add literal brace(s)
545 $accum->addLiteral( str_repeat( $curChar,
$count ) );
548 } elseif ( $found ==
'close' ) {
549 $piece = $stack->top;
550 # lets check if there are enough characters for closing brace
551 $maxCount = $piece->count;
552 $count = strspn( $text, $curChar, $i, $maxCount );
554 # check for maximum matching characters (if there are 5 closing
555 # characters, we will probably need only 3 - depending on the rules)
556 $rule = $this->rules[$piece->open];
557 if (
$count > $rule[
'max'] ) {
558 # The specified maximum exists in the callback array, unless the caller
560 $matchingCount = $rule[
'max'];
562 # Count is less than the maximum
563 # Skip any gaps in the callback array to find the true largest match
564 # Need to use array_key_exists not isset because the callback can be null
566 while ( $matchingCount > 0 && !array_key_exists( $matchingCount, $rule[
'names'] ) ) {
571 if ( $matchingCount <= 0 ) {
572 # No matching element found in callback array
573 # Output a literal closing brace and continue
574 $accum->addLiteral( str_repeat( $curChar,
$count ) );
578 $name = $rule[
'names'][$matchingCount];
579 if (
$name === null ) {
581 $element = $piece->breakSyntax( $matchingCount );
582 $element->addLiteral( str_repeat( $rule[
'end'], $matchingCount ) );
585 # Note: $parts is already XML, does not need to be encoded further
586 $parts = $piece->parts;
587 $titleAccum = $parts[0]->out;
592 # The invocation is at the start of the line if lineStart is set in
593 # the stack, and all opening brackets are used up.
594 if ( $maxCount == $matchingCount && !empty( $piece->lineStart ) ) {
598 $titleNode->firstChild = $titleAccum->firstNode;
599 $titleNode->lastChild = $titleAccum->lastNode;
600 $element->addChild( $titleNode );
602 foreach ( $parts
as $part ) {
603 if ( isset( $part->eqpos ) ) {
606 for ( $node = $part->out->firstNode; $node; $node = $node->nextSibling ) {
607 if ( $node === $part->eqpos ) {
614 throw new MWException( __METHOD__ .
': eqpos not found' );
616 if ( $node->name !==
'equals' ) {
618 throw new MWException( __METHOD__ .
': eqpos is not equals' );
624 if ( $lastNode !==
false ) {
625 $lastNode->nextSibling =
false;
626 $nameNode->firstChild = $part->out->firstNode;
627 $nameNode->lastChild = $lastNode;
632 if ( $equalsNode->nextSibling !==
false ) {
633 $valueNode->firstChild = $equalsNode->nextSibling;
634 $valueNode->lastChild = $part->out->lastNode;
637 $partNode->addChild( $nameNode );
638 $partNode->addChild( $equalsNode->firstChild );
639 $partNode->addChild( $valueNode );
640 $element->addChild( $partNode );
646 $valueNode->firstChild = $part->out->firstNode;
647 $valueNode->lastChild = $part->out->lastNode;
648 $partNode->addChild( $nameNode );
649 $partNode->addChild( $valueNode );
650 $element->addChild( $partNode );
655 # Advance input pointer
656 $i += $matchingCount;
660 $accum =& $stack->getAccum();
662 # Re-add the old stack element if it still has unmatched opening characters remaining
663 if ( $matchingCount < $piece->count ) {
665 $piece->count -= $matchingCount;
666 # do we still qualify for any callback with remaining count?
667 $min = $this->rules[$piece->open][
'min'];
668 if ( $piece->count >= $min ) {
669 $stack->push( $piece );
670 $accum =& $stack->getAccum();
672 $accum->addLiteral( str_repeat( $piece->open, $piece->count ) );
676 extract( $stack->getFlags() );
678 # Add XML element to the enclosing accumulator
679 if ( $element instanceof
PPNode ) {
680 $accum->addNode( $element );
682 $accum->addAccum( $element );
684 } elseif ( $found ==
'pipe' ) {
687 $accum =& $stack->getAccum();
689 } elseif ( $found ==
'equals' ) {
691 $accum->addNodeWithText(
'equals',
'=' );
692 $stack->getCurrentPart()->eqpos = $accum->lastNode;
697 # Output any remaining unclosed brackets
698 foreach ( $stack->stack
as $piece ) {
699 $stack->rootAccum->addAccum( $piece->breakSyntax() );
702 # Enable top-level headings
703 for ( $node = $stack->rootAccum->firstNode; $node; $node = $node->nextSibling ) {
704 if ( isset( $node->name ) && $node->name ===
'possible-h' ) {
710 $rootNode->firstChild = $stack->rootAccum->firstNode;
711 $rootNode->lastChild = $stack->rootAccum->lastNode;
729 $this->elementClass =
'PPDStackElement_Hash';
730 parent::__construct();
743 $this->partClass =
'PPDPart_Hash';
744 parent::__construct( $data );
754 if ( $this->
open ==
"\n" ) {
755 $accum = $this->parts[0]->out;
757 if ( $openingCount ===
false ) {
763 foreach ( $this->parts
as $part ) {
767 $accum->addLiteral(
'|' );
769 $accum->addAccum( $part->out );
788 parent::__construct( $accum );
802 $this->firstNode = $this->lastNode =
false;
810 if ( $this->lastNode ===
false ) {
813 $this->lastNode->value .=
$s;
815 $this->lastNode->nextSibling =
new PPNode_Hash_Text(
$s );
816 $this->lastNode = $this->lastNode->nextSibling;
825 if ( $this->lastNode ===
false ) {
826 $this->firstNode = $this->lastNode = $node;
828 $this->lastNode->nextSibling = $node;
829 $this->lastNode = $node;
850 if ( $accum->lastNode ===
false ) {
852 } elseif ( $this->lastNode ===
false ) {
853 $this->firstNode = $accum->firstNode;
854 $this->lastNode = $accum->lastNode;
856 $this->lastNode->nextSibling = $accum->firstNode;
857 $this->lastNode = $accum->lastNode;
913 $this->
title = $this->parser->mTitle;
914 $this->titleCache = [ $this->
title ? $this->
title->getPrefixedDBkey() :
false ];
915 $this->loopCheckHash = [];
917 $this->childExpansionCache = [];
936 if (
$args !==
false ) {
939 } elseif ( !is_array(
$args ) ) {
940 throw new MWException( __METHOD__ .
': $args must be array or PPNode_Hash_Array' );
943 $bits = $arg->splitArg();
944 if ( $bits[
'index'] !==
'' ) {
946 $index = $bits[
'index'] - $indexOffset;
947 if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) {
948 $this->parser->getOutput()->addWarning(
wfMessage(
'duplicate-args-warning',
952 $this->parser->addTrackingCategory(
'duplicate-args-category' );
954 $numberedArgs[$index] = $bits[
'value'];
955 unset( $namedArgs[$index] );
959 if ( isset( $namedArgs[
$name] ) || isset( $numberedArgs[$name] ) ) {
960 $this->parser->getOutput()->addWarning(
wfMessage(
'duplicate-args-warning',
964 $this->parser->addTrackingCategory(
'duplicate-args-category' );
966 $namedArgs[
$name] = $bits[
'value'];
967 unset( $numberedArgs[$name] );
993 static $expansionDepth = 0;
994 if ( is_string( $root ) ) {
998 if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
999 $this->parser->limitationWarn(
'node-count-exceeded',
1000 $this->parser->mPPNodeCount,
1001 $this->parser->mOptions->getMaxPPNodeCount()
1003 return '<span class="error">Node-count limit exceeded</span>';
1005 if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
1006 $this->parser->limitationWarn(
'expansion-depth-exceeded',
1008 $this->parser->mOptions->getMaxPPExpandDepth()
1010 return '<span class="error">Expansion depth limit exceeded</span>';
1013 if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
1014 $this->parser->mHighestExpansionDepth = $expansionDepth;
1017 $outStack = [
'',
'' ];
1018 $iteratorStack = [
false, $root ];
1019 $indexStack = [ 0, 0 ];
1021 while ( count( $iteratorStack ) > 1 ) {
1022 $level = count( $outStack ) - 1;
1023 $iteratorNode =& $iteratorStack[$level];
1024 $out =& $outStack[$level];
1025 $index =& $indexStack[$level];
1027 if ( is_array( $iteratorNode ) ) {
1028 if ( $index >= count( $iteratorNode ) ) {
1030 $iteratorStack[$level] =
false;
1031 $contextNode =
false;
1033 $contextNode = $iteratorNode[$index];
1037 if ( $index >= $iteratorNode->getLength() ) {
1039 $iteratorStack[$level] =
false;
1040 $contextNode =
false;
1042 $contextNode = $iteratorNode->item( $index );
1048 $contextNode = $iteratorStack[$level];
1049 $iteratorStack[$level] =
false;
1052 $newIterator =
false;
1054 if ( $contextNode ===
false ) {
1056 } elseif ( is_string( $contextNode ) ) {
1057 $out .= $contextNode;
1058 } elseif ( is_array( $contextNode ) || $contextNode instanceof PPNode_Hash_Array ) {
1059 $newIterator = $contextNode;
1063 $out .= $contextNode->value;
1065 if ( $contextNode->name ==
'template' ) {
1066 # Double-brace expansion
1067 $bits = $contextNode->splitTemplate();
1075 $ret = $this->parser->braceSubstitution( $bits, $this );
1076 if ( isset(
$ret[
'object'] ) ) {
1077 $newIterator =
$ret[
'object'];
1082 } elseif ( $contextNode->name ==
'tplarg' ) {
1083 # Triple-brace expansion
1084 $bits = $contextNode->splitTemplate();
1092 $ret = $this->parser->argSubstitution( $bits, $this );
1093 if ( isset(
$ret[
'object'] ) ) {
1094 $newIterator =
$ret[
'object'];
1099 } elseif ( $contextNode->name ==
'comment' ) {
1100 # HTML-style comment
1101 # Remove it in HTML, pre+remove and STRIP_COMMENTS modes
1102 # Not in RECOVER_COMMENTS mode (msgnw) though.
1103 if ( ( $this->parser->ot[
'html']
1104 || ( $this->parser->ot[
'pre'] && $this->parser->mOptions->getRemoveComments() )
1109 } elseif ( $this->parser->ot[
'wiki'] && !(
$flags & PPFrame::RECOVER_COMMENTS ) ) {
1110 # Add a strip marker in PST mode so that pstPass2() can
1111 # run some old-fashioned regexes on the result.
1112 # Not in RECOVER_COMMENTS mode (extractSections) though.
1113 $out .= $this->parser->insertStripItem( $contextNode->firstChild->value );
1115 # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
1116 $out .= $contextNode->firstChild->value;
1118 } elseif ( $contextNode->name ==
'ignore' ) {
1119 # Output suppression used by <includeonly> etc.
1120 # OT_WIKI will only respect <ignore> in substed templates.
1121 # The other output types respect it unless NO_IGNORE is set.
1122 # extractSections() sets NO_IGNORE and so never respects it.
1123 if ( ( !isset( $this->parent ) && $this->parser->ot[
'wiki'] )
1126 $out .= $contextNode->firstChild->value;
1130 } elseif ( $contextNode->name ==
'ext' ) {
1132 $bits = $contextNode->splitExt() + [
'attr' => null,
'inner' => null,
'close' => null ];
1134 $s =
'<' . $bits[
'name']->firstChild->value;
1135 if ( $bits[
'attr'] ) {
1136 $s .= $bits[
'attr']->firstChild->value;
1138 if ( $bits[
'inner'] ) {
1139 $s .=
'>' . $bits[
'inner']->firstChild->value;
1140 if ( $bits[
'close'] ) {
1141 $s .= $bits[
'close']->firstChild->value;
1148 $out .= $this->parser->extensionSubstitution( $bits, $this );
1150 } elseif ( $contextNode->name ==
'h' ) {
1152 if ( $this->parser->ot[
'html'] ) {
1153 # Expand immediately and insert heading index marker
1155 for ( $node = $contextNode->firstChild; $node; $node = $node->nextSibling ) {
1159 $bits = $contextNode->splitHeading();
1160 $titleText = $this->
title->getPrefixedDBkey();
1161 $this->parser->mHeadings[] = [ $titleText, $bits[
'i'] ];
1162 $serial = count( $this->parser->mHeadings ) - 1;
1164 $s = substr(
$s, 0, $bits[
'level'] ) . $marker . substr(
$s, $bits[
'level'] );
1165 $this->parser->mStripState->addGeneral( $marker,
'' );
1168 # Expand in virtual stack
1169 $newIterator = $contextNode->getChildren();
1172 # Generic recursive expansion
1173 $newIterator = $contextNode->getChildren();
1176 throw new MWException( __METHOD__ .
': Invalid parameter type' );
1179 if ( $newIterator !==
false ) {
1181 $iteratorStack[] = $newIterator;
1183 } elseif ( $iteratorStack[$level] ===
false ) {
1186 while ( $iteratorStack[$level] ===
false && $level > 0 ) {
1187 $outStack[$level - 1] .=
$out;
1188 array_pop( $outStack );
1189 array_pop( $iteratorStack );
1190 array_pop( $indexStack );
1196 return $outStack[0];
1206 $args = array_slice( func_get_args(), 2 );
1212 $root = $root->value;
1214 if ( !is_array( $root ) ) {
1217 foreach ( $root
as $node ) {
1237 $args = array_slice( func_get_args(), 1 );
1243 $root = $root->value;
1245 if ( !is_array( $root ) ) {
1248 foreach ( $root
as $node ) {
1269 $args = array_slice( func_get_args(), 1 );
1275 $root = $root->value;
1277 if ( !is_array( $root ) ) {
1280 foreach ( $root
as $node ) {
1302 $args = array_slice( func_get_args(), 3 );
1308 $root = $root->value;
1310 if ( !is_array( $root ) ) {
1313 foreach ( $root
as $node ) {
1335 if ( $level ===
false ) {
1336 return $this->
title->getPrefixedDBkey();
1338 return isset( $this->titleCache[$level] ) ? $this->titleCache[$level] :
false;
1415 $this->
volatile = $flag;
1433 if (
$ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) {
1467 $namedArgs = [],
$title =
false
1476 $this->titleCache = $parent->titleCache;
1477 $this->titleCache[] = $pdbk;
1478 $this->loopCheckHash = $parent->loopCheckHash;
1479 if ( $pdbk !==
false ) {
1480 $this->loopCheckHash[$pdbk] =
true;
1482 $this->depth = $parent->depth + 1;
1483 $this->numberedExpansionCache = $this->namedExpansionCache = [];
1496 $s .=
"\"$name\":\"" .
1497 str_replace(
'"',
'\\"',
$value->__toString() ) .
'"';
1511 if ( isset( $this->parent->childExpansionCache[
$key] ) ) {
1512 return $this->parent->childExpansionCache[
$key];
1516 $this->parent->childExpansionCache[
$key] =
$retval;
1527 return !count( $this->numberedArgs ) && !count( $this->namedArgs );
1535 foreach ( array_merge(
1536 array_keys( $this->numberedArgs ),
1537 array_keys( $this->namedArgs ) )
as $key ) {
1548 foreach ( array_keys( $this->numberedArgs )
as $key ) {
1559 foreach ( array_keys( $this->namedArgs )
as $key ) {
1570 if ( !isset( $this->numberedArgs[$index] ) ) {
1573 if ( !isset( $this->numberedExpansionCache[$index] ) ) {
1574 # No trimming for unnamed arguments
1575 $this->numberedExpansionCache[$index] = $this->parent->expand(
1576 $this->numberedArgs[$index],
1580 return $this->numberedExpansionCache[$index];
1588 if ( !isset( $this->namedArgs[
$name] ) ) {
1591 if ( !isset( $this->namedExpansionCache[$name] ) ) {
1592 # Trim named arguments post-expand, for backwards compatibility
1593 $this->namedExpansionCache[
$name] = trim(
1596 return $this->namedExpansionCache[
$name];
1605 if ( $text ===
false ) {
1621 parent::setVolatile( $flag );
1622 $this->parent->setVolatile( $flag );
1626 parent::setTTL(
$ttl );
1627 $this->parent->setTTL(
$ttl );
1643 $this->args =
$args;
1655 $s .=
"\"$name\":\"" .
1656 str_replace(
'"',
'\\"',
$value->__toString() ) .
'"';
1666 return !count( $this->args );
1674 if ( !isset( $this->args[$index] ) ) {
1677 return $this->args[$index];
1696 $this->firstChild = $this->lastChild = $this->nextSibling =
false;
1702 for ( $node = $this->firstChild; $node; $node = $node->nextSibling ) {
1704 $attribs .=
' ' . $node->name .
'="' . htmlspecialchars( $node->value ) .
'"';
1706 $inner .= $node->__toString();
1709 if ( $inner ===
'' ) {
1710 return "<{$this->name}$attribs/>";
1712 return "<{$this->name}$attribs>$inner</{$this->name}>";
1722 $obj =
new self(
$name );
1728 if ( $this->lastChild ===
false ) {
1729 $this->firstChild = $this->lastChild = $node;
1731 $this->lastChild->nextSibling = $node;
1732 $this->lastChild = $node;
1741 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1742 $children[] = $child;
1757 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1758 if ( isset( $child->name ) && $child->name ===
$name ) {
1759 $children[] = $child;
1798 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1799 if ( !isset( $child->name ) ) {
1802 if ( $child->name ===
'name' ) {
1803 $bits[
'name'] = $child;
1805 && $child->firstChild->name ===
'index'
1807 $bits[
'index'] = $child->firstChild->value;
1809 } elseif ( $child->name ===
'value' ) {
1810 $bits[
'value'] = $child;
1814 if ( !isset( $bits[
'name'] ) ) {
1815 throw new MWException(
'Invalid brace node passed to ' . __METHOD__ );
1817 if ( !isset( $bits[
'index'] ) ) {
1818 $bits[
'index'] =
'';
1832 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1833 if ( !isset( $child->name ) ) {
1836 if ( $child->name ==
'name' ) {
1837 $bits[
'name'] = $child;
1838 } elseif ( $child->name ==
'attr' ) {
1839 $bits[
'attr'] = $child;
1840 } elseif ( $child->name ==
'inner' ) {
1841 $bits[
'inner'] = $child;
1842 } elseif ( $child->name ==
'close' ) {
1843 $bits[
'close'] = $child;
1846 if ( !isset( $bits[
'name'] ) ) {
1847 throw new MWException(
'Invalid ext node passed to ' . __METHOD__ );
1859 if ( $this->
name !==
'h' ) {
1860 throw new MWException(
'Invalid h node passed to ' . __METHOD__ );
1863 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1864 if ( !isset( $child->name ) ) {
1867 if ( $child->name ==
'i' ) {
1868 $bits[
'i'] = $child->value;
1869 } elseif ( $child->name ==
'level' ) {
1870 $bits[
'level'] = $child->value;
1873 if ( !isset( $bits[
'i'] ) ) {
1874 throw new MWException(
'Invalid h node passed to ' . __METHOD__ );
1887 $bits = [
'lineStart' =>
'' ];
1888 for ( $child = $this->firstChild; $child; $child = $child->nextSibling ) {
1889 if ( !isset( $child->name ) ) {
1892 if ( $child->name ==
'title' ) {
1893 $bits[
'title'] = $child;
1895 if ( $child->name ==
'part' ) {
1898 if ( $child->name ==
'lineStart' ) {
1899 $bits[
'lineStart'] =
'1';
1902 if ( !isset( $bits[
'title'] ) ) {
1903 throw new MWException(
'Invalid node passed to ' . __METHOD__ );
1920 if ( is_object(
$value ) ) {
1921 throw new MWException( __CLASS__ .
' given object instead of string' );
1927 return htmlspecialchars( $this->value );
1959 throw new MWException( __METHOD__ .
': not supported' );
1963 throw new MWException( __METHOD__ .
': not supported' );
1967 throw new MWException( __METHOD__ .
': not supported' );
1985 return var_export( $this,
true );
1989 return count( $this->value );
1993 return $this->value[$i];
2017 throw new MWException( __METHOD__ .
': not supported' );
2021 throw new MWException( __METHOD__ .
': not supported' );
2025 throw new MWException( __METHOD__ .
': not supported' );
2044 return "<@{$this->name}>" . htmlspecialchars( $this->value ) .
"</@{$this->name}>";
2076 throw new MWException( __METHOD__ .
': not supported' );
2080 throw new MWException( __METHOD__ .
': not supported' );
2084 throw new MWException( __METHOD__ .
': not supported' );
splitArg()
Split a "
" node into an associative array containing:
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
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
splitTemplate()
Split a "" or "" node.
getArguments()
Returns all arguments of this frame.
getNextSibling()
Get the next sibling of any node.
Stack class to help Preprocessor::preprocessToObj()
getFirstChild()
Get the first child of a tree node.
__construct($preprocessor)
Construct a new preprocessor frame.
$depth
Recursion depth of this frame, top = 0 Note that this is NOT the same as expansion depth in expand() ...
int $count
Number of opening characters found (number of "=" for heading)
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
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...
item($i)
Returns an item of an array-type node.
processing should stop and the error should be shown to the user * false
setTTL($ttl)
Set the TTL of the output of this frame and all of its ancestors.
splitExt()
Split an "" node into an associative array containing name, attr, inner and close All values in ...
addAccum($accum)
Append a PPDAccum_Hash Takes over ownership of the nodes in the source argument.
There are three types of nodes:
__construct($preprocessor, $args)
getLength()
Returns the length of the array, or false if this is not an array-type node.
isEmpty()
Returns true if there are no arguments in this frame.
it s the revision text itself In either if gzip is the revision text is gzipped $flags
addNodeWithText($name, $value)
Append a tree node with text contents.
implode($sep)
Implode with no flags specified This previously called implodeWithFlags but has now been inlined to r...
isTemplate()
Return true if the frame is a template frame.
getChildren()
Get an array-type node containing the children of this node.
breakSyntax($openingCount=false)
Get the accumulator that would result if the close is not found.
Differences from DOM schema:
Stack class to help Preprocessor::preprocessToObj()
splitHeading()
Split an "" node.
item($i)
Returns an item of an array-type node.
getNextSibling()
Get the next sibling of any node.
getNextSibling()
Get the next sibling of any node.
preprocessToObj($text, $flags=0)
Preprocess some wikitext and return the document tree.
array cacheSetTree($text, $flags, $tree)
Store a document tree in the cache.
wfEscapeWikiText($text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
implodeWithFlags($sep, $flags)
virtualImplode($sep)
Makes an object that, when expand()ed, will be the same as one obtained with implode() ...
An expansion frame, used as a context to expand the result of preprocessToObj()
setVolatile($flag=true)
Set the "volatile" flag.
virtualBracketedImplode($start, $sep, $end)
Virtual implode with brackets.
isTemplate()
Return true if the frame is a template frame.
getChildren()
Get an array-type node containing the children of this node.
isEmpty()
Returns true if there are no arguments in this frame.
splitArg()
Split a "
" node into an associative array containing: name PPNode name index String index value...
getTitle()
Get a title of frame.
getChildren()
Get an array-type node containing the children of this node.
getChildrenOfType($name)
Get all children of this tree node which have a given name.
getName()
Get the name of this node.
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 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 unsetoffset-wrap String Wrap the message in html(usually something like"<
getName()
Get the name of this node.
getChildrenOfType($name)
Get all children of this tree node which have a given name.
static newWithText($name, $text)
Expansion frame with template arguments.
newPartNodeArray($values)
getFirstChild()
Get the first child of a tree node.
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
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
splitExt()
Split an "" node into an associative array containing name, attr, inner and close All values in ...
isVolatile()
Get the volatile flag.
getLength()
Returns the length of the array, or false if this is not an array-type node.
splitArg()
Split a "
" node into an associative array containing: name PPNode name index String index value...
__construct($preprocessor, $parent=false, $numberedArgs=[], $namedArgs=[], $title=false)
setVolatile($flag=true)
Set the volatile flag.
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
__construct($name, $value)
splitHeading()
Split an "" node.
loopCheck($title)
Returns true if the infinite loop check is OK, false if a loop is detected.
getNumberedArgument($index)
getNextSibling()
Get the next sibling of any node.
array $childExpansionCache
getChildrenOfType($name)
Get all children of this tree node which have a given 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
item($i)
Returns an item of an array-type node.
addLiteral($s)
Append a string literal.
cachedExpand($key, $root, $flags=0)
splitHeading()
Split an "" node.
getLength()
Returns the length of the array, or false if this is not an array-type node.
splitHeading()
Split an "" node.
splitExt()
Split an "" node into an associative array containing name, attr, inner and close All values in ...
$loopCheckHash
Hashtable listing templates which are disallowed for expansion in this frame, having been encountered...
addNode(PPNode $node)
Append a PPNode.
cachedExpand($key, $root, $flags=0)
splitExt()
Split an "" node into an associative array containing name, attr, inner and close All values in ...
Expansion frame with custom arguments.
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 local account incomplete not yet checked for validity & $retval
getChildrenOfType($name)
Get all children of this tree node which have a given name.
string $out
Output accumulator string.
splitArg()
Split a "
" node into an associative array containing: name PPNode name index String index value...
getFirstChild()
Get the first child of a tree node.
Preprocessor $preprocessor
cacheGetTree($text, $flags)
Attempt to load a precomputed document tree for some given wikitext from the cache.
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
getFirstChild()
Get the first child of a tree node.
getPrefixedDBkey()
Get the prefixed database key form.
getName()
Get the name of this node.
Allows to change the fields on the form that will be generated $name