Extension:TopTenPages/Code

From MediaWiki.org
Jump to: navigation, search
<?php
 
# To activate the extension, include it from your LocalSettings.php
# with: include("extensions/TopTenPages.php");
# 
# Syntax: <TopTenPages/> 
#   alternative: <TopTenPages>5</TopTenPages>
#   option to omit most popular page(s): <TopTenPages offset=1/>
#   option to search certain namspaces most popular page(s): <TopTenPages namespace="talk"/>
#      takes "talk", "user", "image", "template", "help", "category" . defaults to namespace="main".

 
$wgExtensionCredits['specialpage'][] = array(
        'name' => 'TopTenPages',
        'author' => 'Sascha',
        'url' => 'http://www.mediawiki.org/wiki/Extension:TopTenPages',
        'description' => 'Shows most viewed pages',
);
 
 
$wgExtensionFunctions[] = "wfTopTenPages";
 
/**
 *
 * @package MediaWiki
 * @subpackage SpecialPage
 */
 
class TopTenPagesPage extends QueryPageAlt {
 
        function getName() {
                return "TopTenPages";
        }
 
        function isExpensive() {
                # page_counter is not indexed
                return true;
        }
        function isSyndicated() { return false; }
 
        function getSQL($select_namespace) {          
                $dbr =& wfGetDB( DB_SLAVE );
                $page = $dbr->tableName( 'page' );
 
        switch($select_namespace){
                # Commented-Out give errors "implode() [function.implode]: Bad arguments. " around line 512                 
         case "":
                        $namespace_constant_no=NS_MAIN;
                        break;
                case "talk":
                        $namespace_constant_no=NS_TALK;
                        break;
                #case "special":
         #     $namespace_constant_no=NS_SPECIAL;
         #     break;
         case "user":
                        $namespace_constant_no=NS_USER;
                        break;
                #case "media":
         #     $namespace_constant_no=NS_MEDIA;
         #     break;
         #case "usertalk":
         #     $namespace_constant_no=NS_USER_TALK;
         #     break;
         #case "wikipedia":
         #     $namespace_constant_no=NS_WIKIPEDIA;
         #     break;
         #case "wikipediatalk":
         #     $namespace_constant_no=NS_WIKIPEDIA_TALK;
         #     break;
         case "image":
                        $namespace_constant_no=NS_IMAGE;
                        break;
                #case "imagetalk":
         #     $namespace_constant_no=NS_IMAGE_TALK;
         #     break;  
         case "template":
                        $namespace_constant_no=NS_TEMPLATE;
                        break;        
                #case "templatetalk":
         #     $namespace_constant_no=NS_TEMPLATE_TALK;
         #     break;  
         case "help":
                        $namespace_constant_no=NS_HELP;
                        break;        
                #case "helptalk":
         #     $namespace_constant_no=NS_HELP_TALK;
         #     break;  
         case "category":
                        $namespace_constant_no=NS_CATEGORY;
                        break;        
                #case "categorytalk":
         #     $namespace_constant_no=NS_CATEGORY_TALK;
         #     break;  
         default:
                        $namespace_constant_no=NS_MAIN;
        }
                return
                        "SELECT 'TopTenPages' as type,
                                page_namespace as namespace,
                                page_title as title,
                                page_counter as value
                        FROM $page
                        WHERE page_namespace=".$namespace_constant_no." AND page_is_redirect=0";
        }
 
        function formatResult( $skin, $result ) {
                global $wgLang, $wgContLang;
                $title = Title::makeTitle( $result->namespace, $result->title );
                $link = $skin->makeKnownLinkObj( $title, htmlspecialchars( $wgContLang->convert( $title->getPrefixedText() ) ) );
                $nv = wfMsgExt( 'nviews', array( 'parsemag', 'escape'),
                        $wgLang->formatNum( $result->value ) );
                return wfSpecialList($link, $nv);
        }
 
}
 
/**
 * Constructor
 */
function wfSpecialTopTenPages() {
    /*list( $limit, $offset ) = wfCheckLimits();*/
        list( $limit, $offset ) = wfCheckLimits();      
    $ttp = new TopTenPagesPage();       
        return;
}
 
 
function wfTopTenPages() {
    global $wgParser;
    $wgParser->setHook( "TopTenPages", "renderTopTenPages" );
}
 
 
# The callback function for converting the input text to HTML output
function renderTopTenPages( $input, $argv ) {
 
                if (array_key_exists('offset', $argv)) {
                        $offset = $argv['offset'];
                }         
                else {
                        $offset = 0;
                }
                if (array_key_exists('namespace', $argv)) {
                        $select_namespace = $argv['namespace'];
                }
                else {
                        $select_namespace = "main";
                }
 
        /*list( $limit, $offset ) = wfCheckLimits();*/
        $limit = 10;
        if ($input>0){
         $limit = $input;
        }
 
                $ttp = new TopTenPagesPage();
        $ttp->listoutput = false;
        $ttp->select_namespace = $select_namespace;
        $output = '<!-- TopTenPages -->';
        $output .= $ttp->doQuery( $offset, $limit, false);  
        #$output .= $ttp->getNamespace();
        return $output;
}
 
/**
 * This is a class for doing query pages; since they're almost all the same,
 * we factor out some of the functionality into a superclass, and let
 * subclasses derive from it.
 *
 * @package MediaWiki
 */
class QueryPageAlt {
 
        /**
         * Which Namespace to select from
         *
         * @var string
         */
        var $select_namespace = "main";
 
        /**
         * A mutator for $this->select_namespace;
         *
         * @param string $string
         */
        function setNamespace( $string ) {
                $this->select_namespace = $string;
        }
 
        /**
         * A mutator for $this->select_namespace;
         *
         * @param string $string
         */
        function getNamespace() {
                return $this->select_namespace;
        }
 
        /**
         * Whether or not we want plain listoutput rather than an ordered list
         *
         * @var bool
         */
        var $listoutput = false;
 
        /**
         * The offset and limit in use, as passed to the query() function
         *
         * @var integer
         */
        var $offset = 0;
        var $limit = 0;
 
        /**
         * A mutator for $this->listoutput;
         *
         * @param bool $bool
         */
        function setListoutput( $bool ) {
                $this->listoutput = $bool;
        }
 
        /**
         * Subclasses return their name here. Make sure the name is also
         * specified in SpecialPage.php and in Language.php as a language message
         * param.
         */
        function getName() {
                return '';
        }
 
        /**
         * Return title object representing this page
         *
         * @return Title
         */
        function getTitle() {
                return Title::makeTitle( NS_SPECIAL, $this->getName() );
        }
 
        /**
         * Subclasses return an SQL query here.
         *
         * Note that the query itself should return the following four columns:
         * 'type' (your special page's name), 'namespace', 'title', and 'value'
         * *in that order*. 'value' is used for sorting.
         *
         * These may be stored in the querycache table for expensive queries,
         * and that cached data will be returned sometimes, so the presence of
         * extra fields can't be relied upon. The cached 'value' column will be
         * an integer; non-numeric values are useful only for sorting the initial
         * query.
         *
         * Don't include an ORDER or LIMIT clause, this will be added.
         */
        function getSQL() {
                return "SELECT 'sample' as type, 0 as namespace, 'Sample result' as title, 42 as value";
        }
 
        /**
         * Override to sort by increasing values
         */
        function sortDescending() {
                return true;
        }
 
        function getOrder() {
                return ' ORDER BY value ' .
                        ($this->sortDescending() ? 'DESC' : '');
        }
 
        /**
         * Is this query expensive (for some definition of expensive)? Then we
         * don't let it run in miser mode. $wgDisableQueryPageAlts causes all query
         * pages to be declared expensive. Some query pages are always expensive.
         */
        function isExpensive( ) {
                global $wgDisableQueryPageAlts;
                return $wgDisableQueryPageAlts;
        }
 
        /**
         * Whether or not the output of the page in question is retrived from
         * the database cache.
         *
         * @return bool
         */
        function isCached() {
                global $wgMiserMode;
 
                return $this->isExpensive() && $wgMiserMode;
        }
 
        /**
         * Sometime we dont want to build rss / atom feeds.
         */
        function isSyndicated() {
                return true;
        }
 
        /**
         * Formats the results of the query for display. The skin is the current
         * skin; you can use it for making links. The result is a single row of
         * result data. You should be able to grab SQL results off of it.
         * If the function return "false", the line output will be skipped.
         */
        function formatResult( $skin, $result ) {
                return '';
        }
 
        /**
         * The content returned by this function will be output before any result
         */
        function getPageHeader( ) {
                return '';
        }
 
        /**
         * If using extra form wheely-dealies, return a set of parameters here
         * as an associative array. They will be encoded and added to the paging
         * links (prev/next/lengths).
         * @return array
         */
        function linkParameters() {
                return array();
        }
 
        /**
         * Some special pages (for example SpecialListusers) might not return the
         * current object formatted, but return the previous one instead.
         * Setting this to return true, will call one more time wfFormatResult to
         * be sure that the very last result is formatted and shown.
         */
        function tryLastResult( ) {
                return false;
        }
 
        /**
         * Clear the cache and save new results
         */
        function recache( $limit, $ignoreErrors = true ) {
                $fname = get_class($this) . '::recache';
                $dbw =& wfGetDB( DB_MASTER );
                $dbr =& wfGetDB( DB_SLAVE, array( $this->getName(), 'QueryPageAlt::recache', 'vslow' ) );
                if ( !$dbw || !$dbr ) {
                        return false;
                }
 
                $querycache = $dbr->tableName( 'querycache' );
 
                if ( $ignoreErrors ) {
                        $ignoreW = $dbw->ignoreErrors( true );
                        $ignoreR = $dbr->ignoreErrors( true );
                }
 
                # Clear out any old cached data
                $dbw->delete( 'querycache', array( 'qc_type' => $this->getName() ), $fname );
                # Do query
                $sql = $this->getSQL($select_namespace) . $this->getOrder();
                if ($limit !== false)
                        $sql = $dbr->limitResult($sql, $limit, 0);
                $res = $dbr->query($sql, $fname);
                $num = false;
                if ( $res ) {
                        $num = $dbr->numRows( $res );
                        # Fetch results
                        $insertSql = "INSERT INTO $querycache (qc_type,qc_namespace,qc_title,qc_value) VALUES ";
                        $first = true;
                        while ( $res && $row = $dbr->fetchObject( $res ) ) {
                                if ( $first ) {
                                        $first = false;
                                } else {
                                        $insertSql .= ',';
                                }
                                if ( isset( $row->value ) ) {
                                        $value = $row->value;
                                } else {
                                        $value = '';
                                }
 
                                $insertSql .= '(' .
                                        $dbw->addQuotes( $row->type ) . ',' .
                                        $dbw->addQuotes( $row->namespace ) . ',' .
                                        $dbw->addQuotes( $row->title ) . ',' .
                                        $dbw->addQuotes( $value ) . ')';
                        }
 
                        # Save results into the querycache table on the master
                        if ( !$first ) {
                                if ( !$dbw->query( $insertSql, $fname ) ) {
                                        // Set result to false to indicate error
                                        $dbr->freeResult( $res );
                                        $res = false;
                                }
                        }
                        if ( $res ) {
                                $dbr->freeResult( $res );
                        }
                        if ( $ignoreErrors ) {
                                $dbw->ignoreErrors( $ignoreW );
                                $dbr->ignoreErrors( $ignoreR );
                        }
 
                        # Update the querycache_info record for the page
                        $dbw->delete( 'querycache_info', array( 'qci_type' => $this->getName() ), $fname );
                        $dbw->insert( 'querycache_info', array( 'qci_type' => $this->getName(), 'qci_timestamp' => $dbw->timestamp() ), $fname );
 
                }
                return $num;
        }
 
        /**
         * This is the actual workhorse. It does everything needed to make a
         * real, honest-to-gosh query page.
         *
         * @param $offset database query offset
         * @param $limit database query limit
         * @param $shownavigation show navigation like "next 200"?
         */
        function doQuery( $offset, $limit, $shownavigation=true) {
                global $wgUser, $wgOut, $wgLang, $wgContLang;
 
                $this->offset = $offset;
                $this->limit = $limit;
 
                $sname = $this->getName();
                $fname = get_class($this) . '::doQuery';
                $sql = $this->getSQL($this->select_namespace);
                $dbr =& wfGetDB( DB_SLAVE );
                $querycache = $dbr->tableName( 'querycache' );
 
                $wgOut->setSyndicated( $this->isSyndicated() );
 
                if ( $this->isCached() ) {
                        $type = $dbr->strencode( $sname );
                        $sql =
                                "SELECT qc_type as type, qc_namespace as namespace,qc_title as title, qc_value as value
                                 FROM $querycache WHERE qc_type='$type'";
 
                        if( !$this->listoutput ) {
 
                                # Fetch the timestamp of this update
                                $tRes = $dbr->select( 'querycache_info', array( 'qci_timestamp' ), array( 'qci_type' => $type ), $fname );
                                $tRow = $dbr->fetchObject( $tRes );
 
                                if( $tRow ) {
                                        $updated = $wgLang->timeAndDate( $tRow->qci_timestamp, true, true );
                                        $cacheNotice = wfMsg( 'perfcachedts', $updated );
                                        $wgOut->addMeta( 'Data-Cache-Time', $tRow->qci_timestamp );
                                        $wgOut->addScript( '<script language="JavaScript">var dataCacheTime = \'' . $tRow->qci_timestamp . '\';</script>' );
                                } else {
                                        $cacheNotice = wfMsg( 'perfcached' );
                                }
 
                                $wgOut->addWikiText( $cacheNotice );
                        }
 
                }
 
                $sql .= $this->getOrder();
                $sql = $dbr->limitResult($sql, $limit, $offset);
                $res = $dbr->query( $sql );
                $num = $dbr->numRows($res);
 
                $this->preprocessResults( $dbr, $res );
 
                $sk = $wgUser->getSkin( );
 
                if($shownavigation) {
                        $wgOut->addHTML( $this->getPageHeader() );
                        $top = wfShowingResults( $offset, $num);
                        $wgOut->addHTML( "<p>{$top}\n" );
 
                        # often disable 'next' link when we reach the end
                        $atend = $num < $limit;
 
                        $sl = wfViewPrevNext( $offset, $limit ,
                                $wgContLang->specialPage( $sname ),
                                wfArrayToCGI( $this->linkParameters() ), $atend );
                        $wgOut->addHTML( "<br />{$sl}</p>\n" );
                }
                if ( $num > 0 ) {
                        $s = array();
                        if ( ! $this->listoutput )
                                $s[] = "<ol start='" . ( $offset == 0 ? $offset + 1 : $offset ) . "' class='special'>";
 
                        # Only read at most $num rows, because $res may contain the whole 1000
                        for ( $i = 0; $i < $num && $obj = $dbr->fetchObject( $res ); $i++ ) {
                                $format = $this->formatResult( $sk, $obj );
                                if ( $format ) {
                                        $attr = ( isset ( $obj->usepatrol ) && $obj->usepatrol &&
                                                                                $obj->patrolled == 0 ) ? ' class="not-patrolled"' : '';
                                        $s[] = $this->listoutput ? $format : "<li{$attr}>{$format}</li>\n";
                                }
                        }
 
                        if($this->tryLastResult()) {
                                // flush the very last result
                                $obj = null;
                                $format = $this->formatResult( $sk, $obj );
                                if( $format ) {
                                        $attr = ( isset ( $obj->usepatrol ) && $obj->usepatrol &&
                                                                                $obj->patrolled == 0 ) ? ' class="not-patrolled"' : '';
                                        $s[] = "<li{$attr}>{$format}</li>\n";
                                }
                        }
 
                        $dbr->freeResult( $res );
                        if ( ! $this->listoutput )
                                $s[] = '</ol>';
                        $str = $this->listoutput ? $wgContLang->listToText( $s ) : implode( '', $s );                   
                }
                if($shownavigation) {
                        $wgOut->addHTML( "<p>{$sl}</p>\n" );
                }
                return implode(" ", $s );
        }
 
        /**
         * Do any necessary preprocessing of the result object.
         * You should pass this by reference: &$db , &$res
         */
        function preprocessResults( $db, $res ) {}
 
        /**
         * Similar to above, but packaging in a syndicated feed instead of a web page
         */
        function doFeed( $class = '', $limit = 50 ) {
                global $wgFeedClasses;
 
                if( isset($wgFeedClasses[$class]) ) {
                        $feed = new $wgFeedClasses[$class](
                                $this->feedTitle(),
                                $this->feedDesc(),
                                $this->feedUrl() );
                        $feed->outHeader();
 
                        $dbr =& wfGetDB( DB_SLAVE );
                        $sql = $this->getSQL($this->select_namespace) . $this->getOrder();
                        $sql = $dbr->limitResult( $sql, $limit, 0 );
                        $res = $dbr->query( $sql, 'QueryPageAlt::doFeed' );
                        while( $obj = $dbr->fetchObject( $res ) ) {
                                $item = $this->feedResult( $obj );
                                if( $item ) $feed->outItem( $item );
                        }
                        $dbr->freeResult( $res );
 
                        $feed->outFooter();
                        return true;
                } else {
                        return false;
                }
        }
 
        /**
         * Override for custom handling. If the titles/links are ok, just do
         * feedItemDesc()
         */
        function feedResult( $row ) {
                if( !isset( $row->title ) ) {
                        return NULL;
                }
                $title = Title::MakeTitle( intval( $row->namespace ), $row->title );
                if( $title ) {
                        $date = isset( $row->timestamp ) ? $row->timestamp : '';
                        $comments = '';
                        if( $title ) {
                                $talkpage = $title->getTalkPage();
                                $comments = $talkpage->getFullURL();
                        }
 
                        return new FeedItem(
                                $title->getPrefixedText(),
                                $this->feedItemDesc( $row ),
                                $title->getFullURL(),
                                $date,
                                $this->feedItemAuthor( $row ),
                                $comments);
                } else {
                        return NULL;
                }
        }
 
        function feedItemDesc( $row ) {
                return isset( $row->comment ) ? htmlspecialchars( $row->comment ) : '';
        }
 
        function feedItemAuthor( $row ) {
                return isset( $row->user_text ) ? $row->user_text : '';
        }
 
        function feedTitle() {
                global $wgLanguageCode, $wgSitename;
                $page = SpecialPage::getPage( $this->getName() );
                $desc = $page->getDescription();
                return "$wgSitename - $desc [$wgLanguageCode]";
        }
 
        function feedDesc() {
                return wfMsg( 'tagline' );
        }
 
        function feedUrl() {
                $title = Title::MakeTitle( NS_SPECIAL, $this->getName() );
                return $title->getFullURL();
        }
}
Personal tools
Namespaces
Variants
Actions
Site
Support
Download
Development
Communication
Print/export
Toolbox