Manual:Funciones del analizador sintáctico
Las funciones del analizador, añadida en MediaWiki 1.7, es un tipo de extension que se integra estrechamente con el analizador. La expresión «función del analizador» no debería confundirse con $2, que es una colección de funciones simples del analizador. (Véase Ayuda:Extensión:ParserFunctions para esa otra.)
Descripción
Mientras que una extensión de marcado está concebida para tomar texto sin procesar y devolver HTML al navegador, una función del analizador puede «interactuar» con otros elementos wiki de la página. Por ejemplo, la salida de una función de análisis se podría usar como parámetro de una plantilla o en la construcción de un enlace.
La sintaxis típica de una función del analizador es:
{{ #functionname: param1 | param2 | param3 }}
Para más información, consulta la documentación de Parser::setFunctionHook ( $id, $callback, $flags = 0 )
. Según esta documentación,
- La función de retrollamada (callback) debería tener la forma:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
- O con
SFH_OBJECT_ARGS
:function myParserFunction( $parser, $frame, $args ) { ... }
La primera variante de la llamada pasa todos los argumentos como texto plano.
La segunda pasa todos los argumentos como una matriz de PPNode , excepto el primero ($args[0]
), que en la actualidad es texto, aunque esto puede cambiar en el futuro.
Estos representan el wikitexto sin expandir.
El parámetro $frame
se puede utilizar para expandir estos argumentos según sea necesario.
Esto se suele usar para el procesamiento condicional de forma que solo se evalúe el caso true
con una función del analizador if-
o switch-like
.
El objeto de marco también puede subir por el árbol del documento para obtener información sobre el llamador y dispone de funciones para determinar y gestionar la profundidad de la llamada, el tiempo de vida y si el resultado de la función del analizador es volátil.
Crear una función del analizador es ligeramente más complejo que crear una nueva etiqueta porque el nombre de la función debe ser una palabra mágica, una palabra clave que sea compatible con el uso de alias y localización.
Ejemplo simple
A continuación hay un ejemplo de una extensión que crea una función del analizador.
El registro va a extension.json y el código a includes/ExampleExtension.php, respectivamente:
Standard: | Using the HookHandler interface: |
---|---|
extension.json | |
{
"name": "ExampleExtension",
"author": "Me",
"version": "1.0.0",
"url": "https://www.mediawiki.org/wiki/Extension:ExampleExtension",
"descriptionmsg": "exampleextension-desc",
"license-name": "GPL-2.0-or-later",
"type": "parserhook",
"MessagesDirs": {
"ExampleExtension": [
"i18n"
]
},
"AutoloadClasses": {
"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
},
"ExtensionMessagesFiles": {
"ExampleExtensionMagic": "ExampleExtension.i18n.php"
},
"Hooks": {
"ParserFirstCallInit": "ExampleExtensionHooks::onParserFirstCallInit"
},
"manifest_version": 1
}
|
{
"name": "ExampleExtension",
"author": "Me",
"version": "1.0.0",
"url": "https://www.mediawiki.org/wiki/Extension:ExampleExtension",
"descriptionmsg": "exampleextension-desc",
"license-name": "GPL-2.0-or-later",
"type": "parserhook",
"MessagesDirs": {
"ExampleExtension": [
"i18n"
]
},
"AutoloadClasses": {
"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
},
"ExtensionMessagesFiles": {
"ExampleExtensionMagic": "ExampleExtension.i18n.php"
},
"Hooks": {
"ParserFirstCallInit": "onParserFirstCallInit"
},
"HookHandlers": {
"ExampleExtensionHooks": {
"class": "MediaWiki\\Extension\\ExampleExtension\\Hooks"
}
},
"manifest_version": 1
}
|
ExampleExtensionHooks.php | |
<?php
class ExampleExtensionHooks {
// Registra cualquier retrollamada de renderización con el analizador
public static function onParserFirstCallInit( Parser $parser ) {
// Crea un gancho (''hook'') de función que asocia la palabra mágica <code>example</code> con renderExample()
$parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
}
// Muestra la salida de {{#example:}}.
public static function renderExample( Parser $parser, $param1 = '', $param2 = '', $param3 = '' ) {
// Los parámetros de entrada son wikitexto con las plantillas expandidas.
// La salida también debería estar en forma de wikitexto.
$output = "param1 is $param1 and param2 is $param2 and param3 is $param3";
return $output;
}
}
|
<?php
class ExampleExtensionHooks implements ParserFirstCallInitHook {
// Register any render callbacks with the parser
public function onParserFirstCallInit( $parser ) {
// Create a function hook associating the <code>example</code> magic word with renderExample()
$parser->setFunctionHook( 'example', [ $this, 'renderExample' ] );
}
// Render the output of {{#example:}}.
public function renderExample( $parser, $param1 = '', $param2 = '', $param3 = '' ) {
// The input parameters are wikitext with templates expanded.
// The output should be wikitext too.
$output = "param1 is $param1 and param2 is $param2 and param3 is $param3";
return $output;
}
}
|
Otro archivo, ExampleExtension.i18n.php, en el directorio de tu extensión (no en el subdirectorio de src/) deberá contener:
<?php
/**
* @license GPL-2.0-or-later
* @author Tu Nombre (YourUserName)
*/
$magicWords = [];
/** English
* @author Tu Nombre (YourUserName)
*/
$magicWords['en'] = [
'example' => [ 0, 'example' ],
];
Con esta extensión activada,
- {{#example: hello | hi | hey}}
produce:
- param1 es hello y param2 es hi y param3 es hey
LocalSettings.php
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['MAG_CUSTOM', 'custom'];
Dentro de LocalSettings.php
Las palabras mágicas y sus funciones asociadas del analizador se pueden definir por completo en LocalSettings.php.
$wgHooks['ParserFirstCallInit'][] = function ( Parser $parser )
{
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['wikicodeToHtml', 'wikicodeToHtml'];
$parser->setFunctionHook( 'wikicodeToHtml', 'wikicodeToHtml' );
};
function wikicodeToHtml( Parser $parser, $code = '' )
{
$title = $parser->getTitle();
$options = $parser->Options();
$options->enableLimitReport(false);
$parser = $parser->getFreshParser();
return [$parser->parse($code, $title, $options)->getText(), 'isHTML' => true];
}
Funciones más largas
Para funciones más largas, quizá desees separar las funciones de gancho en un archivo _body.php o .hooks.php y convertirlas en funciones estáticas de una clase. Luego puedes cargar la clase con $wgAutoloadClasses y llamar a las funciones estáticas en los ganchos, p. ej.:
Agrega esto en tu archivo extension.json
:
"Hooks": {
"ParserFirstCallInit": "ExampleExtensionHooks::onParserFirstCallInit"
},
"AutoloadClasses": {
"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
}
- Véase: crear un manejador de eventos para otros estilos.
Luego agrega esto en tu archivo src/ExampleExtensionHooks.php
:
class ExampleExtensionHooks {
public static function onParserFirstCallInit( Parser $parser ) {
$parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
}
}
Interfaz del analizador
Control del análisis sintáctico de la salida
Para que el wikitexto devuelto por tu función del analizador esté completamente analizado (incluyendo las expansiones de plantillas), define la opción noparse
como false
en la salida:
return [ $output, 'noparse' => false ];
Parece ser que el valor predeterminado de noparse
cambió de false
a true
, al menos en algunas situaciones, en algún momento en torno a la versión 1.12.
En cambio, para que tu función del analizador devuelva HTML no analizado, en lugar de wikitexto, usa lo siguiente:
return [ $output, 'noparse' => true, 'isHTML' => true ];
Nombramiento
Por defecto, MW añade una almohadilla (#
) al nombre de cada función del analizador.
Para suprimir este añadido (y obtener una función del analizador sin el prefijo #
), debes incluir la constante SFH_NO_HASH en el argumento opcional flags a setFunctionHook, como se describe más adelante.
Al elegir un nombre sin almohadilla prefijada, ten en cuenta que ya no es posible transcluir una página con un nombre que empiece por ese nombre de función seguido del carácter dos puntos. En particular, evita nombres de función iguales al nombre de un espacio de nombres. En caso de que la transclusión interwiki [1] esté habilitada, también debes evitar los nombres de función iguales a un prefijo interwiki.
El gancho setFunctionHook
Para más información sobre la interfaz del analizador, consulta la documentación de setFunctionHook en includes/Parser.php. Aquí se muestra una copia (posiblemente obsoleta) de estos comentarios:
función setFunctionHook( $id, $callback, $flags = 0 )
Parámetros:
- cadena $id - el identificador de la palabra mágica
- mixto $callback - la función de retrollamada (y objeto) que usar
- entero $flags - opcional. Valores:
- SFH_NO_HASH (1) constante si llamas a la función sin
#
. - SFH_OBJECT_ARGS (2) si pasas un objeto PPFrame y una matriz de argumentos en lugar de una serie de argumentos de funciones, para las que vuelve atrás.
- Su valor por defecto es 0 (sin banderas).
- SFH_NO_HASH (1) constante si llamas a la función sin
Valor de retorno: La antigua función de retrollamada para este nombre, en caso de existir
Crea una función, por ejemplo, {{#sum:1|2|3}}
. La función de retrollamada debería tener la forma:
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
La retrollamada podrá devolver el texto resultado de la función o bien una matriz con el texto en el elemento 0 y una serie de banderas en los demás elementos. Los nombres de las banderas se especifican en las claves. Las banderas válidas son:
Nombre | Tipo | Valor por defecto | Descripción |
---|---|---|---|
found | Booleano | true
|
true si el texto devuelto es válido y el procesamiento de la plantilla debe detenerse.
|
text | ? | ? | El texto devuelto por la función. Si se especifica isChildObj o isLocalObj, esto debería ser un nodo del DOM en su lugar. |
noparse | Booleano | true
|
true si el texto no se debe preprocesar a un árbol del DOM, por ejemplo, las etiquetas HTML inseguras no se deben suprimir, etc.
|
isHTML | Booleano | ? | true si el texto devuelto es HTML y debe protegerse contra transformaciones a wikitexto. Sin embargo, consulta la discusión
|
nowiki | Booleano | generalmente false
|
true si el marcado wiki en el valor (texto) de retorno debe escaparse.
|
isChildObj | Booleano | ? | true si el texto es un nodo del DOM que necesita expandirse en un marco hijo.
|
isLocalObj | Booleano | ? | true si el texto es un nodo del DOM que necesita expandirse en el marco actual. El valor por defecto depende de otros valores y resultados.
|
preprocessFlags | ? | false
|
Banderas PPFrame opcionales que usar al analizar el texto devuelto. Esto solo se aplica cuando noparse es false .
|
title | ? | false
|
El objeto Title del que provino el texto. |
forceRawInterwiki | Booleano | ? | true si debe forzarse la transclusión interwiki para que se realice en crudo, sin renderizarse.
|
Funciones del analizador costosas
Algunas función del analizador representan un uso significativo de los recursos de un wiki y deben marcarse como «costosas». El número de función del analizador costosas en cualquier página dada está limitado por el valor de $wgExpensiveParserFunctionLimit . La propia función es la que decide qué se considera «costoso», pero, por lo general, debe considerarse cualquier cosa susceptible de causar un retraso que se prolongue más allá del simple procesamiento de datos. Esto incluye, por ejemplo, lecturas y escrituras en la base de datos, lanzar un script de la shell de forma síncrona o la manipulación de archivos. Por otra parte, no se tienen por qué marcar así todas estas funciones. Semantic MediaWiki, por ejemplo, solo marca como costosa una parte de sus lecturas de la base de datos. Esto se debe a que, en determinadas páginas con un uso intensivo de datos, podría sobrepasar fácilmente los límites normales de funciones del analizador costosas. En casos así, el potencial de un rendimiento notablemente más lento que no se marca como costoso es un compromiso con tener la funcionalidad que ofrece SMW.
Para marcar tu función del analizador como costoso desde dentro del cuerpo del código de la función, usa $result = $parser->incrementExpensiveFunctionCount();
.
El valor de retorno será false
si se ha alcanzado o excedido el límite de funciones costosas.
Parámetros nombrados
Las funciones del analizador no permiten el uso de parámetros nombrados de la manera en que lo hacen las plantillas y extensiones de marcado, pero a veces puede ser útil imitarlos. Los usuarios a menudo están acostumbrados a usar barras verticales ( |
) para separar argumentos, así que está bien poder hacerlo también en el contexto de las funciones de análisis. He aquí un ejemplo sencillo de cómo conseguirlo:
function ExampleExtensionRenderParserFunction( &$parser ) {
// Supón que el usuario invocó la función del analizador así:
// {{#myparserfunction: foo=bar | apple=orange | banana }}
$options = extractOptions( array_slice( func_get_args(), 1 ) );
// Ahora dispones de una matriz con este aspecto:
// [foo] => 'bar'
// [apple] => 'orange'
// [banana] => true
// Sigue escribiendo tu código...
}
/**
* Convierte una matriz de valores a la forma [0] => "nombre=valor"
* en una verdadera matriz asociativa de la forma [nombre] => valor
* Si no se proporciona =, se asume el valor true (verdadero) así: [nombre] => true
*
* @param array string $options
* @return array $results
*/
function extractOptions( array $options ) {
$results = [];
foreach ( $options as $option ) {
$pair = array_map( 'trim', explode( '=', $option, 2 ) );
if ( count( $pair ) === 2 ) {
$results[ $pair[0] ] = $pair[1];
}
if ( count( $pair ) === 1 ) {
$results[ $pair[0] ] = true;
}
}
return $results;
}
Véase también
Guías de uso general y guías relacionadas:
- Manual:Desarrollo de extensiones , o, para una información más general sobre extensiones, consulta Manual:Extensiones y Extensions FAQ .
- Manual:Extensiones de etiquetas
- Manual:Palabras mágicas
Código:
- Manual:Parser.php
- Manual:Hooks/ParserFirstCallInit
- Parser function hooks - una lista (incompleta) de funciones de análisis proporcionada por el núcleo y las extensiones
- La biblioteca PHP Parser Hooks, que proporciona una interfaz orientada a objetos para ganchos declarativos del analizador
- Manual:Extension data
Ejemplos:
- La extensión ParserFunctions es una conocida colección de funciones del analizador.
- Ayuda:Extensión:ParserFunctions
- Categoría:Extensiones de de funciones Parser