Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
29.07% |
75 / 258 |
|
4.55% |
1 / 22 |
CRAP | |
0.00% |
0 / 1 |
PPFrame_Hash | |
29.18% |
75 / 257 |
|
4.55% |
1 / 22 |
4020.56 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
newChild | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
132 | |||
cachedExpand | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
expand | |
46.48% |
66 / 142 |
|
0.00% |
0 / 1 |
417.10 | |||
implodeWithFlags | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
implode | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
virtualImplode | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
42 | |||
virtualBracketedImplode | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
42 | |||
__toString | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getPDBK | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getArguments | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getNumberedArguments | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getNamedArguments | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isEmpty | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getArgument | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
loopCheck | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isTemplate | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTitle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setVolatile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isVolatile | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setTTL | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
20 | |||
getTTL | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | * @ingroup Parser |
20 | */ |
21 | |
22 | namespace MediaWiki\Parser; |
23 | |
24 | use InvalidArgumentException; |
25 | use MediaWiki\Message\Message; |
26 | use MediaWiki\Title\Title; |
27 | use RuntimeException; |
28 | use Stringable; |
29 | |
30 | /** |
31 | * An expansion frame, used as a context to expand the result of preprocessToObj() |
32 | * @ingroup Parser |
33 | */ |
34 | // phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps |
35 | class PPFrame_Hash implements Stringable, PPFrame { |
36 | |
37 | /** |
38 | * @var Parser |
39 | */ |
40 | public $parser; |
41 | |
42 | /** |
43 | * @var Preprocessor |
44 | */ |
45 | public $preprocessor; |
46 | |
47 | /** |
48 | * @var Title |
49 | */ |
50 | public $title; |
51 | |
52 | /** |
53 | * @var (string|false)[] |
54 | */ |
55 | public $titleCache; |
56 | |
57 | /** |
58 | * Hashtable listing templates which are disallowed for expansion in this frame, |
59 | * having been encountered previously in parent frames. |
60 | * @var true[] |
61 | */ |
62 | public $loopCheckHash; |
63 | |
64 | /** |
65 | * Recursion depth of this frame, top = 0 |
66 | * Note that this is NOT the same as expansion depth in expand() |
67 | * @var int |
68 | */ |
69 | public $depth; |
70 | |
71 | /** @var bool */ |
72 | private $volatile = false; |
73 | /** @var int|null */ |
74 | private $ttl = null; |
75 | |
76 | /** |
77 | * @var array |
78 | */ |
79 | protected $childExpansionCache; |
80 | /** |
81 | * @var int |
82 | */ |
83 | private $maxPPNodeCount; |
84 | /** |
85 | * @var int |
86 | */ |
87 | private $maxPPExpandDepth; |
88 | |
89 | /** |
90 | * @param Preprocessor $preprocessor The parent preprocessor |
91 | */ |
92 | public function __construct( $preprocessor ) { |
93 | $this->preprocessor = $preprocessor; |
94 | $this->parser = $preprocessor->parser; |
95 | $this->title = $this->parser->getTitle(); |
96 | $this->maxPPNodeCount = $this->parser->getOptions()->getMaxPPNodeCount(); |
97 | $this->maxPPExpandDepth = $this->parser->getOptions()->getMaxPPExpandDepth(); |
98 | $this->titleCache = [ $this->title ? $this->title->getPrefixedDBkey() : false ]; |
99 | $this->loopCheckHash = []; |
100 | $this->depth = 0; |
101 | $this->childExpansionCache = []; |
102 | } |
103 | |
104 | /** |
105 | * Create a new child frame |
106 | * $args is optionally a multi-root PPNode or array containing the template arguments |
107 | * |
108 | * @param PPNode[]|false|PPNode_Hash_Array $args |
109 | * @param Title|false $title |
110 | * @param int $indexOffset |
111 | * @return PPTemplateFrame_Hash |
112 | */ |
113 | public function newChild( $args = false, $title = false, $indexOffset = 0 ) { |
114 | $namedArgs = []; |
115 | $numberedArgs = []; |
116 | if ( $title === false ) { |
117 | $title = $this->title; |
118 | } |
119 | if ( $args !== false ) { |
120 | if ( $args instanceof PPNode_Hash_Array ) { |
121 | $args = $args->value; |
122 | } elseif ( !is_array( $args ) ) { |
123 | throw new InvalidArgumentException( __METHOD__ . ': $args must be array or PPNode_Hash_Array' ); |
124 | } |
125 | foreach ( $args as $arg ) { |
126 | $bits = $arg->splitArg(); |
127 | if ( $bits['index'] !== '' ) { |
128 | // Numbered parameter |
129 | $index = $bits['index'] - $indexOffset; |
130 | if ( isset( $namedArgs[$index] ) || isset( $numberedArgs[$index] ) ) { |
131 | $this->parser->getOutput()->addWarningMsg( |
132 | 'duplicate-args-warning', |
133 | Message::plaintextParam( (string)$this->title ), |
134 | Message::plaintextParam( (string)$title ), |
135 | Message::numParam( $index ) |
136 | ); |
137 | $this->parser->addTrackingCategory( 'duplicate-args-category' ); |
138 | } |
139 | $numberedArgs[$index] = $bits['value']; |
140 | unset( $namedArgs[$index] ); |
141 | } else { |
142 | // Named parameter |
143 | $name = trim( $this->expand( $bits['name'], PPFrame::STRIP_COMMENTS ) ); |
144 | if ( isset( $namedArgs[$name] ) || isset( $numberedArgs[$name] ) ) { |
145 | $this->parser->getOutput()->addWarningMsg( |
146 | 'duplicate-args-warning', |
147 | Message::plaintextParam( (string)$this->title ), |
148 | Message::plaintextParam( (string)$title ), |
149 | Message::plaintextParam( $name ) |
150 | ); |
151 | $this->parser->addTrackingCategory( 'duplicate-args-category' ); |
152 | } |
153 | $namedArgs[$name] = $bits['value']; |
154 | unset( $numberedArgs[$name] ); |
155 | } |
156 | } |
157 | } |
158 | return new PPTemplateFrame_Hash( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title ); |
159 | } |
160 | |
161 | /** |
162 | * @param string|int $key |
163 | * @param string|PPNode $root |
164 | * @param int $flags |
165 | * @return string |
166 | */ |
167 | public function cachedExpand( $key, $root, $flags = 0 ) { |
168 | // we don't have a parent, so we don't have a cache |
169 | return $this->expand( $root, $flags ); |
170 | } |
171 | |
172 | /** |
173 | * @param string|PPNode $root |
174 | * @param int $flags |
175 | * @return string |
176 | */ |
177 | public function expand( $root, $flags = 0 ) { |
178 | static $expansionDepth = 0; |
179 | if ( is_string( $root ) ) { |
180 | return $root; |
181 | } |
182 | |
183 | if ( ++$this->parser->mPPNodeCount > $this->maxPPNodeCount ) { |
184 | $this->parser->limitationWarn( 'node-count-exceeded', |
185 | $this->parser->mPPNodeCount, |
186 | $this->maxPPNodeCount |
187 | ); |
188 | return '<span class="error">Node-count limit exceeded</span>'; |
189 | } |
190 | if ( $expansionDepth > $this->maxPPExpandDepth ) { |
191 | $this->parser->limitationWarn( 'expansion-depth-exceeded', |
192 | $expansionDepth, |
193 | $this->maxPPExpandDepth |
194 | ); |
195 | return '<span class="error">Expansion depth limit exceeded</span>'; |
196 | } |
197 | ++$expansionDepth; |
198 | if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) { |
199 | $this->parser->mHighestExpansionDepth = $expansionDepth; |
200 | } |
201 | |
202 | $outStack = [ '', '' ]; |
203 | $iteratorStack = [ false, $root ]; |
204 | $indexStack = [ 0, 0 ]; |
205 | |
206 | while ( count( $iteratorStack ) > 1 ) { |
207 | $level = count( $outStack ) - 1; |
208 | $iteratorNode =& $iteratorStack[$level]; |
209 | $out =& $outStack[$level]; |
210 | $index =& $indexStack[$level]; |
211 | |
212 | if ( is_array( $iteratorNode ) ) { |
213 | if ( $index >= count( $iteratorNode ) ) { |
214 | // All done with this iterator |
215 | $iteratorStack[$level] = false; |
216 | $contextNode = false; |
217 | } else { |
218 | $contextNode = $iteratorNode[$index]; |
219 | $index++; |
220 | } |
221 | } elseif ( $iteratorNode instanceof PPNode_Hash_Array ) { |
222 | if ( $index >= $iteratorNode->getLength() ) { |
223 | // All done with this iterator |
224 | $iteratorStack[$level] = false; |
225 | $contextNode = false; |
226 | } else { |
227 | $contextNode = $iteratorNode->item( $index ); |
228 | $index++; |
229 | } |
230 | } else { |
231 | // Copy to $contextNode and then delete from iterator stack, |
232 | // because this is not an iterator but we do have to execute it once |
233 | $contextNode = $iteratorStack[$level]; |
234 | $iteratorStack[$level] = false; |
235 | } |
236 | |
237 | $newIterator = false; |
238 | $contextName = false; |
239 | $contextChildren = false; |
240 | |
241 | if ( $contextNode === false ) { |
242 | // nothing to do |
243 | } elseif ( is_string( $contextNode ) ) { |
244 | $out .= $contextNode; |
245 | } elseif ( $contextNode instanceof PPNode_Hash_Array ) { |
246 | $newIterator = $contextNode; |
247 | } elseif ( $contextNode instanceof PPNode_Hash_Attr ) { |
248 | // No output |
249 | } elseif ( $contextNode instanceof PPNode_Hash_Text ) { |
250 | $out .= $contextNode->value; |
251 | } elseif ( $contextNode instanceof PPNode_Hash_Tree ) { |
252 | $contextName = $contextNode->name; |
253 | $contextChildren = $contextNode->getRawChildren(); |
254 | } elseif ( is_array( $contextNode ) ) { |
255 | // Node descriptor array |
256 | if ( count( $contextNode ) !== 2 ) { |
257 | throw new RuntimeException( __METHOD__ . |
258 | ': found an array where a node descriptor should be' ); |
259 | } |
260 | [ $contextName, $contextChildren ] = $contextNode; |
261 | } else { |
262 | throw new RuntimeException( __METHOD__ . ': Invalid parameter type' ); |
263 | } |
264 | |
265 | // Handle node descriptor array or tree object |
266 | if ( $contextName === false ) { |
267 | // Not a node, already handled above |
268 | } elseif ( $contextName[0] === '@' ) { |
269 | // Attribute: no output |
270 | } elseif ( $contextName === 'template' ) { |
271 | # Double-brace expansion |
272 | $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren ); |
273 | if ( $flags & PPFrame::NO_TEMPLATES ) { |
274 | $newIterator = $this->virtualBracketedImplode( |
275 | '{{', '|', '}}', |
276 | $bits['title'], |
277 | $bits['parts'] |
278 | ); |
279 | } else { |
280 | $ret = $this->parser->braceSubstitution( $bits, $this ); |
281 | if ( isset( $ret['object'] ) ) { |
282 | $newIterator = $ret['object']; |
283 | } else { |
284 | $out .= $ret['text']; |
285 | } |
286 | } |
287 | } elseif ( $contextName === 'tplarg' ) { |
288 | # Triple-brace expansion |
289 | $bits = PPNode_Hash_Tree::splitRawTemplate( $contextChildren ); |
290 | if ( $flags & PPFrame::NO_ARGS ) { |
291 | $newIterator = $this->virtualBracketedImplode( |
292 | '{{{', '|', '}}}', |
293 | $bits['title'], |
294 | $bits['parts'] |
295 | ); |
296 | } else { |
297 | $ret = $this->parser->argSubstitution( $bits, $this ); |
298 | if ( isset( $ret['object'] ) ) { |
299 | $newIterator = $ret['object']; |
300 | } else { |
301 | $out .= $ret['text']; |
302 | } |
303 | } |
304 | } elseif ( $contextName === 'comment' ) { |
305 | # HTML-style comment |
306 | # Remove it in HTML, pre+remove and STRIP_COMMENTS modes |
307 | # Not in RECOVER_COMMENTS mode (msgnw) though. |
308 | if ( ( $this->parser->getOutputType() === Parser::OT_HTML |
309 | || ( $this->parser->getOutputType() === Parser::OT_PREPROCESS && |
310 | $this->parser->getOptions()->getRemoveComments() ) |
311 | || ( $flags & PPFrame::STRIP_COMMENTS ) |
312 | ) && !( $flags & PPFrame::RECOVER_COMMENTS ) |
313 | ) { |
314 | $out .= ''; |
315 | } elseif ( |
316 | $this->parser->getOutputType() === Parser::OT_WIKI && |
317 | !( $flags & PPFrame::RECOVER_COMMENTS ) |
318 | ) { |
319 | # Add a strip marker in PST mode so that pstPass2() can |
320 | # run some old-fashioned regexes on the result. |
321 | # Not in RECOVER_COMMENTS mode (extractSections) though. |
322 | $out .= $this->parser->insertStripItem( $contextChildren[0] ); |
323 | } else { |
324 | # Recover the literal comment in RECOVER_COMMENTS and pre+no-remove |
325 | $out .= $contextChildren[0]; |
326 | } |
327 | } elseif ( $contextName === 'ignore' ) { |
328 | # Output suppression used by <includeonly> etc. |
329 | # OT_WIKI will only respect <ignore> in substed templates. |
330 | # The other output types respect it unless NO_IGNORE is set. |
331 | # extractSections() sets NO_IGNORE and so never respects it. |
332 | if ( ( !isset( $this->parent ) && $this->parser->getOutputType() === Parser::OT_WIKI ) |
333 | || ( $flags & PPFrame::NO_IGNORE ) |
334 | ) { |
335 | $out .= $contextChildren[0]; |
336 | } else { |
337 | // $out .= ''; |
338 | } |
339 | } elseif ( $contextName === 'ext' ) { |
340 | # Extension tag |
341 | $bits = PPNode_Hash_Tree::splitRawExt( $contextChildren ) + |
342 | [ 'attr' => null, 'inner' => null, 'close' => null ]; |
343 | if ( $flags & PPFrame::NO_TAGS ) { |
344 | $s = '<' . $bits['name']->getFirstChild()->value; |
345 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
346 | if ( $bits['attr'] ) { |
347 | $s .= $bits['attr']->getFirstChild()->value; |
348 | } |
349 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
350 | if ( $bits['inner'] ) { |
351 | $s .= '>' . $bits['inner']->getFirstChild()->value; |
352 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
353 | if ( $bits['close'] ) { |
354 | $s .= $bits['close']->getFirstChild()->value; |
355 | } |
356 | } else { |
357 | $s .= '/>'; |
358 | } |
359 | $out .= $s; |
360 | } else { |
361 | $out .= $this->parser->extensionSubstitution( $bits, $this, |
362 | (bool)( $flags & PPFrame::PROCESS_NOWIKI ) ); |
363 | } |
364 | } elseif ( $contextName === 'h' ) { |
365 | # Heading |
366 | if ( $this->parser->getOutputType() === Parser::OT_HTML ) { |
367 | # Expand immediately and insert heading index marker |
368 | $s = $this->expand( $contextChildren, $flags ); |
369 | $bits = PPNode_Hash_Tree::splitRawHeading( $contextChildren ); |
370 | $titleText = $this->title->getPrefixedDBkey(); |
371 | $this->parser->mHeadings[] = [ $titleText, $bits['i'] ]; |
372 | $serial = count( $this->parser->mHeadings ) - 1; |
373 | $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX; |
374 | $s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] ); |
375 | $this->parser->getStripState()->addGeneral( $marker, '' ); |
376 | $out .= $s; |
377 | } else { |
378 | # Expand in virtual stack |
379 | $newIterator = $contextChildren; |
380 | } |
381 | } else { |
382 | # Generic recursive expansion |
383 | $newIterator = $contextChildren; |
384 | } |
385 | |
386 | if ( $newIterator !== false ) { |
387 | $outStack[] = ''; |
388 | $iteratorStack[] = $newIterator; |
389 | $indexStack[] = 0; |
390 | } elseif ( $iteratorStack[$level] === false ) { |
391 | // Return accumulated value to parent |
392 | // With tail recursion |
393 | while ( $iteratorStack[$level] === false && $level > 0 ) { |
394 | $outStack[$level - 1] .= $out; |
395 | array_pop( $outStack ); |
396 | array_pop( $iteratorStack ); |
397 | array_pop( $indexStack ); |
398 | $level--; |
399 | } |
400 | } |
401 | } |
402 | --$expansionDepth; |
403 | return $outStack[0]; |
404 | } |
405 | |
406 | /** |
407 | * @param string $sep |
408 | * @param int $flags |
409 | * @param string|PPNode ...$args |
410 | * @return string |
411 | */ |
412 | public function implodeWithFlags( $sep, $flags, ...$args ) { |
413 | $first = true; |
414 | $s = ''; |
415 | foreach ( $args as $root ) { |
416 | if ( $root instanceof PPNode_Hash_Array ) { |
417 | $root = $root->value; |
418 | } |
419 | if ( !is_array( $root ) ) { |
420 | $root = [ $root ]; |
421 | } |
422 | foreach ( $root as $node ) { |
423 | if ( $first ) { |
424 | $first = false; |
425 | } else { |
426 | $s .= $sep; |
427 | } |
428 | $s .= $this->expand( $node, $flags ); |
429 | } |
430 | } |
431 | return $s; |
432 | } |
433 | |
434 | /** |
435 | * Implode with no flags specified |
436 | * This previously called implodeWithFlags but has now been inlined to reduce stack depth |
437 | * @param string $sep |
438 | * @param string|PPNode ...$args |
439 | * @return string |
440 | */ |
441 | public function implode( $sep, ...$args ) { |
442 | $first = true; |
443 | $s = ''; |
444 | foreach ( $args as $root ) { |
445 | if ( $root instanceof PPNode_Hash_Array ) { |
446 | $root = $root->value; |
447 | } |
448 | if ( !is_array( $root ) ) { |
449 | $root = [ $root ]; |
450 | } |
451 | foreach ( $root as $node ) { |
452 | if ( $first ) { |
453 | $first = false; |
454 | } else { |
455 | $s .= $sep; |
456 | } |
457 | $s .= $this->expand( $node ); |
458 | } |
459 | } |
460 | return $s; |
461 | } |
462 | |
463 | /** |
464 | * Makes an object that, when expand()ed, will be the same as one obtained |
465 | * with implode() |
466 | * |
467 | * @param string $sep |
468 | * @param string|PPNode ...$args |
469 | * @return PPNode_Hash_Array |
470 | */ |
471 | public function virtualImplode( $sep, ...$args ) { |
472 | $out = []; |
473 | $first = true; |
474 | |
475 | foreach ( $args as $root ) { |
476 | if ( $root instanceof PPNode_Hash_Array ) { |
477 | $root = $root->value; |
478 | } |
479 | if ( !is_array( $root ) ) { |
480 | $root = [ $root ]; |
481 | } |
482 | foreach ( $root as $node ) { |
483 | if ( $first ) { |
484 | $first = false; |
485 | } else { |
486 | $out[] = $sep; |
487 | } |
488 | $out[] = $node; |
489 | } |
490 | } |
491 | return new PPNode_Hash_Array( $out ); |
492 | } |
493 | |
494 | /** |
495 | * Virtual implode with brackets |
496 | * |
497 | * @param string $start |
498 | * @param string $sep |
499 | * @param string $end |
500 | * @param string|PPNode ...$args |
501 | * @return PPNode_Hash_Array |
502 | */ |
503 | public function virtualBracketedImplode( $start, $sep, $end, ...$args ) { |
504 | $out = [ $start ]; |
505 | $first = true; |
506 | |
507 | foreach ( $args as $root ) { |
508 | if ( $root instanceof PPNode_Hash_Array ) { |
509 | $root = $root->value; |
510 | } |
511 | if ( !is_array( $root ) ) { |
512 | $root = [ $root ]; |
513 | } |
514 | foreach ( $root as $node ) { |
515 | if ( $first ) { |
516 | $first = false; |
517 | } else { |
518 | $out[] = $sep; |
519 | } |
520 | $out[] = $node; |
521 | } |
522 | } |
523 | $out[] = $end; |
524 | return new PPNode_Hash_Array( $out ); |
525 | } |
526 | |
527 | public function __toString() { |
528 | return 'frame{}'; |
529 | } |
530 | |
531 | /** |
532 | * @param string|false $level |
533 | * @return false|string |
534 | */ |
535 | public function getPDBK( $level = false ) { |
536 | if ( $level === false ) { |
537 | return $this->title->getPrefixedDBkey(); |
538 | } else { |
539 | return $this->titleCache[$level] ?? false; |
540 | } |
541 | } |
542 | |
543 | /** |
544 | * @return array |
545 | */ |
546 | public function getArguments() { |
547 | return []; |
548 | } |
549 | |
550 | /** |
551 | * @return array |
552 | */ |
553 | public function getNumberedArguments() { |
554 | return []; |
555 | } |
556 | |
557 | /** |
558 | * @return array |
559 | */ |
560 | public function getNamedArguments() { |
561 | return []; |
562 | } |
563 | |
564 | /** |
565 | * Returns true if there are no arguments in this frame |
566 | * |
567 | * @return bool |
568 | */ |
569 | public function isEmpty() { |
570 | return true; |
571 | } |
572 | |
573 | /** |
574 | * @param int|string $name |
575 | * @return bool Always false in this implementation. |
576 | */ |
577 | public function getArgument( $name ) { |
578 | return false; |
579 | } |
580 | |
581 | /** |
582 | * Returns true if the infinite loop check is OK, false if a loop is detected |
583 | * |
584 | * @param Title $title |
585 | * |
586 | * @return bool |
587 | */ |
588 | public function loopCheck( $title ) { |
589 | return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] ); |
590 | } |
591 | |
592 | /** |
593 | * Return true if the frame is a template frame |
594 | * |
595 | * @return bool |
596 | */ |
597 | public function isTemplate() { |
598 | return false; |
599 | } |
600 | |
601 | /** |
602 | * Get a title of frame |
603 | * |
604 | * @return Title |
605 | */ |
606 | public function getTitle() { |
607 | return $this->title; |
608 | } |
609 | |
610 | /** |
611 | * Set the volatile flag |
612 | * |
613 | * @param bool $flag |
614 | */ |
615 | public function setVolatile( $flag = true ) { |
616 | $this->volatile = $flag; |
617 | } |
618 | |
619 | /** |
620 | * Get the volatile flag |
621 | * |
622 | * @return bool |
623 | */ |
624 | public function isVolatile() { |
625 | return $this->volatile; |
626 | } |
627 | |
628 | /** |
629 | * @param int $ttl |
630 | */ |
631 | public function setTTL( $ttl ) { |
632 | if ( $ttl !== null && ( $this->ttl === null || $ttl < $this->ttl ) ) { |
633 | $this->ttl = $ttl; |
634 | } |
635 | } |
636 | |
637 | /** |
638 | * @return int|null |
639 | */ |
640 | public function getTTL() { |
641 | return $this->ttl; |
642 | } |
643 | } |
644 | |
645 | /** @deprecated class alias since 1.43 */ |
646 | class_alias( PPFrame_Hash::class, 'PPFrame_Hash' ); |