Jeroen De Dauw has submitted this change and it was merged.
Change subject: Refactor SMWParserExtensions, convert static into an
instantiable class
......................................................................
Refactor SMWParserExtensions, convert static into an instantiable class
This commit does not contain any processing or logic changes.
+ Rename SMWParserExtensions class to SMW\ParserTextProcessor
(because the class is actually doing text processing)
+ Remove hook caller from class and move into the SMWHooks class
+ Eliminate static SMWParserData caller
+ Convert all static methods
+ Split parse into smaller piece for better modularity
+ Add test
Change-Id: I66b812e0276820fa58dbbfbc632236ea6f8ba6d5
---
M SemanticMediaWiki.hooks.php
M includes/ParserData.php
A includes/ParserTextProcessor.php
D includes/SMW_ParserExtensions.php
M includes/Setup.php
M tests/phpunit/includes/HooksTest.php
A tests/phpunit/includes/ParserTextProcessorTest.php
7 files changed, 860 insertions(+), 230 deletions(-)
Approvals:
Jeroen De Dauw: Looks good to me, approved
jenkins-bot: Verified
diff --git a/SemanticMediaWiki.hooks.php b/SemanticMediaWiki.hooks.php
index 8dc4fd6..be0f613 100644
--- a/SemanticMediaWiki.hooks.php
+++ b/SemanticMediaWiki.hooks.php
@@ -240,6 +240,7 @@
'Hooks',
'DataValueFactory',
'Settings',
+ 'ParserTextProcessor',
'api/ApiSMWInfo',
@@ -610,4 +611,40 @@
$parserData->addSpecialProperties( $wikiPage, $revision, $user
);
return true;
}
+
+ /**
+ * Hook: InternalParseBeforeLinks is used to process the expanded wiki
+ * code after <nowiki>, HTML-comments, and templates have been treated.
+ *
+ * This method will be called before an article is displayed or
previewed.
+ * For display and preview we strip out the semantic properties and
append them
+ * at the end of the article.
+ *
+ * @note MW 1.20+ see InternalParseBeforeSanitize
+ *
+ * @see Parser
+ * @see
http://http://www.mediawiki.org/wiki/Manual:Hooks/InternalParseBeforeLinks
+ *
+ * @since 1.10
+ *
+ * @param Parser $parser
+ * @param string $text
+ *
+ * @return true
+ */
+ public static function onInternalParseBeforeLinks( Parser &$parser,
&$text ) {
+
+ $settings = SMW\Settings::newFromArray( array(
+ 'smwgNamespacesWithSemanticLinks' =>
$GLOBALS['smwgNamespacesWithSemanticLinks'],
+ 'smwgLinksInValues' => $GLOBALS['smwgLinksInValues'],
+ 'smwgInlineErrors' => $GLOBALS['smwgInlineErrors']
+ ) );
+
+ $processor = new SMW\ParserTextProcessor(
+ new SMW\ParserData( $parser->getTitle(),
$parser->getOutput() ),
+ $settings
+ );
+ $processor->parse( $text );
+ return true;
+ }
}
diff --git a/includes/ParserData.php b/includes/ParserData.php
index 4f3d3f7..d35d307 100644
--- a/includes/ParserData.php
+++ b/includes/ParserData.php
@@ -166,18 +166,6 @@
protected $updateJobs = true;
/**
- * Allows explicitly to switch storage method, MW 1.21 comes with a new
- * method setExtensionData/getExtensionData in how the ParserOutput
- * stores arbitrary data
- *
- * MW 1.21 unit tests are passed but real page content did vanished
- * therefore for now disable this feature for MW 1.21 as well
- *
- * @var $extensionData
- */
- protected $useExtensionData = false;
-
- /**
* Constructor
*
* @since 1.9
@@ -302,13 +290,15 @@
}
/**
- * Init semanticData container either from the ParserOutput object
- * or if not available use the subject
+ * Initializes the semantic data container either from the ParserOutput
or
+ * if not available a new container is being created
+ *
+ * @note MW 1.21+ use getExtensionData()
*
* @since 1.9
*/
protected function setData() {
- if ( method_exists( $this->parserOutput, 'getExtensionData' )
&& $this->useExtensionData ) {
+ if ( method_exists( $this->parserOutput, 'getExtensionData' ) )
{
$this->semanticData =
$this->parserOutput->getExtensionData( 'smwdata' );
} elseif ( isset( $this->parserOutput->mSMWData ) ) {
$this->semanticData = $this->parserOutput->mSMWData;
@@ -323,6 +313,8 @@
/**
* Update ParserOutput with processed semantic data
*
+ * @note MW 1.21+ use setExtensionData()
+ *
* @since 1.9
*
* @throws MWException
@@ -332,7 +324,7 @@
throw new MWException( 'The semantic data container is
not available' );
}
- if ( method_exists( $this->parserOutput, 'setExtensionData' )
&& $this->useExtensionData ) {
+ if ( method_exists( $this->parserOutput, 'setExtensionData' ) )
{
$this->parserOutput->setExtensionData( 'smwdata',
$this->semanticData );
} else {
$this->parserOutput->mSMWData = $this->semanticData;
diff --git a/includes/ParserTextProcessor.php b/includes/ParserTextProcessor.php
new file mode 100644
index 0000000..771dab3
--- /dev/null
+++ b/includes/ParserTextProcessor.php
@@ -0,0 +1,408 @@
+<?php
+
+namespace SMW;
+
+use MagicWord;
+use Title;
+use Html;
+use SpecialPage;
+
+use SMWOutputs;
+use SMWDIWikiPage;
+use SMWDIProperty;
+
+/**
+ * Class collects all functions for wiki text parsing / processing that are
+ * relevant for SMW
+ *
+ * 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
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SMW
+ * @ingroup Parser
+ *
+ * @author Markus Krötzsch
+ * @author Denny Vrandecic
+ * @author mwjames
+ */
+
+/**
+ * This class is contains all functions necessary for parsing wiki text before
+ * it is displayed or previewed while identifying SMW related
+ * annotations.
+ *
+ * @ingroup SMW
+ * @ingroup Parser
+ */
+class ParserTextProcessor {
+
+ /**
+ * Represents a Settings object
+ * @var Settings
+ */
+ protected $settings;
+
+ /**
+ * Represents a IParserData object
+ * @var IParserData
+ */
+ protected $parserData;
+
+ /**
+ * Represents $smwgNamespacesWithSemanticLinks status
+ * @var boolean
+ */
+ protected $isEnabled;
+
+ /**
+ * Internal state for switching SMW link annotations off/on during
parsing
+ * ([[SMW::on]] and [[SMW:off]])
+ * @var boolean
+ */
+ protected $isAnnotation = true;
+
+ /**
+ * @par Example:
+ * @code
+ * $settings = Settings::newFromArray( array(
+ * 'smwgNamespacesWithSemanticLinks' =>
$GLOBALS['smwgNamespacesWithSemanticLinks'],
+ * 'smwgLinksInValues' => $GLOBALS['smwgLinksInValues'],
+ * 'smwgInlineErrors' => $GLOBALS['smwgInlineErrors']
+ * ) );
+ *
+ * $parserData = new ParserData( $title, $parserOutput );
+ *
+ * new ParserTextProcessor( $parserData, $settings );
+ * @endcode
+ *
+ * @see SMWHooks::onInternalParseBeforeLinks
+ *
+ * @since 1.9
+ *
+ * @param IParserData $parserData
+ * @param Settings $settings
+ */
+ public function __construct( IParserData $parserData, Settings
$settings ) {
+ $this->parserData = $parserData;
+ $this->settings = $settings;
+ }
+
+ /**
+ * Parsing text before an article is displayed or previewed, strip out
+ * semantic properties and add them to the ParserOutput object
+ *
+ * @since 1.9
+ *
+ * @param string &$text
+ */
+ public function parse( &$text ) {
+ $title = $this->parserData->getTitle();
+
+ // Strip magic words from text body
+ $this->stripMagicWords( $text );
+
+ // Attest if semantic data should be processed
+ $this->isSemanticEnabled( $title );
+
+ // Process redirects
+ $this->setRedirect( $title );
+
+ // Parse links to extract semantic properties
+ $linksInValues = $this->settings->get( 'smwgLinksInValues' );
+ $text = preg_replace_callback(
+ $this->getRegexpPattern( $linksInValues ),
+ $linksInValues ? 'self::process' : 'self::preprocess',
+ $text
+ );
+
+ // Add RDF link to the HTML header.
+ $this->parserData->getOutput()->addHeadItem( "\t\t" .
$this->getRDFUrl( $title ) . "\n" );
+
+ // Update ParserOutput
+ $this->parserData->getOutput()->addModules( $this->getModules()
);
+ $this->parserData->updateOutput();
+ SMWOutputs::commitToParserOutput(
$this->parserData->getOutput() );
+ }
+
+ /**
+ * Attest if semantic data should be processed and displayed
+ * for a page in the given namespace. (have to parse them in
+ * any case, in order to clean the wiki source for further processing)
+ *
+ * @since 1.9
+ *
+ * @param Title $title
+ *
+ * @return boolean
+ */
+ protected function isSemanticEnabled( Title $title ) {
+ $namespaces = $this->settings->get(
'smwgNamespacesWithSemanticLinks' );
+ $this->isEnabled = !empty( $namespaces[$title->getNamespace()]
);
+ }
+
+ /**
+ * Returns required resource modules
+ *
+ * @since 1.9
+ *
+ * @return array
+ */
+ protected function getModules() {
+ return array(
+ 'ext.smw.style',
+ 'ext.smw.tooltips'
+ );
+ }
+
+ /**
+ * Process and add '_REDI' property in case the current Title is a
redirect
+ *
+ * @since 1.9
+ *
+ * @param Title $title
+ */
+ protected function setRedirect( Title $title ) {
+ if ( $this->isEnabled && $title->isRedirect() ) {
+ $this->parserData->getData()->addPropertyObjectValue(
+ new SMWDIProperty( '_REDI' ),
+ SMWDIWikiPage::newFromTitle( $title, '__red' )
+ );
+ }
+ }
+
+ /**
+ * $smwgLinksInValues (default = false) determines which regexp pattern
+ * is returned, either a more complex (lib PCRE may cause segfaults if
text
+ * is long) or a simpler (no segfaults found for those, but no links
+ * in values) pattern.
+ *
+ * If enabled (SMW accepts inputs like [[property::Some [[link]] in
value]]),
+ * this may lead to PHP crashes (!) when very long texts are
+ * used as values. This is due to limitations in the library PCRE that
+ * PHP uses for pattern matching.
+ *
+ * @since 1.9
+ *
+ * @param boolean $linksInValues
+ *
+ * @return string
+ */
+ protected function getRegexpPattern( $linksInValues ) {
+ if ( $linksInValues ) {
+ return '/\[\[ # Beginning of the link
+ (?:([^:][^]]*):[=:])+ # Property name (or a
list of those)
+ ( # After that:
+ (?:[^|\[\]] # either normal text
(without |, [ or ])
+ |\[\[[^]]*\]\] # or a [[link]]
+ |\[[^]]*\] # or an [external link]
+ )*) # all this zero or more
times
+ (?:\|([^]]*))? # Display text (like
"text" in [[link|text]]), optional
+ \]\] # End of link
+ /xu';
+ } else {
+ return '/\[\[ # Beginning of the link
+ (?:([^:][^]]*):[=:])+ # Property name (or a
list of those)
+ ([^\[\]]*) # content: anything but
[, |, ]
+ \]\] # End of link
+ /xu';
+ }
+ }
+
+ /**
+ * Returns ExportRDF URL
+ *
+ * @since 1.9
+ *
+ * @param Title $title
+ *
+ * @return string
+ */
+ protected function getRDFUrl( Title $title ) {
+ return Html::element( 'link', array(
+ 'type' => 'application/rdf+xml',
+ 'title' => $title->getPrefixedText(),
+ 'href' => SpecialPage::getTitleFor( 'ExportRDF',
$title->getPrefixedText() )->getLocalUrl( 'xmlmime=rdf' )
+ )
+ );
+ }
+
+ /**
+ * A method that precedes the process() callback, it takes care of
separating
+ * value and caption (instead of leaving this to a more complex regexp).
+ *
+ * @since 1.9
+ *
+ * @param array $semanticLink expects (linktext, properties,
value|caption)
+ *
+ * @return string
+ */
+ protected function preprocess( array $semanticLink ) {
+ $value = '';
+ $caption = false;
+
+ if ( array_key_exists( 2, $semanticLink ) ) {
+ $parts = explode( '|', $semanticLink[2] );
+ if ( array_key_exists( 0, $parts ) ) {
+ $value = $parts[0];
+ }
+ if ( array_key_exists( 1, $parts ) ) {
+ $caption = $parts[1];
+ }
+ }
+
+ if ( $caption !== false ) {
+ return $this->process( array( $semanticLink[0],
$semanticLink[1], $value, $caption ) );
+ } else {
+ return $this->process( array( $semanticLink[0],
$semanticLink[1], $value ) );
+ }
+ }
+
+ /**
+ * This callback function strips out the semantic attributes from a wiki
+ * link.
+ *
+ * @since 1.9
+ *
+ * @param array $semanticLink expects (linktext, properties,
value|caption)
+ *
+ * @return string
+ */
+ protected function process( array $semanticLink ) {
+ wfProfileIn( __METHOD__ );
+
+ if ( array_key_exists( 1, $semanticLink ) ) {
+ $property = $semanticLink[1];
+ } else {
+ $property = '';
+ }
+
+ if ( array_key_exists( 2, $semanticLink ) ) {
+ $value = $semanticLink[2];
+ } else {
+ $value = '';
+ }
+
+ if ( $value === '' ) { // silently ignore empty values
+ wfProfileOut( __METHOD__ );
+ return '';
+ }
+
+ if ( $property == 'SMW' ) {
+ switch ( $value ) {
+ case 'on':
+ $this->isAnnotation = true;
+ break;
+ case 'off':
+ $this->isAnnotation = false;
+ break;
+ }
+ wfProfileOut( __METHOD__ );
+ return '';
+ }
+
+ if ( array_key_exists( 3, $semanticLink ) ) {
+ $valueCaption = $semanticLink[3];
+ } else {
+ $valueCaption = false;
+ }
+
+ // Extract annotations and create tooltip.
+ $properties = preg_split( '/:[=:]/u', $property );
+
+ wfProfileOut( __METHOD__ );
+ return $this->addPropertyValue( $properties, $value,
$valueCaption );
+ }
+
+ /**
+ * Adds property values to the ParserOutput instance
+ *
+ * @since 1.9
+ *
+ * @param array $properties
+ *
+ * @return string
+ */
+ protected function addPropertyValue( array $properties, $value,
$valueCaption ) {
+ wfProfileIn( __METHOD__ );
+
+ $subject = $this->parserData->getData()->getSubject();
+
+ // Add properties to the semantic container
+ foreach ( $properties as $property ) {
+ $dataValue = DataValueFactory::newPropertyValue(
+ $property,
+ $value,
+ $valueCaption,
+ $subject
+ );
+
+ if ( $this->isEnabled && $this->isAnnotation ) {
+ $this->parserData->addPropertyValue( $dataValue
);
+ }
+ }
+
+ // Return the text representation
+ $result = $dataValue->getShortWikitext( true );
+
+ // If necessary add an error text
+ if ( ( $this->settings->get( 'smwgInlineErrors' ) &&
+ $this->isEnabled && $this->isAnnotation ) &&
+ ( !$dataValue->isValid() ) ) {
+ $result .= $dataValue->getErrorText();
+ }
+
+ wfProfileOut( __METHOD__ );
+ return $result;
+ }
+
+ /**
+ * Remove relevant SMW magic words from the given text and return
+ * an array of the names of all discovered magic words. Moreover,
+ * store this array in the current parser output, using the variable
+ * mSMWMagicWords and for MW 1.21+ 'smwmagicwords'
+ *
+ * @since 1.9
+ *
+ * @param &$text
+ *
+ * @return array
+ */
+ protected function stripMagicWords( &$text ) {
+ $words = array();
+ $mw = MagicWord::get( 'SMW_NOFACTBOX' );
+
+ if ( $mw->matchAndRemove( $text ) ) {
+ $words[] = 'SMW_NOFACTBOX';
+ }
+
+ $mw = MagicWord::get( 'SMW_SHOWFACTBOX' );
+
+ if ( $mw->matchAndRemove( $text ) ) {
+ $words[] = 'SMW_SHOWFACTBOX';
+ }
+
+ // Store values into the mSMWMagicWords property
+ if ( method_exists( $this->parserData->getOutput(),
'setExtensionData' ) ) {
+ $this->parserData->getOutput()->setExtensionData(
'smwmagicwords', $words );
+ } else {
+ $this->parserData->getOutput()->mSMWMagicWords = $words;
+ }
+
+ return $words;
+ }
+}
diff --git a/includes/SMW_ParserExtensions.php
b/includes/SMW_ParserExtensions.php
deleted file mode 100644
index 989ce6b..0000000
--- a/includes/SMW_ParserExtensions.php
+++ /dev/null
@@ -1,212 +0,0 @@
-<?php
-/**
- * Static class to collect all functions related to parsing wiki text in SMW.
- * It includes all parser function declarations and hooks.
- *
- * @file SMW_ParserExtensions.php
- * @ingroup SMW
- *
- * @author Markus Krötzsch
- * @author Denny Vrandecic
- */
-class SMWParserExtensions {
-
- /// Temporarily store parser as it cannot be passed to call-back
functions otherwise.
- protected static $mTempParser;
- /// Internal state for switching off/on SMW link annotations during
parsing
- protected static $mTempStoreAnnotations;
-
- /**
- * This method will be called before an article is displayed or
previewed.
- * For display and preview we strip out the semantic properties and
append them
- * at the end of the article.
- *
- * @param Parser $parser
- * @param string $text
- *
- * @return true
- */
- static public function onInternalParseBeforeLinks( Parser &$parser,
&$text ) {
- global $smwgStoreAnnotations, $smwgLinksInValues;
-
- SMWParserExtensions::stripMagicWords( $text, $parser );
-
- // Store the results if enabled (we have to parse them in any
case,
- // in order to clean the wiki source for further processing).
- $smwgStoreAnnotations = smwfIsSemanticsProcessed(
$parser->getTitle()->getNamespace() );
- SMWParserExtensions::$mTempStoreAnnotations = true; // used for
[[SMW::on]] and [[SMW:off]]
-
- // Process redirects, if any (it seems that there is indeed no
more direct way of getting this info from MW)
- if ( $smwgStoreAnnotations ) {
- $rt = Title::newFromRedirect( $text );
-
- if ( !is_null( $rt ) ) {
- $p = new SMWDIProperty( '_REDI' );
- $di = SMWDIWikiPage::newFromTitle( $rt, '__red'
);
- SMWParseData::getSMWData( $parser
)->addPropertyObjectValue( $p, $di );
- }
- }
-
- // only used in subsequent callbacks, forgotten afterwards
- SMWParserExtensions::$mTempParser = $parser;
-
- // In the regexp matches below, leading ':' escapes the markup,
as known for Categories.
- // Parse links to extract semantic properties.
- if ( $smwgLinksInValues ) { // More complex regexp -- lib PCRE
may cause segfaults if text is long :-(
- $semanticLinkPattern = '/\[\[ #
Beginning of the link
- (?:([^:][^]]*):[=:])+ #
Property name (or a list of those)
- ( # After
that:
- (?:[^|\[\]] #
either normal text (without |, [ or ])
- |\[\[[^]]*\]\] # or a
[[link]]
- |\[[^]]*\] # or an
[external link]
- )*) # all
this zero or more times
- (?:\|([^]]*))? # Display
text (like "text" in [[link|text]]), optional
- \]\] # End of
link
- /xu';
- $text = preg_replace_callback( $semanticLinkPattern,
array( 'SMWParserExtensions', 'parsePropertiesCallback' ), $text );
- } else { // Simpler regexps -- no segfaults found for those,
but no links in values.
- $semanticLinkPattern = '/\[\[ #
Beginning of the link
- (?:([^:][^]]*):[=:])+ #
Property name (or a list of those)
- ([^\[\]]*) #
content: anything but [, |, ]
- \]\] # End of
link
- /xu';
- $text = preg_replace_callback( $semanticLinkPattern,
array( 'SMWParserExtensions', 'simpleParsePropertiesCallback' ), $text );
- }
-
- // Add link to RDF to HTML header.
- // TODO: do escaping via Html or Xml class.
- SMWOutputs::requireHeadItem(
- 'smw_rdf', '<link rel="alternate"
type="application/rdf+xml" title="' .
- htmlspecialchars(
$parser->getTitle()->getPrefixedText() ) . '" href="' .
- htmlspecialchars(
- SpecialPage::getTitleFor( 'ExportRDF',
$parser->getTitle()->getPrefixedText() )->getLocalUrl( 'xmlmime=rdf' )
- ) . "\" />"
- );
-
- SMWOutputs::commitToParser( $parser );
- return true; // always return true, in order not to stop MW's
hook processing!
- }
-
- /**
- * This callback function strips out the semantic attributes from a wiki
- * link. Expected parameter: array(linktext, properties, value|caption)
- * This function is a preprocessing for smwfParsePropertiesCallback, and
- * takes care of separating value and caption (instead of leaving this
to
- * a more complex regexp).
- */
- static public function simpleParsePropertiesCallback( $semanticLink ) {
- $value = '';
- $caption = false;
-
- if ( array_key_exists( 2, $semanticLink ) ) {
- $parts = explode( '|', $semanticLink[2] );
- if ( array_key_exists( 0, $parts ) ) {
- $value = $parts[0];
- }
- if ( array_key_exists( 1, $parts ) ) {
- $caption = $parts[1];
- }
- }
-
- if ( $caption !== false ) {
- return SMWParserExtensions::parsePropertiesCallback(
array( $semanticLink[0], $semanticLink[1], $value, $caption ) );
- } else {
- return SMWParserExtensions::parsePropertiesCallback(
array( $semanticLink[0], $semanticLink[1], $value ) );
- }
- }
-
- /**
- * This callback function strips out the semantic attributes from a wiki
- * link. Expected parameter: array(linktext, properties, value, caption)
- */
- static public function parsePropertiesCallback( $semanticLink ) {
- global $smwgInlineErrors, $smwgStoreAnnotations;
-
- wfProfileIn( 'smwfParsePropertiesCallback (SMW)' );
-
- if ( array_key_exists( 1, $semanticLink ) ) {
- $property = $semanticLink[1];
- } else {
- $property = '';
- }
-
- if ( array_key_exists( 2, $semanticLink ) ) {
- $value = $semanticLink[2];
- } else {
- $value = '';
- }
-
- if ( $value === '' ) { // silently ignore empty values
- wfProfileOut( 'smwfParsePropertiesCallback (SMW)' );
- return '';
- }
-
- if ( $property == 'SMW' ) {
- switch ( $value ) {
- case 'on':
-
SMWParserExtensions::$mTempStoreAnnotations = true;
- break;
- case 'off':
-
SMWParserExtensions::$mTempStoreAnnotations = false;
- break;
- }
- wfProfileOut( 'smwfParsePropertiesCallback (SMW)' );
- return '';
- }
-
- if ( array_key_exists( 3, $semanticLink ) ) {
- $valueCaption = $semanticLink[3];
- } else {
- $valueCaption = false;
- }
-
- // Extract annotations and create tooltip.
- $properties = preg_split( '/:[=:]/u', $property );
-
- foreach ( $properties as $singleprop ) {
- $dv = SMWParseData::addProperty( $singleprop, $value,
$valueCaption, SMWParserExtensions::$mTempParser, $smwgStoreAnnotations &&
SMWParserExtensions::$mTempStoreAnnotations );
- }
-
- $result = $dv->getShortWikitext( true );
-
- if ( ( $smwgInlineErrors && $smwgStoreAnnotations &&
SMWParserExtensions::$mTempStoreAnnotations ) && ( !$dv->isValid() ) ) {
- $result .= $dv->getErrorText();
- }
-
- wfProfileOut( 'smwfParsePropertiesCallback (SMW)' );
-
- return $result;
- }
-
- /**
- * Remove relevant SMW magic words from the given text and return
- * an array of the names of all discovered magic words. Moreover,
- * store this array in the current parser output, using the variable
- * mSMWMagicWords.
- *
- * @note moved from SMWParseData::stripMagicWords as it is only used
- * in here
- *
- * @since 1.9
- */
- static public function stripMagicWords( &$text, Parser $parser ) {
- $words = array();
- $mw = MagicWord::get( 'SMW_NOFACTBOX' );
-
- if ( $mw->matchAndRemove( $text ) ) {
- $words[] = 'SMW_NOFACTBOX';
- }
-
- $mw = MagicWord::get( 'SMW_SHOWFACTBOX' );
-
- if ( $mw->matchAndRemove( $text ) ) {
- $words[] = 'SMW_SHOWFACTBOX';
- }
-
- $output = $parser->getOutput();
- $output->mSMWMagicWords = $words;
-
- return $words;
- }
-
-}
diff --git a/includes/Setup.php b/includes/Setup.php
index 3354267..693f0e8 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -72,7 +72,8 @@
// Additional special properties (modification date etc.)
$wgHooks['NewRevisionFromEditComplete'][] =
'SMWHooks::onNewRevisionFromEditComplete';
- $wgHooks['InternalParseBeforeLinks'][] =
'SMWParserExtensions::onInternalParseBeforeLinks'; // parse annotations in
[[link syntax]]
+ // Parsing [[link::syntax]] and resolves property annotations
+ $wgHooks['InternalParseBeforeLinks'][] =
'SMWHooks::onInternalParseBeforeLinks';
$wgHooks['OutputPageParserOutput'][] =
'SMWFactbox::onOutputPageParserOutput'; // copy some data for later Factbox
display
$wgHooks['ArticleFromTitle'][] = 'SMWHooks::onArticleFromTitle'; //
special implementations for property/type articles
@@ -122,7 +123,7 @@
$wgAutoloadClasses['SMWFactbox'] = $incDir .
'SMW_Factbox.php';
$wgAutoloadClasses['SMWInfolink'] = $incDir .
'SMW_Infolink.php';
$wgAutoloadClasses['SMWOutputs'] = $incDir .
'SMW_Outputs.php';
- $wgAutoloadClasses['SMWParserExtensions'] = $incDir .
'SMW_ParserExtensions.php';
+ $wgAutoloadClasses['SMW\ParserTextProcessor'] = $incDir .
'ParserTextProcessor.php';
$wgAutoloadClasses['SMWQueryLanguage'] = $incDir .
'SMW_QueryLanguage.php';
$wgAutoloadClasses['SMWSemanticData'] = $incDir .
'SMW_SemanticData.php';
$wgAutoloadClasses['SMWPageLister'] = $incDir .
'SMW_PageLister.php';
diff --git a/tests/phpunit/includes/HooksTest.php
b/tests/phpunit/includes/HooksTest.php
index e0ad9df..66eed79 100644
--- a/tests/phpunit/includes/HooksTest.php
+++ b/tests/phpunit/includes/HooksTest.php
@@ -382,4 +382,19 @@
}
}
}
+
+ /**
+ * @test SMWHooks::onInternalParseBeforeLinks
+ * @dataProvider getTextDataProvider
+ *
+ * @since 1.9
+ *
+ * @param $text
+ */
+ public function testOnInternalParseBeforeLinks( $text ) {
+ $parser = $this->getParser();
+ $result = SMWHooks::onInternalParseBeforeLinks( $parser, $text
);
+
+ $this->assertTrue( $result );
+ }
}
diff --git a/tests/phpunit/includes/ParserTextProcessorTest.php
b/tests/phpunit/includes/ParserTextProcessorTest.php
new file mode 100644
index 0000000..2584bc5
--- /dev/null
+++ b/tests/phpunit/includes/ParserTextProcessorTest.php
@@ -0,0 +1,389 @@
+<?php
+
+namespace SMW\Test;
+
+use SMW\ParserTextProcessor;
+use SMW\ParserData;
+use SMW\Settings;
+
+use SMWDIProperty;
+use SMWDataItem;
+use SMWDataValueFactory;
+use Title;
+use MWException;
+use ParserOutput;
+use ReflectionClass;
+
+/**
+ * Tests for the SMW\ParserTextProcessor class
+ *
+ * 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
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SMW
+ * @ingroup SMWParser
+ * @ingroup Test
+ *
+ * @group SMW
+ * @group SMWExtension
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+
+/**
+ * Testing methods provided by the ParserTextProcessor class
+ *
+ * @ingroup SMW
+ */
+class ParserTextProcessorTest extends \MediaWikiTestCase {
+
+ protected $className = 'SMW\ParserTextProcessor';
+
+ /**
+ * Provides text samples
+ *
+ * @return array
+ */
+ public function getTextDataProvider() {
+ return array(
+
+ // #0 NS_MAIN; [[FooBar...]] with a different caption
+ array(
+ NS_MAIN,
+ array(
+ 'smwgNamespacesWithSemanticLinks' =>
array( NS_MAIN => true ),
+ 'smwgLinksInValues' => false,
+ 'smwgInlineErrors' => true,
+ ),
+ 'Lorem ipsum dolor sit &$% consectetuer auctor
at quis' .
+ ' [[FooBar::dictumst|寒い]] cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu ultrices eu Ut quis
[[foo::9001]] et Donec.',
+ array(
+ 'resultText' => 'Lorem ipsum dolor
sit &$% consectetuer auctor at quis' .
+ ' [[:Dictumst|寒い]] cursus. Nisl
sit condimentum Quisque facilisis' .
+ ' Suspendisse [[:Tincidunt
semper|tincidunt semper]] facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu
ultrices eu Ut quis [[:9001|9001]] et Donec.',
+ 'propertyCount' => 3,
+ 'propertyLabel' => array( 'Foo', 'Bar',
'FooBar' ),
+ 'propertyValue' => array( 'Dictumst',
'Tincidunt semper', '9001' )
+ )
+ ),
+
+ // #1 NS_MAIN; [[FooBar...]] with a different caption
and smwgLinksInValues = true
+ array(
+ NS_MAIN,
+ array(
+ 'smwgNamespacesWithSemanticLinks' =>
array( NS_MAIN => true ),
+ 'smwgLinksInValues' => true,
+ 'smwgInlineErrors' => true,
+ ),
+ 'Lorem ipsum dolor sit &$% consectetuer auctor
at quis' .
+ ' [[FooBar::dictumst|寒い]] cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::[[tincidunt semper]]]]
facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu ultrices eu Ut quis
[[foo::[http:://www/foo/9001] ]] et Donec.',
+ array(
+ 'resultText' => 'Lorem ipsum dolor
sit &$% consectetuer auctor at quis' .
+ ' [[:Dictumst|寒い]] cursus. Nisl
sit condimentum Quisque facilisis' .
+ ' Suspendisse [[:Tincidunt
semper|tincidunt semper]] facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu
ultrices eu Ut quis'.
+ '
[[:Http:://www/foo/9001|http:://www/foo/9001]] et Donec.',
+ 'propertyCount' => 3,
+ 'propertyLabel' => array( 'Foo', 'Bar',
'FooBar' ),
+ 'propertyValue' => array( 'Dictumst',
'Tincidunt semper', 'Http:://www/foo/9001' )
+ )
+ ),
+
+ // #1 NS_MAIN, [[-FooBar...]] produces an error with
inlineErrors = true
+ // (only check for an indication of an error in
'resultText' )
+ array(
+ NS_MAIN,
+ array(
+ 'smwgNamespacesWithSemanticLinks' =>
array( NS_MAIN => true ),
+ 'smwgLinksInValues' => false,
+ 'smwgInlineErrors' => true,
+ ),
+ 'Lorem ipsum dolor sit &$% consectetuer auctor
at quis' .
+ ' [[-FooBar::dictumst|重い]] cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu ultrices eu Ut quis
[[foo::9001]] et Donec.',
+ array(
+ 'resultText' =>
'class="smw-highlighter" data-type="4" data-state="inline"',
+ 'propertyCount' => 2,
+ 'propertyLabel' => array( 'Foo', 'Bar'
),
+ 'propertyValue' => array( 'Tincidunt
semper', '9001' )
+ )
+ ),
+
+ // #2 NS_MAIN, [[-FooBar...]] produces an error but
inlineErrors = false
+ array(
+ NS_MAIN,
+ array(
+ 'smwgNamespacesWithSemanticLinks' =>
array( NS_MAIN => true ),
+ 'smwgLinksInValues' => false,
+ 'smwgInlineErrors' => false,
+ ),
+ 'Lorem ipsum dolor sit &$% consectetuer auctor
at quis' .
+ ' [[-FooBar::dictumst|軽い]] cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu ultrices eu Ut quis
[[foo::9001]] et Donec.',
+ array(
+ 'resultText' => 'Lorem ipsum dolor
sit &$% consectetuer auctor at quis' .
+ ' 軽い cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[:Tincidunt
semper|tincidunt semper]] facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu
ultrices eu Ut quis [[:9001|9001]] et Donec.',
+ 'propertyCount' => 2,
+ 'propertyLabel' => array( 'Foo', 'Bar'
),
+ 'propertyValue' => array( 'Tincidunt
semper', '9001' )
+ )
+ ),
+
+ // #3 NS_HELP disabled
+ array(
+ NS_HELP,
+ array(
+ 'smwgNamespacesWithSemanticLinks' =>
array( NS_HELP => false ),
+ 'smwgLinksInValues' => false,
+ 'smwgInlineErrors' => true,
+ ),
+ 'Lorem ipsum dolor sit &$% consectetuer auctor
at quis' .
+ ' [[FooBar::dictumst|おもろい]] cursus. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu ultrices eu Ut quis
[[foo::9001]] et Donec.',
+ array(
+ 'resultText' => 'Lorem ipsum dolor
sit &$% consectetuer auctor at quis' .
+ ' [[:Dictumst|おもろい]] cursus.
Nisl sit condimentum Quisque facilisis' .
+ ' Suspendisse [[:Tincidunt
semper|tincidunt semper]] facilisi dolor Aenean. Ut' .
+ ' Aliquam {{volutpat}} arcu
ultrices eu Ut quis [[:9001|9001]] et Donec.',
+ 'propertyCount' => 0,
+ 'propertyLabel' => array(),
+ 'propertyValue' => array()
+ )
+ ),
+ );
+ }
+
+ /**
+ * Provides magic words sample text
+ *
+ * @return array
+ */
+ public function getMagicWordDataProvider() {
+ return array(
+ // #0 __NOFACTBOX__
+ array(
+ NS_MAIN,
+ 'Lorem ipsum dolor sit amet consectetuer auctor
at quis' .
+ ' [[Foo::dictumst cursus]]. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' __NOFACTBOX__ ',
+ array( 'SMW_NOFACTBOX' )
+ ),
+
+ // #1 __SHOWFACTBOX__
+ array(
+ NS_HELP,
+ 'Lorem ipsum dolor sit amet consectetuer auctor
at quis' .
+ ' [[Foo::dictumst cursus]]. Nisl sit
condimentum Quisque facilisis' .
+ ' Suspendisse [[Bar::tincidunt semper]]
facilisi dolor Aenean. Ut' .
+ ' __SHOWFACTBOX__',
+ array( 'SMW_SHOWFACTBOX' )
+ ),
+ );
+ }
+
+ /**
+ * Helper method that returns a random string
+ *
+ * @since 1.9
+ *
+ * @param $length
+ *
+ * @return string
+ */
+ private function getRandomString( $length = 10 ) {
+ return substr( str_shuffle(
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ), 0, $length
);
+ }
+
+ /**
+ * Helper method that returns a Title object
+ *
+ * @param $namespace
+ *
+ * @return Title
+ */
+ private function getTitle( $namespace = NS_MAIN ){
+ return Title::newFromText( $this->getRandomString(), $namespace
);
+ }
+
+ /**
+ * Helper method that returns a ParserOutput object
+ *
+ * @return ParserOutput
+ */
+ private function getParserOutput(){
+ return new ParserOutput();
+ }
+
+ /**
+ * Helper method that returns a ParserData object
+ *
+ * @param $title
+ * @param $parserOutput
+ *
+ * @return ParserData
+ */
+ private function getParserData( Title $title, ParserOutput
$parserOutput ){
+ return new ParserData( $title, $parserOutput );
+ }
+
+ /**
+ * Helper method that returns a ParserTextProcessor object
+ *
+ * @param $title
+ * @param $parserOutput
+ * @param $settings
+ *
+ * @return ParserTextProcessor
+ */
+ private function getInstance( Title $title, ParserOutput $parserOutput,
array $settings = array() ) {
+ return new ParserTextProcessor(
+ $this->getParserData( $title, $parserOutput ),
+ Settings::newFromArray( $settings )
+ );
+ }
+
+ /**
+ * @test ParserTextProcessor::__construct
+ * @dataProvider getTextDataProvider
+ *
+ * @since 1.9
+ *
+ * @param $namespace
+ */
+ public function testConstructor( $namespace ) {
+ $instance = $this->getInstance( $this->getTitle( $namespace ),
$this->getParserOutput() );
+ $this->assertInstanceOf( $this->className, $instance );
+ }
+
+ /**
+ * @test ParserTextProcessor::getRDFUrl
+ *
+ * @since 1.9
+ */
+ public function testGetRDFUrl() {
+ $reflection = new ReflectionClass( $this->className );
+
+ $parserOutput = $this->getParserOutput();
+ $title = $this->getTitle();
+ $instance = $this->getInstance( $title, $parserOutput );
+
+ // Make proected method accessible
+ $method = $reflection->getMethod( 'getRDFUrl' );
+ $method->setAccessible( true );
+
+ // Invoke the instance
+ $result = $method->invoke( $instance, $title );
+
+ // Doing a lazy check, the url has to contain the title text
+ $this->assertInternalType( 'string', $result );
+ $this->assertContains( 'title="' . $title->getText() . '"',
$result );
+ }
+
+ /**
+ * @test ParserTextProcessor::stripMagicWords
+ * @dataProvider getMagicWordDataProvider
+ *
+ * @since 1.9
+ *
+ * @param $namespace
+ * @param $text
+ * @param $expected
+ */
+ public function testStripMagicWords( $namespace, $text, array $expected
) {
+ $reflection = new ReflectionClass( $this->className );
+
+ $parserOutput = $this->getParserOutput();
+ $title = $this->getTitle( $namespace );
+ $instance = $this->getInstance( $title, $parserOutput );
+
+ // Make protected method accessible
+ $method = $reflection->getMethod( 'stripMagicWords' );
+ $method->setAccessible( true );
+
+ $result = $method->invoke( $instance, array( &$text ) );
+
+ // Check return values
+ $this->assertInternalType( 'array', $result );
+ $this->assertEquals( $expected, $result );
+
+ // Check values against ParserData/ParserOutput object
+ $parserData = $this->getParserData( $title, $parserOutput );
+
+ if ( method_exists( $parserOutput, 'getExtensionData' ) ) {
+ $this->assertEquals( $expected,
$parserData->getOutput()->getExtensionData( 'smwmagicwords' ) );
+ } else {
+ $this->assertEquals( $expected,
$parserData->getOutput()->mSMWMagicWords );
+ }
+ }
+
+ /**
+ * @test ParserTextProcessor::parse
+ * @dataProvider getTextDataProvider
+ *
+ * @since 1.9
+ *
+ * @param $namespace
+ * @param $settings
+ * @param $text
+ * @param $expected
+ */
+ public function testParse( $namespace, array $settings, $text, array
$expected ) {
+ $parserOutput = $this->getParserOutput();
+ $title = $this->getTitle( $namespace );
+ $instance = $this->getInstance( $title, $parserOutput,
$settings );
+
+ // Text parsing
+ $instance->parse( $text );
+
+ // Check transformed text
+ $this->assertContains( $expected['resultText'], $text );
+
+ // Re-read data from stored parserOutput
+ $parserData = $this->getParserData( $title, $parserOutput );
+
+ // Check the returned instance
+ $this->assertInstanceOf( 'SMWSemanticData',
$parserData->getData() );
+ $this->assertCount( $expected['propertyCount'],
$parserData->getData()->getProperties() );
+
+ // Check added properties
+ foreach ( $parserData->getData()->getProperties() as $key =>
$diproperty ){
+ $this->assertInstanceOf( 'SMWDIProperty', $diproperty );
+ $this->assertContains( $diproperty->getLabel(),
$expected['propertyLabel'] );
+
+ // Check added property values
+ foreach ( $parserData->getData()->getPropertyValues(
$diproperty ) as $dataItem ){
+ $dataValue =
SMWDataValueFactory::newDataItemValue( $dataItem, $diproperty );
+ if ( $dataValue->getDataItem()->getDIType() ===
SMWDataItem::TYPE_WIKIPAGE ){
+ $this->assertContains(
$dataValue->getWikiValue(), $expected['propertyValue'] );
+ }
+ }
+ }
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/60393
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I66b812e0276820fa58dbbfbc632236ea6f8ba6d5
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/SemanticMediaWiki
Gerrit-Branch: master
Gerrit-Owner: Mwjames <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: Mwjames <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits