Extension:Article Class Extended

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 whereby 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.

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 *                   stylesheet data here * * 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; } ?>

 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 "; 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. content 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. ?>