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