Jump to content

Fonctions d'analyse

From mediawiki.org
This page is a translated version of the page Manual:Parser functions and the translation is 100% complete.
MediaWiki extensions

Les fonctions d'analyse syntaxique (fonctions parseur), ajoutées dans MediaWiki 1.7, sont un type d'extension en relation directe avec l'analyseur syntaxique (parseur). L'expression "fonction parseur" ne doit pas être confondue avec Extension:ParserFunctions , qui est une collection de fonctions parseur simples (voir Aide:Extension:Fonctions d'analyse pour plus d'informations).

Description

Alors qu'une extension de balise est conçue pour prendre le texte non traité et retourner le code HTML résultant vers le navigateur, une fonction d'analyse syntaxique (parseur) peut « interagir » avec d'autres éléments wiki dans la page. Par exemple, le résultat d'une fonction d'analyse syntaxique peut être utilisé comme paramètre de modèle ou pour construire un lien.

La syntaxe typique pour une fonction parseur est :

{{ #functionname: param1 | param2 | param3 }}

Pour plus d'informations, voir la documentation de Parser::setFunctionHook ( $id, $callback, $flags = 0 ). Cette documentation dit que :

La fonction de rappel (callback) doit ressembler à :
function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }
ou avec SFH_OBJECT_ARGS:
function myParserFunction( $parser, $frame, $args ) { ... }

La première version de l'appel passe tous les arguments en tant que texte brut. Le second passe tous les arguments dans un tableau de PPNode , sauf le premier ($args[0]), qui est actuellement du texte bien que cela puisse changer à l'avenir. Ceci représente le wikicode non développé. Le paramètre $frame peut être utilisé pour étendre ces arguments selon les besoins. Ceci est utilisé habituellement pour le traitement conditionnel pour que le cas true soit évalué avec une fonction d'analyse de type if- ou switch-like. L'objet de trame peut également remonter l'arborescence du document pour obtenir les informations concernant l'appelant et possède des fonctions pour déterminer et gérer la profondeur des appels, la durée de validité, et indiquer si le résultat de la fonction d'analyse est volatile.

Créer une fonction parseur est légèrement plus compliqué que de créer une nouvelle balise car le nom de la fonction doit être un mot magique, un mot clé qui supporte les alias et la localisation.

Exemple simple

Ci-dessous, un exemple d'extension qui créée une fonction parseur.

L'enregistrement va respectivement dans extension.json et le code dans src/ExampleExtensionHooks.php :

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 {

   // Enregistrement et rendu des fonctions de rappel ( callbacks) avec l'analyseur syntaxique
   public static function onParserFirstCallInit( Parser $parser ) {
      // Créer une fonction d'accroche en associant le  mot magique <code>example</code> avec renderExample()
      $parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
   }

   // Rendu du résultat de {{#example:}}.
   public static function renderExample( Parser $parser, $param1 = '', $param2 = '', $param3 = '' ) {
      // Les paramètres d'entrée sont du texte wiki avec des modèles étendus.
      // La sortie devrait être également un wikitext.
      $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;
   }

}

Un autre fichier, ExampleExtension.i18n.php, dans le répertoire de votre extension (et non pas dans le dossier src/) doit contenir :

<?php
/**
 * @license GPL-2.0-or-later
 * @author Votre nom (YourUserName)
 */

$magicWords = [];

/** English
 * @author Votre nom (YourUserName)
 */
$magicWords['en'] = [
   'example' => [ 0, 'example' ],
];

Avec cette extension activée,

  • {{#example: hello | hi | hey}}

produit :

  • param1 vaut hello et param2 vaut hi et param3 vaut hey
Ce tableau de mots magiques n'est pas optionnel. S'il est omis, la fonction parseur ne sera simplement pas exécutée; la variable {{#example: hello | hi}} sera traitée comme si l'extension n'avait pas été installée. Si uniquement le tableau spécifique à la langue est initialisé et pas celui de magicWords, il peut se produire des erreurs d'internationalisation dûes aux traductions venant des autres extensions et en conflit avec les votres. Vous pouvez associer les mots magiques en ligne dans PHP plutôt que par l'intermédiaire d'un fichier i18n. Ceci est utile lorsque vous définissez les accroches dans LocalSettings.php
MediaWiki\MediaWikiServices::getInstance()->getContentLanguage()->mMagicExtensions['wikicodeToHtml'] = ['MAG_CUSTOM', 'custom'];

Dans LocalSettings.php

Les mots magiques, et les fonctions d'analyse qui leur sont associées, peuvent être définies entièrement dans 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];
}

Fonctions complexes

Pour les fonctions plus complexes, vous pouvez séparer les fonctions d'accroche dans ​un fichier _body.php ou un fichier .hooks.php et les définir en tant que fonctions statiques de classe. Ensuite, vous pouvez charger cette classe avec $wgAutoloadClasses et appeler les fonctions statiques dans les accroches; par exemple :

Mettre ceci dans votre fichier extension.json :

"Hooks": {
	"ParserFirstCallInit": "ExampleExtensionHooks::onParserFirstCallInit"
},
"AutoloadClasses": {
	"ExampleExtensionHooks": "src/ExampleExtensionHooks.php"
}

Puis mettre ceci dans votre fichier src/ExampleExtensionHooks.php :

class ExampleExtensionHooks {
      public static function onParserFirstCallInit( Parser $parser ) {
           $parser->setFunctionHook( 'example', [ self::class, 'renderExample' ] );
      }
}


Interface Parser

Contrôler l'analyse de la sortie

Pour que le texte wiki renvoyé par la fonction d'analyse soit complètement analysé (en incluant l'expansion des modèles), mettez l'option noparse à false lors du retour :

return [ $output, 'noparse' => false ];

Il semblerait que la valeur par défaut de noparse ait changé de false à true, tout du moins dans certaines situations, parfois aux alentours de la version 1.12.

Inversement, pour faire en sorte que le code HTML renvoyé par votre fonction parseur reste non analysé, plutôt que d'utiliser du wikicode, utilisez ceci :

return [ $output, 'noparse' => true, 'isHTML' => true ];

Nommage

Par défaut, MediaWiki ajoute un caractère dièse (signe dièse , #) au nom de chaque fonction d'analyse. Pour supprimer cet ajout (et obtenir une fonction d'analyse syntaxique sans préfixe #), incluez la constante SFH_NO_HASH dans l'argument flags pour setFunctionHook, comme décrit ci-dessous .

Lorsque l'on choisit un nom sans préfixe #, notez que la transclusion d'une page avec un nom commençant par le nom de cette fonction suivi par deux points n'est plus possible. En particulier, évitez les noms de fonction identiques à un nom d'espace de noms. Dans le cas où cette transclusion interwiki [1] est activée, évitez également les noms de fonctions identiques à un préfixe interwiki.

L'accroche setFunctionHook

Pour plus de détails sur l'interface dans l'analyseur syntaxique, consultez la documentation de setFunctionHook dans le fichier includes/Parser.php. Voici une copie (peut-être ancienne) de ces observations :

fonction setFunctionHook( $id, $callback, $flags = 0 )

Paramètres :

  • string $id - L'identificateur (ID) du mot magique
  • mixte $callback - La fonction de rappel (et l'objet) à utiliser
  • entier $flags - Optionnel. Valeurs :
  • constante SFH_NO_HASH (1) pour appeler la fonction sans le #.
  • SFH_OBJECT_ARGS (2) pour passer un objet PPFrame et un tableau d'arguments à la place d'une série d'arguments de fonction, voir [#Description|ci-dessus]].
  • 0 est la valeur par défaut (pas d'option).

Code retour : L'ancienne fonction de rappel pour ce nom, le cas échéant.

Créer une fonction, par exemple {{#sum:1|2|3}}. La fonction de rappel doit avoir la forme :

function myParserFunction( $parser, $arg1, $arg2, $arg3 ) { ... }

Le rappel peut renvoyer le résultat de la fonction sous la forme d'une chaîne de caractères, ou un tableau avec le texte dans l'élément 0 et un certain nombre de drapeaux pour les autres éléments. Les noms des drapeaux sont spécifiés dans les clés. Les drapeaux valides sont :

Nom Type Valeur par défaut Description
found booléen true true si le texte renvoyé est valide et que le traitement du modèle doit s'arrêter.
text ? ? texte à renvoyer par la fonction. Si isChildObj ou isLocalObj sont fournis, alors ceci doit être un noeud du DOM.
noparse booléen true true si le texte ne doit pas être pré-traité comme une arborescence DOM, par exemple si les balises HTML dangereuses ne doivent pas être supprimées, etc.
isHTML booléen ? true si le texte renvoyé est au format HTML et doit être protégé le contre la transformation en wikicode. Mais voir la discussion
nowiki booléen habituellement false true si le balisage wiki dans la valeur de retour (textuelle) doit être échappé.
isChildObj booléen ? true si le texte est un noeud du DOM devant être développé dans une frame fille.
isLocalObj booléen ? true si le texte est un nœud du DOM devant être développé dans la frame actuelle. La valeur par défaut dépend des autres valeurs et des résultats.
preprocessFlags ? false options PPFrame facultatives à utiliser lors de l'analyse du texte renvoyé. Ceci ne s'applique que si noparse vaut false.
title ? false objet Title qui a fourni le texte.
forceRawInterwiki booléen ? true si la transclusion interwiki doit être forcée en mode à plat (raw) et non pas comme rendu.

Fonctions d'analyse coûteuses

Certaines fonctions de l'analyseur représentent une utilisation importante des ressources du wiki et doivent être marquées comme étant coûteuses. Le nombre de fonctions d'analyse coûteuses sur une page donnée est limité par la valeur de $wgExpensiveParserFunctionLimit . Ce qui est coûteux est laissé à la fonction elle-même, mais généralement, tout ce qui est susceptible de causer un retard qui va au-delà du simple traitement des données doit être pris en compte. Cela inclut des opérations comme la lecture ou l'écriture dans les bases de données, le lancement synchrone d'un script du shell ou la manipulation de fichiers. D'autre part, toutes les fonctions ainsi identifiées ne devraient pas nécessairement être étiquetées. Semantic MediaWiki par exemple, ne marque qu'une portion de ses lectures en base de données comme coûteuses. Cela est dû au fait que sur certaines pages à forte intensité de données, on pourrait facilement dépasser les limites normales des fonctions d'analyse coûteuses. Pour ces cas, la possibilité de réduire les performances de manière perceptible alors que la fonction n'a pas été marquée comme étant coûteuse est liée au bénéfice d'avoir la fonctionnalité offerte par SMW.

Pour indiquer dans le corps d'une fonction que celle-ci est coûteuse, utiliser $result = $parser->incrementExpensiveFunctionCount();. Le code retour sera false si les limites de la fonction consommatrice ont été atteintes ou dépassées.

Paramètres nommés

Les fonctions d'analyse syntaxique ne prennent pas en charge les paramètres nommés comme le font les modèles et les balises d'extensions, mais il est parfois utile de les imiter. Les utilisateurs sont souvent habitués à utiliser des barres verticales ( | ) pour séparer les arguments, il est donc aussi intéressant de pouvoir le faire dans le contexte de la fonction de l'analyseur syntaxique. Voici un exemple simple pour illustrer ceci :

function ExampleExtensionRenderParserFunction( &$parser ) {
	// Supposons que l'utilisateur appelle la fonction d'analyse ainsi :
	// {{#myparserfunction: foo=bar | apple=orange | banana }}

	$options = extractOptions( array_slice( func_get_args(), 1 ) );

	// Vous disposez alors d'un tableau qui ressemble à :
	// [foo] => 'bar'
	// [apple] => 'orange'
	// [banana] => true
	// continuez la suite de votre code...
}

/**
 * Convertit un tableau de valeurs sous la forme [0] => ''name=value''
 * dans un tableau associatif de réels sous forme => valeur
 * S'il n'y a pas de signe = , alors la valeur assignée est true ainsi : [name] => 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;
}

Voir aussi

Généralités et guides associés :

Code :

Exemples :