Extension:Article Class Extended
From MediaWiki.org
|
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. ?>