Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1426332
PPFrame_Hash.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
PPFrame_Hash.php
View Options
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup Parser
*/
namespace
MediaWiki\Parser
;
use
InvalidArgumentException
;
use
MediaWiki\Message\Message
;
use
MediaWiki\Title\Title
;
use
RuntimeException
;
use
Stringable
;
/**
* An expansion frame, used as a context to expand the result of preprocessToObj()
* @ingroup Parser
*/
// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
class
PPFrame_Hash
implements
Stringable
,
PPFrame
{
/**
* @var Parser
*/
public
$parser
;
/**
* @var Preprocessor
*/
public
$preprocessor
;
/**
* @var Title
*/
public
$title
;
/**
* @var (string|false)[]
*/
public
$titleCache
;
/**
* Hashtable listing templates which are disallowed for expansion in this frame,
* having been encountered previously in parent frames.
* @var true[]
*/
public
$loopCheckHash
;
/**
* Recursion depth of this frame, top = 0
* Note that this is NOT the same as expansion depth in expand()
* @var int
*/
public
$depth
;
/** @var bool */
private
$volatile
=
false
;
/** @var int|null */
private
$ttl
=
null
;
/**
* @var array
*/
protected
$childExpansionCache
;
/**
* @var int
*/
private
$maxPPNodeCount
;
/**
* @var int
*/
private
$maxPPExpandDepth
;
/**
* @param Preprocessor $preprocessor The parent preprocessor
*/
public
function
__construct
(
$preprocessor
)
{
$this
->
preprocessor
=
$preprocessor
;
$this
->
parser
=
$preprocessor
->
parser
;
$this
->
title
=
$this
->
parser
->
getTitle
();
$this
->
maxPPNodeCount
=
$this
->
parser
->
getOptions
()->
getMaxPPNodeCount
();
$this
->
maxPPExpandDepth
=
$this
->
parser
->
getOptions
()->
getMaxPPExpandDepth
();
$this
->
titleCache
=
[
$this
->
title
?
$this
->
title
->
getPrefixedDBkey
()
:
false
];
$this
->
loopCheckHash
=
[];
$this
->
depth
=
0
;
$this
->
childExpansionCache
=
[];
}
/**
* Create a new child frame
* $args is optionally a multi-root PPNode or array containing the template arguments
*
* @param PPNode[]|false|PPNode_Hash_Array $args
* @param Title|false $title
* @param int $indexOffset
* @return PPTemplateFrame_Hash
*/
public
function
newChild
(
$args
=
false
,
$title
=
false
,
$indexOffset
=
0
)
{
$namedArgs
=
[];
$numberedArgs
=
[];
if
(
$title
===
false
)
{
$title
=
$this
->
title
;
}
if
(
$args
!==
false
)
{
if
(
$args
instanceof
PPNode_Hash_Array
)
{
$args
=
$args
->
value
;
}
elseif
(
!
is_array
(
$args
)
)
{
throw
new
InvalidArgumentException
(
__METHOD__
.
': $args must be array or PPNode_Hash_Array'
);
}
foreach
(
$args
as
$arg
)
{
$bits
=
$arg
->
splitArg
();
if
(
$bits
[
'index'
]
!==
''
)
{
// Numbered parameter
$index
=
$bits
[
'index'
]
-
$indexOffset
;
if
(
isset
(
$namedArgs
[
$index
]
)
||
isset
(
$numberedArgs
[
$index
]
)
)
{
$this
->
parser
->
getOutput
()->
addWarningMsg
(
'duplicate-args-warning'
,
Message
::
plaintextParam
(
(
string
)
$this
->
title
),
Message
::
plaintextParam
(
(
string
)
$title
),
Message
::
numParam
(
$index
)
);
$this
->
parser
->
addTrackingCategory
(
'duplicate-args-category'
);
}
$numberedArgs
[
$index
]
=
$bits
[
'value'
];
unset
(
$namedArgs
[
$index
]
);
}
else
{
// Named parameter
$name
=
trim
(
$this
->
expand
(
$bits
[
'name'
],
PPFrame
::
STRIP_COMMENTS
)
);
if
(
isset
(
$namedArgs
[
$name
]
)
||
isset
(
$numberedArgs
[
$name
]
)
)
{
$this
->
parser
->
getOutput
()->
addWarningMsg
(
'duplicate-args-warning'
,
Message
::
plaintextParam
(
(
string
)
$this
->
title
),
Message
::
plaintextParam
(
(
string
)
$title
),
Message
::
plaintextParam
(
$name
)
);
$this
->
parser
->
addTrackingCategory
(
'duplicate-args-category'
);
}
$namedArgs
[
$name
]
=
$bits
[
'value'
];
unset
(
$numberedArgs
[
$name
]
);
}
}
}
return
new
PPTemplateFrame_Hash
(
$this
->
preprocessor
,
$this
,
$numberedArgs
,
$namedArgs
,
$title
);
}
/**
* @param string|int $key
* @param string|PPNode $root
* @param int $flags
* @return string
*/
public
function
cachedExpand
(
$key
,
$root
,
$flags
=
0
)
{
// we don't have a parent, so we don't have a cache
return
$this
->
expand
(
$root
,
$flags
);
}
/**
* @param string|PPNode $root
* @param int $flags
* @return string
*/
public
function
expand
(
$root
,
$flags
=
0
)
{
static
$expansionDepth
=
0
;
if
(
is_string
(
$root
)
)
{
return
$root
;
}
if
(
++
$this
->
parser
->
mPPNodeCount
>
$this
->
maxPPNodeCount
)
{
$this
->
parser
->
limitationWarn
(
'node-count-exceeded'
,
$this
->
parser
->
mPPNodeCount
,
$this
->
maxPPNodeCount
);
return
'<span class="error">Node-count limit exceeded</span>'
;
}
if
(
$expansionDepth
>
$this
->
maxPPExpandDepth
)
{
$this
->
parser
->
limitationWarn
(
'expansion-depth-exceeded'
,
$expansionDepth
,
$this
->
maxPPExpandDepth
);
return
'<span class="error">Expansion depth limit exceeded</span>'
;
}
++
$expansionDepth
;
if
(
$expansionDepth
>
$this
->
parser
->
mHighestExpansionDepth
)
{
$this
->
parser
->
mHighestExpansionDepth
=
$expansionDepth
;
}
$outStack
=
[
''
,
''
];
$iteratorStack
=
[
false
,
$root
];
$indexStack
=
[
0
,
0
];
while
(
count
(
$iteratorStack
)
>
1
)
{
$level
=
count
(
$outStack
)
-
1
;
$iteratorNode
=&
$iteratorStack
[
$level
];
$out
=&
$outStack
[
$level
];
$index
=&
$indexStack
[
$level
];
if
(
is_array
(
$iteratorNode
)
)
{
if
(
$index
>=
count
(
$iteratorNode
)
)
{
// All done with this iterator
$iteratorStack
[
$level
]
=
false
;
$contextNode
=
false
;
}
else
{
$contextNode
=
$iteratorNode
[
$index
];
$index
++;
}
}
elseif
(
$iteratorNode
instanceof
PPNode_Hash_Array
)
{
if
(
$index
>=
$iteratorNode
->
getLength
()
)
{
// All done with this iterator
$iteratorStack
[
$level
]
=
false
;
$contextNode
=
false
;
}
else
{
$contextNode
=
$iteratorNode
->
item
(
$index
);
$index
++;
}
}
else
{
// Copy to $contextNode and then delete from iterator stack,
// because this is not an iterator but we do have to execute it once
$contextNode
=
$iteratorStack
[
$level
];
$iteratorStack
[
$level
]
=
false
;
}
$newIterator
=
false
;
$contextName
=
false
;
$contextChildren
=
false
;
if
(
$contextNode
===
false
)
{
// nothing to do
}
elseif
(
is_string
(
$contextNode
)
)
{
$out
.=
$contextNode
;
}
elseif
(
$contextNode
instanceof
PPNode_Hash_Array
)
{
$newIterator
=
$contextNode
;
}
elseif
(
$contextNode
instanceof
PPNode_Hash_Attr
)
{
// No output
}
elseif
(
$contextNode
instanceof
PPNode_Hash_Text
)
{
$out
.=
$contextNode
->
value
;
}
elseif
(
$contextNode
instanceof
PPNode_Hash_Tree
)
{
$contextName
=
$contextNode
->
name
;
$contextChildren
=
$contextNode
->
getRawChildren
();
}
elseif
(
is_array
(
$contextNode
)
)
{
// Node descriptor array
if
(
count
(
$contextNode
)
!==
2
)
{
throw
new
RuntimeException
(
__METHOD__
.
': found an array where a node descriptor should be'
);
}
[
$contextName
,
$contextChildren
]
=
$contextNode
;
}
else
{
throw
new
RuntimeException
(
__METHOD__
.
': Invalid parameter type'
);
}
// Handle node descriptor array or tree object
if
(
$contextName
===
false
)
{
// Not a node, already handled above
}
elseif
(
$contextName
[
0
]
===
'@'
)
{
// Attribute: no output
}
elseif
(
$contextName
===
'template'
)
{
# Double-brace expansion
$bits
=
PPNode_Hash_Tree
::
splitRawTemplate
(
$contextChildren
);
if
(
$flags
&
PPFrame
::
NO_TEMPLATES
)
{
$newIterator
=
$this
->
virtualBracketedImplode
(
'{{'
,
'|'
,
'}}'
,
$bits
[
'title'
],
$bits
[
'parts'
]
);
}
else
{
$ret
=
$this
->
parser
->
braceSubstitution
(
$bits
,
$this
);
if
(
isset
(
$ret
[
'object'
]
)
)
{
$newIterator
=
$ret
[
'object'
];
}
else
{
$out
.=
$ret
[
'text'
];
}
}
}
elseif
(
$contextName
===
'tplarg'
)
{
# Triple-brace expansion
$bits
=
PPNode_Hash_Tree
::
splitRawTemplate
(
$contextChildren
);
if
(
$flags
&
PPFrame
::
NO_ARGS
)
{
$newIterator
=
$this
->
virtualBracketedImplode
(
'{{{'
,
'|'
,
'}}}'
,
$bits
[
'title'
],
$bits
[
'parts'
]
);
}
else
{
$ret
=
$this
->
parser
->
argSubstitution
(
$bits
,
$this
);
if
(
isset
(
$ret
[
'object'
]
)
)
{
$newIterator
=
$ret
[
'object'
];
}
else
{
$out
.=
$ret
[
'text'
];
}
}
}
elseif
(
$contextName
===
'comment'
)
{
# HTML-style comment
# Remove it in HTML, pre+remove and STRIP_COMMENTS modes
# Not in RECOVER_COMMENTS mode (msgnw) though.
if
(
(
$this
->
parser
->
getOutputType
()
===
Parser
::
OT_HTML
||
(
$this
->
parser
->
getOutputType
()
===
Parser
::
OT_PREPROCESS
&&
$this
->
parser
->
getOptions
()->
getRemoveComments
()
)
||
(
$flags
&
PPFrame
::
STRIP_COMMENTS
)
)
&&
!(
$flags
&
PPFrame
::
RECOVER_COMMENTS
)
)
{
$out
.=
''
;
}
elseif
(
$this
->
parser
->
getOutputType
()
===
Parser
::
OT_WIKI
&&
!(
$flags
&
PPFrame
::
RECOVER_COMMENTS
)
)
{
# Add a strip marker in PST mode so that pstPass2() can
# run some old-fashioned regexes on the result.
# Not in RECOVER_COMMENTS mode (extractSections) though.
$out
.=
$this
->
parser
->
insertStripItem
(
$contextChildren
[
0
]
);
}
else
{
# Recover the literal comment in RECOVER_COMMENTS and pre+no-remove
$out
.=
$contextChildren
[
0
];
}
}
elseif
(
$contextName
===
'ignore'
)
{
# Output suppression used by <includeonly> etc.
# OT_WIKI will only respect <ignore> in substed templates.
# The other output types respect it unless NO_IGNORE is set.
# extractSections() sets NO_IGNORE and so never respects it.
if
(
(
!
isset
(
$this
->
parent
)
&&
$this
->
parser
->
getOutputType
()
===
Parser
::
OT_WIKI
)
||
(
$flags
&
PPFrame
::
NO_IGNORE
)
)
{
$out
.=
$contextChildren
[
0
];
}
else
{
// $out .= '';
}
}
elseif
(
$contextName
===
'ext'
)
{
# Extension tag
$bits
=
PPNode_Hash_Tree
::
splitRawExt
(
$contextChildren
)
+
[
'attr'
=>
null
,
'inner'
=>
null
,
'close'
=>
null
];
if
(
$flags
&
PPFrame
::
NO_TAGS
)
{
$s
=
'<'
.
$bits
[
'name'
]->
getFirstChild
()->
value
;
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable
if
(
$bits
[
'attr'
]
)
{
$s
.=
$bits
[
'attr'
]->
getFirstChild
()->
value
;
}
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable
if
(
$bits
[
'inner'
]
)
{
$s
.=
'>'
.
$bits
[
'inner'
]->
getFirstChild
()->
value
;
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable
if
(
$bits
[
'close'
]
)
{
$s
.=
$bits
[
'close'
]->
getFirstChild
()->
value
;
}
}
else
{
$s
.=
'/>'
;
}
$out
.=
$s
;
}
else
{
$out
.=
$this
->
parser
->
extensionSubstitution
(
$bits
,
$this
,
(
bool
)(
$flags
&
PPFrame
::
PROCESS_NOWIKI
)
);
}
}
elseif
(
$contextName
===
'h'
)
{
# Heading
if
(
$this
->
parser
->
getOutputType
()
===
Parser
::
OT_HTML
)
{
# Expand immediately and insert heading index marker
$s
=
$this
->
expand
(
$contextChildren
,
$flags
);
$bits
=
PPNode_Hash_Tree
::
splitRawHeading
(
$contextChildren
);
$titleText
=
$this
->
title
->
getPrefixedDBkey
();
$this
->
parser
->
mHeadings
[]
=
[
$titleText
,
$bits
[
'i'
]
];
$serial
=
count
(
$this
->
parser
->
mHeadings
)
-
1
;
$marker
=
Parser
::
MARKER_PREFIX
.
"-h-$serial-"
.
Parser
::
MARKER_SUFFIX
;
$s
=
substr
(
$s
,
0
,
$bits
[
'level'
]
)
.
$marker
.
substr
(
$s
,
$bits
[
'level'
]
);
$this
->
parser
->
getStripState
()->
addGeneral
(
$marker
,
''
);
$out
.=
$s
;
}
else
{
# Expand in virtual stack
$newIterator
=
$contextChildren
;
}
}
else
{
# Generic recursive expansion
$newIterator
=
$contextChildren
;
}
if
(
$newIterator
!==
false
)
{
$outStack
[]
=
''
;
$iteratorStack
[]
=
$newIterator
;
$indexStack
[]
=
0
;
}
elseif
(
$iteratorStack
[
$level
]
===
false
)
{
// Return accumulated value to parent
// With tail recursion
while
(
$iteratorStack
[
$level
]
===
false
&&
$level
>
0
)
{
$outStack
[
$level
-
1
]
.=
$out
;
array_pop
(
$outStack
);
array_pop
(
$iteratorStack
);
array_pop
(
$indexStack
);
$level
--;
}
}
}
--
$expansionDepth
;
return
$outStack
[
0
];
}
/**
* @param string $sep
* @param int $flags
* @param string|PPNode ...$args
* @return string
*/
public
function
implodeWithFlags
(
$sep
,
$flags
,
...
$args
)
{
$first
=
true
;
$s
=
''
;
foreach
(
$args
as
$root
)
{
if
(
$root
instanceof
PPNode_Hash_Array
)
{
$root
=
$root
->
value
;
}
if
(
!
is_array
(
$root
)
)
{
$root
=
[
$root
];
}
foreach
(
$root
as
$node
)
{
if
(
$first
)
{
$first
=
false
;
}
else
{
$s
.=
$sep
;
}
$s
.=
$this
->
expand
(
$node
,
$flags
);
}
}
return
$s
;
}
/**
* Implode with no flags specified
* This previously called implodeWithFlags but has now been inlined to reduce stack depth
* @param string $sep
* @param string|PPNode ...$args
* @return string
*/
public
function
implode
(
$sep
,
...
$args
)
{
$first
=
true
;
$s
=
''
;
foreach
(
$args
as
$root
)
{
if
(
$root
instanceof
PPNode_Hash_Array
)
{
$root
=
$root
->
value
;
}
if
(
!
is_array
(
$root
)
)
{
$root
=
[
$root
];
}
foreach
(
$root
as
$node
)
{
if
(
$first
)
{
$first
=
false
;
}
else
{
$s
.=
$sep
;
}
$s
.=
$this
->
expand
(
$node
);
}
}
return
$s
;
}
/**
* Makes an object that, when expand()ed, will be the same as one obtained
* with implode()
*
* @param string $sep
* @param string|PPNode ...$args
* @return PPNode_Hash_Array
*/
public
function
virtualImplode
(
$sep
,
...
$args
)
{
$out
=
[];
$first
=
true
;
foreach
(
$args
as
$root
)
{
if
(
$root
instanceof
PPNode_Hash_Array
)
{
$root
=
$root
->
value
;
}
if
(
!
is_array
(
$root
)
)
{
$root
=
[
$root
];
}
foreach
(
$root
as
$node
)
{
if
(
$first
)
{
$first
=
false
;
}
else
{
$out
[]
=
$sep
;
}
$out
[]
=
$node
;
}
}
return
new
PPNode_Hash_Array
(
$out
);
}
/**
* Virtual implode with brackets
*
* @param string $start
* @param string $sep
* @param string $end
* @param string|PPNode ...$args
* @return PPNode_Hash_Array
*/
public
function
virtualBracketedImplode
(
$start
,
$sep
,
$end
,
...
$args
)
{
$out
=
[
$start
];
$first
=
true
;
foreach
(
$args
as
$root
)
{
if
(
$root
instanceof
PPNode_Hash_Array
)
{
$root
=
$root
->
value
;
}
if
(
!
is_array
(
$root
)
)
{
$root
=
[
$root
];
}
foreach
(
$root
as
$node
)
{
if
(
$first
)
{
$first
=
false
;
}
else
{
$out
[]
=
$sep
;
}
$out
[]
=
$node
;
}
}
$out
[]
=
$end
;
return
new
PPNode_Hash_Array
(
$out
);
}
public
function
__toString
()
{
return
'frame{}'
;
}
/**
* @param string|false $level
* @return false|string
*/
public
function
getPDBK
(
$level
=
false
)
{
if
(
$level
===
false
)
{
return
$this
->
title
->
getPrefixedDBkey
();
}
else
{
return
$this
->
titleCache
[
$level
]
??
false
;
}
}
/**
* @return array
*/
public
function
getArguments
()
{
return
[];
}
/**
* @return array
*/
public
function
getNumberedArguments
()
{
return
[];
}
/**
* @return array
*/
public
function
getNamedArguments
()
{
return
[];
}
/**
* Returns true if there are no arguments in this frame
*
* @return bool
*/
public
function
isEmpty
()
{
return
true
;
}
/**
* @param int|string $name
* @return bool Always false in this implementation.
*/
public
function
getArgument
(
$name
)
{
return
false
;
}
/**
* Returns true if the infinite loop check is OK, false if a loop is detected
*
* @param Title $title
*
* @return bool
*/
public
function
loopCheck
(
$title
)
{
return
!
isset
(
$this
->
loopCheckHash
[
$title
->
getPrefixedDBkey
()]
);
}
/**
* Return true if the frame is a template frame
*
* @return bool
*/
public
function
isTemplate
()
{
return
false
;
}
/**
* Get a title of frame
*
* @return Title
*/
public
function
getTitle
()
{
return
$this
->
title
;
}
/**
* Set the volatile flag
*
* @param bool $flag
*/
public
function
setVolatile
(
$flag
=
true
)
{
$this
->
volatile
=
$flag
;
}
/**
* Get the volatile flag
*
* @return bool
*/
public
function
isVolatile
()
{
return
$this
->
volatile
;
}
/**
* @param int $ttl
*/
public
function
setTTL
(
$ttl
)
{
if
(
$ttl
!==
null
&&
(
$this
->
ttl
===
null
||
$ttl
<
$this
->
ttl
)
)
{
$this
->
ttl
=
$ttl
;
}
}
/**
* @return int|null
*/
public
function
getTTL
()
{
return
$this
->
ttl
;
}
}
/** @deprecated class alias since 1.43 */
class_alias
(
PPFrame_Hash
::
class
,
'PPFrame_Hash'
);
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 13:02 (1 d, 15 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
bb/e3/17b147f7c2365b98a4045da507f9
Default Alt Text
PPFrame_Hash.php (16 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment