Extension:Article Class Extended

From MediaWiki.org

Jump to: navigation, search

         

Manual on MediaWiki Extensions
List of MediaWiki Extensions
Crystal Clear action run.png
ArticleEx

Release status: stable

Implementation  Hook
Description Extends the Mediawiki Article Class to provide serving pages without skin and addressed through explicit 'type' information.
Author(s)  user:jldupont
Last Version  1.7
MediaWiki  tested on 1.8.2 and 1.9.3
License No license specified
Download [1]

check usage (experimental)

Contents

[edit] What can this extension do?

This extension extends the Mediawiki Article class with the following features:

  • Serves XML / XSL data sources stored in MW pages with proper MIME content type (requires using Extension:XML Class)
  • Serves 'raw' data stored in MW pages, the said data must be enclosed in <tag> whereby <tag> defines the title name extension that will be used to retrieve the said data.
  • Adds a new hook ArticleViewEx which can be leveraged to modify content before it is added to the output page.

[edit] Usage

[edit] Installation

[edit] Parameters

[edit] Changes to LocalSettings.php

[edit] Code

<?php
/*
 * ArticleEx.php
 * 
 * MediaWiki extension
 * @author: Jean-Lou Dupont (http://www.bluecortex.com)
 *
 * Purpose:  Extends the MW Article class to handle
 *           the serving of pages without skin and addressed
 *           through explicit type information.
 *           Example:
 *           /index.php?title=Main:somexmldatapage.xml
 *           The actual MW stored article is titled:
 *           "Main:somexmldatapage" and the "raw" form
 *           is addressed with the above URL.
 *
 * Supported types:  all.  Data is retrieved from
 *                   a section delimited with an XML style
 *                   tag.  E.g. for an XSL XML stylesheet,
 *                   the page data would be enclosed in
 *                   <xsl> stylesheet data here </xsl>  
 *
 * Tested Compatibility: MW 1.8.2
 *
 * History:
 * v1.0		Initial availability
 * v1.1		- Added "ArticleViewEx" hook
 * v1.2		- Added "ArticleViewExBegin" hook
 *          - Added a general purpose "attributes" array.
 *          - Added the capability to flag is the said article
 *            is the first loaded in a transaction.
 * v1.3		- Corrected major bug: if article did not exists
 *			  would cause a fatal error.
 * v1.4		- Corrected maor bug: if an non-existing page from
 *            the following namespaces is requested (NS_MEDIA,
 *            NS_CATEGORY, NS_IMAGE), the standard processing
 *            flow should have been continued.
 * v1.5     - Corrected bug: initialised attributes array AFTER
 *            setting some variables causing loss of variables...
 * v1.6     - Added support for retrieving the 'categorylinks'
 *            when a valid article is loaded. The data can be found
 *            in '$this->categories'.
 *            This functionality is especially useful when templates
 *            require 'categorisation' level information.
 *          - Added initialisation of the global variable 'wgArticle'.
 *            Normally, this global variable is initialised a little bit
 *            too late to be useful i.e. after the action on the page is
 *            actually performed (see Wiki.php 'initialize' function).
 *
 * v1.7     - (a) Added chaining capability to 'ArticleViewExBegin' hook.
 *
 */
$wgExtensionCredits['other'][] = array( 
	'name'    => 'ArticleEx',
	'version' => '1.7',
	'author'  => 'Jean-Lou Dupont', 
	'url'     => 'http://www.bluecortex.com',
);
 
require_once(dirname( __FILE__ ) . '/ArticleExClass.php');
 
$wgExtensionFunctions[] = "wfArticleExSetup";
 
function wfArticleExSetup()
{
	global $wgHooks;
	$wgHooks['ArticleFromTitle'][] = 'wfArticleExInit';	
}
 
function wfArticleExInit( &$title, &$article )
{
	// What really counts is what is returned in $article.
	$GLOBALS['wgArticle'] = new ArticleExClass( $title, $article, true );
	return true;	
} 
?>
<?php
/*
 * ArticleExClass.php
 * 
 * MediaWiki extension
 * @author: Jean-Lou Dupont (http://www.bluecortex.com)
*/
 
require_once("$IP/includes/Article.php");
 
class ArticleExClass extends Article
{
	static $qType = array(
							'js'  => array( 'js', 'javascript' ),
							'xsl' => array( 'xsl', 'xml' ),
							'xml' => array( 'xml', 'xsl' ),
						);
	var $noskin;
	var $extractSection;
	var $type;
	var $bname;
	var $fname;
	var $section;
	var $attributes;
	var $foundDot;
 
	public function ArticleExClass( &$title, &$article, $firstArticleInTransation=false )
	{
		$this->init();	
		$this->setA("first", $firstArticleInTransation );  // new in v1.2
		$this->create( $title, $article );
	}
 
	public function init()
	{
		$this->noskin = false;
		$this->type   = null;
		$this->bname  = "";
		$this->extractSection = false;
		$this->section = null;
		$this->attributes = array();
		$this->foundDot = false;
	}
 
	// Attributes table 'getter/setter' interface.
	// v1.2 change.
	public function setA($key,$value) { $this->attributes[$key]=$value; }
	public function getA($key)		  { return @$this->attributes[$key]; }
 
	public function create( &$title, &$article )
	/*
	 *   Hook function handler.
	 *   Substitutes an ArticleEx object instance in place
	 *   of the usual MW Article class object.
	 *
	 */
	{
		// Check the special cases
		$ns = $title->getNamespace();
		if ($ns == NS_MEDIA || $ns == NS_IMAGE || $ns == NS_CATEGORY)
			return null; // let the normal flow proceed.
 
		parent::__construct( $title );
		$article = $this;
 
		// Let's check the database if a page matching the title name
		// actually exists... if one does, then abort our special hook.
		if ($this->getID()!=0)
			return true;  // continue the hook chain.
 
		// First, extract base name from MW Title Class object.
		// The base name takes the form:
		//    somemwprefixeddbkey.type
		// Where only the right most '.' delimits the 'type' information
		$n = $this->fname = $this->getTitle()->getPrefixedDBkey();
		$p = strrpos( $n, "." );
 
		if ($p===false) 	// no '.' found, bail out.
			return true;
 
		// Raise a flag to simplify our lives in the view() method.
		$this->foundDot = true;
 
		// We are anyhow dealing with a valid MW title name,
		// so spare the security checks.
		$this->bname = substr($n, 0, $p);
		$this->type  = substr($n, $p+1 );
 
		return true; // continue the hook chain.
	}
 
	public function view()
	{
		// V1.2 change
		// Don't forget to check user rights (if applicable) 
		// in the extensions that attach here!
		if (!wfRunHooks( 'ArticleViewExBegin', array( &$this ) ))
			return; // v1.7 feature (a)
 
		if (!$this->foundDot)
			return parent::view();				
 
		// if the article does not exists (probably given the 'type' extension
		// appended to the title name) & an actual 'type' extension is 
		// found in the title name, then let's check if an article actually
		// exists with a title name that EXCLUDES the 'type' extension.
		if ($this->getID()!=0)
			return parent::view();
 
		// at this point, we know that the article does not exist.
		// Let's check for an article with for title one without
		// the 'type' extension.
		$title = Title::newFromText($this->bname);
		$this->mTitle = $title; 
		$this->clear();
		$this->oldid= null;
 
		// nope...
		if ($this->getID()==0)
		{
			// good thing we kept the full title name just in case!
			$title = Title::newFromText($this->fname);
			$this->mTitle = $title;
			$this->clear();
			$this->oldid = null;
			return parent::view(); // go with default behavior
		}
 
		// At this point, we know we have a valid article
 
		// Check User Rights...
		if (!$title->userCanRead()) 
			return parent::view(); // let the normal flow handle this one...
 
		$this->loadContent();
 
		$this->extractSection = empty($this->type) ? false:true;	
 
		#echo "type = $this->type, extract= $this->extractSection <br/>";
 
		if ($this->extractSection)
			$this->section = $this->extractSection( $this->type, $this->mContent ) ;			
 
		#echo $this->section;
 
		// DEFAULT BEHAVIOR:
		// If we have detected a "type" in the page name,
		// then serve the page without the skin.
		$this->noskin = empty($this->type) ? false:true;
		$content = $this->section;
 
		// The other parameters can be fetched from the object itself.
		// Parameters passed:
		// - ArticleEx object instance
		// - type e.g. xml, xsl etc.
		// - content  (what is about to be returned if nothing is done)
		// 
		// NOTE: at this point, the variable $content does not include the
		//       Mediawiki content enclosing tags e.g. <xml> content </xml>
		wfRunHooks( 'ArticleViewEx', array( &$this, &$this->type, &$content ) );
 
		global $wgOut;
		$wgOut->clearHTML();
		$wgOut->addHTML( $content );				
 
		// next, let's see if we need to apply special treatment.
		if ($this->noskin)
			$wgOut->setArticleBodyOnly(true);
 
	}
	private function extractSection( &$type, &$content )
	{
		// check if we have multiple choices
		if (isset(self::$qType[$type]))
		{
			$tags = self::$qType[$type];
			foreach( $tags as $tag )
			{
				$pattern = "/<".$tag."(?:.*)\>(.*)(?:\<.?".$tag.">)/siU";
				$r = preg_match_all( $pattern, $content, $m );
				if ($r>0)
					break;
			}
		}
		else
		{
			$pattern = "/<".$type."(?:.*)\>(.*)(?:\<.?".$type.">)/siU";
			preg_match_all( $pattern, $content, $m );
		}
 
		return trim( $m[1][0] ); // just the first submatch
	}
 
// =================================================================================
 
	public function loadPageData( $data = 'fromdb' )
	/*
	 *   This hook is used to retrieve all the categories associated with an article.
	 */
	{
		$ret = parent::loadPageData( $data ); // get return code just in case.
 
		// At this point, we have a valid 'page id' in a local variable.
		// Use it to query the database for 'categorylinks'
		$dbr      =& wfGetDB( DB_SLAVE );
		$page     = $dbr->tableName( 'page' );
        $catlinks = $dbr->tableName( 'categorylinks' ); 
 
		$id = $this->getID();
 
		$query = "SELECT cl_to FROM {$catlinks} WHERE {$catlinks}.cl_from={$id}";
 
		$results = $dbr->query( $query );
		$count   = $dbr->numRows( $results );
 
		if ($count>=1)
			while( $row = $dbr->fetchObject( $results ) )
				$this->categories[] = $row->cl_to;
 
		$dbr->freeResult( $results );
 
		return $ret;
	}
 
} // End class definition.
?>

[edit] See also