DAT-2845 add infobox parser api

This commit is contained in:
Adam Robak 2015-05-29 15:04:04 +02:00
parent 91b21f5b73
commit 7978ed0b96
5 changed files with 146 additions and 23 deletions

View file

@ -45,6 +45,7 @@ $wgAutoloadClasses[ 'Wikia\PortableInfobox\Helpers\SimpleXmlUtil' ] = $dir . 'se
// controller classes
$wgAutoloadClasses[ 'PortableInfoboxParserTagController' ] = $dir . 'controllers/PortableInfoboxParserTagController.class.php';
$wgAutoloadClasses[ 'ApiPortableInfobox' ] = $dir . 'controllers/ApiPortableInfobox.class.php';
$wgAutoloadClasses[ 'PortableInfoboxHooks' ] = $dir . 'PortableInfoboxHooks.class.php';
// hooks
@ -54,3 +55,6 @@ $wgHooks['ParserAfterTidy'][] = 'PortableInfoboxParserTagController::replaceInfo
// i18n mapping
$wgExtensionMessagesFiles[ 'PortableInfobox' ] = $dir . 'PortableInfobox.i18n.php';
//MW API
$wgAPIModules['infobox'] = 'ApiPortableInfobox';

View file

@ -0,0 +1,79 @@
<?php
class ApiPortableInfobox extends ApiBase {
public function __construct( $main, $action ) {
parent:: __construct( $main, $action );
}
public function execute() {
$text = $this->getParameter( "text" );
$title = $this->getParameter( "title" );
$arguments = $this->getFrameArguments();
if ( $arguments === null ) {
$this->getResult()->setWarning( "Arguments json format incorect or empty" );
}
$parser = new Parser();
$parser->startExternalParse( Title::newFromText( $title ), new ParserOptions(), 'text', true );
$frame = $parser->getPreprocessor()->newCustomFrame( $arguments );
try {
$output = PortableInfoboxParserTagController::getInstance()->render( $text, $parser, $frame );
$this->getResult()->addValue( null, $this->getModuleName(), [ 'text' => [ '*' => $output ] ] );
} catch ( \Wikia\PortableInfobox\Parser\Nodes\UnimplementedNodeException $e ) {
$this->dieUsage( wfMessage( 'unimplemented-infobox-tag', [ $e->getMessage() ] )->escaped(), "notimplemented" );
} catch ( \Wikia\PortableInfobox\Parser\XmlMarkupParseErrorException $e ) {
$this->dieUsage( wfMessage( 'xml-parse-error' )->text(), "badxml" );
}
}
public function getAllowedParams() {
return array(
'text' => array(
ApiBase :: PARAM_TYPE => 'string'
),
'title' => array(
ApiBase :: PARAM_TYPE => 'string'
),
'args' => array(
ApiBase :: PARAM_TYPE => 'string'
)
);
}
public function getParamDescription() {
return array(
'text' => 'Infobox to parse (xml string)',
'title' => 'Title of page the text belongs to',
'args' => 'Variable list to use during parse (json format)',
);
}
public function getDescription() {
return array( 'This module provides infobox parser' );
}
/**
* Examples
*/
public function getExamples() {
return array(
'api.php?action=infobox',
'api.php?action=infobox&text=<infobox><data><default>{{PAGENAME}}</default></data></infobox>&title=Test',
'api.php?action=infobox&text=<infobox><data source="test" /></infobox>&args={"test": "test value"}',
);
}
public function getVersion() {
return __CLASS__ . '$Id$';
}
/**
* @return mixed
*/
protected function getFrameArguments() {
$arguments = $this->getParameter( "args" );
return isset( $arguments ) ? json_decode( $arguments, true ) : false;
}
}

View file

@ -42,6 +42,31 @@ class PortableInfoboxParserTagController extends WikiaController {
return true;
}
/**
* @param $markup
* @param Parser $parser
* @param PPFrame $frame
* @return array|string
* @throws UnimplementedNodeException when node used in markup does not exists
* @throws XmlMarkupParseErrorException xml not well formatted
*/
public function render( $markup, Parser $parser, PPFrame $frame, $params = null ) {
$infoboxParser = new Wikia\PortableInfobox\Parser\XmlParser(
array_merge( $frame->getNamedArguments(), $frame->getArguments() ) );
$infoboxParser->setExternalParser( new Wikia\PortableInfobox\Parser\MediaWikiParserService( $parser, $frame ) );
//get params if not overridden
if ( !isset( $params ) ) {
$params = $infoboxParser->getInfoboxParams( $markup );
}
$data = $infoboxParser->getDataFromXmlString( $markup );
//save for later api usage
$this->saveToParserOutput( $parser->getOutput(), $data );
$theme = $this->getThemeWithDefault( $params, $frame );
return ( new PortableInfoboxRenderService() )->renderInfobox( $data, $theme );
}
/**
* @desc Renders Infobox
*
@ -56,23 +81,14 @@ class PortableInfoboxParserTagController extends WikiaController {
$this->markerNumber++;
$markup = '<' . self::PARSER_TAG_NAME . '>' . $text . '</' . self::PARSER_TAG_NAME . '>';
$infoboxParser = new Wikia\PortableInfobox\Parser\XmlParser( $frame->getNamedArguments() );
$infoboxParser->setExternalParser( ( new Wikia\PortableInfobox\Parser\MediaWikiParserService( $parser, $frame ) ) );
try {
$data = $infoboxParser->getDataFromXmlString( $markup );
$renderedValue = $this->render( $markup, $parser, $frame, $params );
} catch ( \Wikia\PortableInfobox\Parser\Nodes\UnimplementedNodeException $e ) {
return $this->handleError( wfMessage( 'unimplemented-infobox-tag', [ $e->getMessage() ] )->escaped() );
} catch ( \Wikia\PortableInfobox\Parser\XmlMarkupParseErrorException $e ) {
return $this->handleError( wfMessage( 'xml-parse-error' ) );
}
//save for later api usage
$this->saveToParserOutput( $parser->getOutput(), $data );
$renderer = new PortableInfoboxRenderService();
$theme = $this->getThemeWithDefault( $params, $frame );
$renderedValue = $renderer->renderInfobox( $data, $theme );
if ( $wgArticleAsJson ) {
// (wgArticleAsJson == true) it means that we need to encode output for use inside JSON
$renderedValue = trim( json_encode( $renderedValue ), '"' );

View file

@ -55,25 +55,22 @@ class XmlParser {
public function getDataFromXmlString( $xmlString ) {
wfProfileIn( __METHOD__ );
$global_libxml_setting = libxml_use_internal_errors();
libxml_use_internal_errors( true );
$xml = simplexml_load_string( $xmlString );
$errors = libxml_get_errors();
libxml_use_internal_errors( $global_libxml_setting );
if ( $xml === false ) {
foreach ( $errors as $xmlerror ) {
$this->logXmlParseError( $xmlerror->level, $xmlerror->code, trim( $xmlerror->message ) );
}
libxml_clear_errors();
throw new XmlMarkupParseErrorException();
}
$xml = $this->parseXmlString( $xmlString );
$data = $this->getDataFromNodes( $xml );
wfProfileOut( __METHOD__ );
return $data;
}
public function getInfoboxParams( $xmlString ) {
$xml = $this->parseXmlString( $xmlString );
$result = [];
foreach ( $xml->attributes() as $k => $v ) {
$result[$k] = (string) $v;
}
return $result;
}
protected function logXmlParseError( $level, $code, $message ) {
\Wikia\Logger\WikiaLogger::instance()->info( "PortableInfobox XML Parser problem", [
"level" => $level,
@ -106,6 +103,28 @@ class XmlParser {
return new Nodes\NodeUnimplemented( $xmlNode, $this->infoboxData );
}
/**
* @param $xmlString
* @return \SimpleXMLElement
* @throws XmlMarkupParseErrorException
*/
protected function parseXmlString( $xmlString ) {
$global_libxml_setting = libxml_use_internal_errors();
libxml_use_internal_errors( true );
$xml = simplexml_load_string( $xmlString );
$errors = libxml_get_errors();
libxml_use_internal_errors( $global_libxml_setting );
if ( $xml === false ) {
foreach ( $errors as $xmlerror ) {
$this->logXmlParseError( $xmlerror->level, $xmlerror->code, trim( $xmlerror->message ) );
}
libxml_clear_errors();
throw new XmlMarkupParseErrorException();
}
return $xml;
}
}
class XmlMarkupParseErrorException extends \Exception {

View file

@ -2,6 +2,11 @@
class PortableInfoboxParserTagControllerTest extends WikiaBaseTest {
/** @var PortableInfoboxParserTagController */
protected $parser;
/** @var Parser */
protected $controller;
protected function setUp() {
$this->setupFile = dirname( __FILE__ ) . '/../PortableInfobox.setup.php';
parent::setUp();