Needs configurability, purty graphs, and some cleanup in the back-end.
$acchitsTable = $dbw->tableName( 'acchits' );
if( $wgHitcounterUpdateFreq <= 1 ) {
- $dbw->query( "UPDATE $pageTable SET page_counter = page_counter + 1 WHERE page_id = $id" );
+ self::incrementCounterByValue( $id, 1 );
return;
}
+
+ ## TODO: Will get to making this stuff use the new infrastructure.
# Not important enough to warrant an error page in case of failure
$oldignore = $dbw->ignoreErrors( true );
}
$dbw->ignoreErrors( $oldignore );
}
+
+ static function incrementCounterByValue( $article_id, $number ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbr = wfGetDB( DB_SLAVE );
+ $oldIgnore = $dbw->ignoreErrors( true );
+
+ ## Does a row already exist?
+ ## We really need ON DUPLICATE KEY UPDATE :(
+ $startOfToday = $dbw->timestamp( strtotime( '0:00' ) ); // Hack hack hack
+ $endOfToday = $dbw->timestamp( strtotime( '0:00 tomorrow' ) );
+ $rowExists = $dbr->selectField( 'hit_statistics', '1', array( 'hs_page' => $article_id, "hs_period_start='$startOfToday'", "hs_period_end='$endOfToday'" ), __METHOD__ );
+
+ if ($rowExists) {
+ $dbw->update( 'hit_statistics', array( 'hs_count=hs_count+'.intval($number) ), array( 'hs_page' => $article_id, 'hs_period_start' => $startOfToday, 'hs_period_end' => $endOfToday ), __METHOD__ );
+ } else {
+ $row = array(
+ 'hs_page' => $article_id,
+ 'hs_period_start' => $startOfToday,
+ 'hs_period_end' => $endOfToday,
+ 'hs_period_length' => 86400, // One day.
+ 'hs_count' => $number
+ );
+
+ $dbw->insert( 'hit_statistics', $row, __METHOD__ );
+
+ ## Update with the previous day's hits...
+ Article::updatePageRowCounter( $article_id );
+ }
+
+ $dbw->ignoreErrors( false );
+ }
+
+ static function updatePageRowCounter( $article_id ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $oi = $dbw->ignoreErrors( true );
+
+ $total = $dbw->selectField( 'hit_statistics', 'sum(hs_count)', array( 'hs_page' => $article_id ), __METHOD__ );
+ $dbw->update( 'page', array( 'page_counter' => $total ), array( 'page_id' => $article_id ), __METHOD__ );
+
+ $dbw->ignoreErrors( $oi );
+ }
/**#@+
* The onArticle*() functions are supposed to be a kind of hooks
'PageArchive' => 'includes/specials/SpecialUndelete.php',
'PasswordResetForm' => 'includes/specials/SpecialResetpass.php',
'PopularPagesPage' => 'includes/specials/SpecialPopularpages.php',
+ 'SpecialPageStatistics' => 'includes/specials/SpecialPageStatistics.php',
'PreferencesForm' => 'includes/specials/SpecialPreferences.php',
'RandomPage' => 'includes/specials/SpecialRandompage.php',
'RevisionDeleteForm' => 'includes/specials/SpecialRevisiondelete.php',
);
wfRunHooks( 'wgQueryPages', array( &$wgQueryPages ) );
+## Maybe this can be re-enabled with the new hit-counting infrastructure??
global $wgDisableCounters;
if ( !$wgDisableCounters )
$wgQueryPages[] = array( 'PopularPagesPage', 'Popularpages' );
if ( 0 == $wgArticle->getID() ) { return ''; }
$s = '';
- if ( !$wgDisableCounters ) {
- $count = $wgLang->formatNum( $wgArticle->getCount() );
- if ( $count ) {
- $s = wfMsgExt( 'viewcount', array( 'parseinline' ), $count );
- }
+ $count = $wgArticle->getCount();
+ if ( $count ) {
+ $count = $wgLang->formatNum( $count );
+ $s = wfMsgExt( 'viewcount', array( 'parseinline' ), $count );
}
if( $wgMaxCredits != 0 ){
global $wgScript, $wgStylePath, $wgContLanguageCode;
global $wgMimeType, $wgJsMimeType, $wgOutputEncoding, $wgRequest;
global $wgXhtmlDefaultNamespace, $wgXhtmlNamespaces;
- global $wgDisableCounters, $wgLogo, $action, $wgFeedClasses, $wgHideInterlanguageLinks;
+ global $wgLogo, $action, $wgFeedClasses, $wgHideInterlanguageLinks;
global $wgMaxCredits, $wgShowCreditsIfMax;
global $wgPageShowWatchingUsers;
global $wgUseTrackbacks, $wgUseSiteJs;
if ( $out->isArticle() and (!isset( $oldid ) or isset( $diff )) and
$wgArticle and 0 != $wgArticle->getID() )
{
- if ( !$wgDisableCounters ) {
- $viewcount = $wgLang->formatNum( $wgArticle->getCount() );
+ $count = $wgArticle->getCount();
+
+ if ( $count ) {
+ $viewcount = $wgLang->formatNum( $count );
if ( $viewcount ) {
$tpl->set('viewcount', wfMsgExt( 'viewcount', array( 'parseinline' ), $viewcount ) );
} else {
'Randomredirect' => 'SpecialRandomredirect',
'Withoutinterwiki' => array( 'SpecialPage', 'Withoutinterwiki' ),
'Filepath' => array( 'SpecialPage', 'Filepath' ),
+ 'PageStatistics' => 'SpecialPageStatistics',
'Mypage' => array( 'SpecialMypage' ),
'Mytalk' => array( 'SpecialMytalk' ),
--- /dev/null
+<?php
+if (!defined('MEDIAWIKI'))
+ die();
+
+class SpecialPageStatistics extends SpecialPage {
+ function __construct() {
+ parent::__construct( 'PageStatistics' );
+ }
+
+ function execute( $subpage ) {
+ global $wgOut;
+
+ $wgOut->setPageTitle( wfMsg( 'pagestatistics' ) );
+ $wgOut->setRobotPolicy( "noindex,nofollow" );
+ $wgOut->setArticleRelated( false );
+ $wgOut->enableClientCache( false );
+
+ $this->setHeaders();
+ $this->loadParameters( $subpage );
+
+ if ($this->page) {
+ $this->showStatistics( );
+ } else {
+ $this->showMain();
+ }
+
+
+ }
+
+ function loadParameters( $subpage ) {
+ global $wgRequest;
+
+ $this->page = $subpage;
+ $this->periodStart = $wgRequest->getVal( 'periodstart' );
+ $this->periodEnd = $wgRequest->getVal( 'periodend' );
+
+ if ($p = $wgRequest->getVal( 'target' ) )
+ $this->page = $p;
+ }
+
+ function showSearchBox( ) {
+ global $wgOut;
+
+ $fields = array();
+ $fields['pagestatistics-page'] = Xml::input( 'target', 45, $this->page );
+ $fields['pagestatistics-periodstart'] = Xml::input( 'periodstart', 45, $this->periodStart );
+ $fields['pagestatistics-periodend'] = Xml::input( 'periodend', 45, $this->periodEnd );
+
+ $form = Xml::buildForm( $fields, 'pagestatistics-search' );
+ $form .= Xml::hidden( 'title', $this->getTitle()->getPrefixedText() );
+ $form = Xml::tags( 'form', array( 'method' => 'GET', 'action' => $this->getTitle()->getFullURL() ), $form );
+ $form = Xml::fieldset( wfMsgExt( 'pagestatistics-search-legend', 'parseinline' ), $form );
+
+ $wgOut->addHTML( $form );
+ }
+
+ function showMain() {
+ global $wgUser, $wgOut;
+
+ $sk = $wgUser->getSkin();
+
+ ## Create initial intro
+ $wgOut->addWikiMsg( 'pagestatistics-intro' );
+
+ ## Fieldset with search stuff
+ $this->showSearchBox( );
+ }
+
+ function showStatistics() {
+ global $wgLang, $wgOut;
+
+ $this->showSearchBox();
+
+ ## For now, just a data table.
+ $dbr = wfGetDB( DB_SLAVE );
+
+ $article = new Article( Title::newFromText( $this->page ) );
+
+ $periodStart = $dbr->addQuotes( $dbr->timestamp( strtotime( $this->periodStart ) ) );
+ $periodEnd = $dbr->addQuotes( $dbr->timestamp( strtotime( $this->periodEnd ) ) );
+
+ $res = $dbr->select( 'hit_statistics', '*', array( "hs_period_start>=$periodStart", "hs_period_end<=$periodEnd", 'hs_page' => $article->getId() ), __METHOD__ );
+
+ $html = Xml::tags( 'th', null, wfMsgExt( 'pagestatistics-datatable-periodstart', 'parseinline' ) );
+ $html .= Xml::tags( 'th', null, wfMsgExt( 'pagestatistics-datatable-periodend', 'parseinline' ) );
+ $html .= Xml::tags( 'th', null, wfMsgExt( 'pagestatistics-datatable-count', 'parseinline' ) );
+ $html = Xml::tags( 'tr', null, $html );
+
+ $total = 0;
+ $data = array();
+ while( $row = $dbr->fetchObject( $res ) ) {
+ $thisData = array(
+ 'count' => $row->hs_count,
+ 'start' => $row->hs_period_start,
+ 'end' => $row->hs_period_end,
+ );
+ $data[] = $thisData;
+
+ $total += $row->hs_count;
+
+ $thisRow = Xml::tags( 'td', null, $wgLang->timeanddate( $row->hs_period_start ) );
+ $thisRow .= Xml::tags('td', null, $wgLang->timeanddate( $row->hs_period_end ) );
+ $thisRow .= Xml::tags('td', null, $row->hs_count );
+ $thisRow = Xml::tags( 'tr', null, $thisRow );
+
+ $html .= "$thisRow\n";
+ }
+
+ ## Rollup total row
+ $totalLabel = Xml::tags( 'strong', null, wfMsgExt( 'pagestatistics-datatable-total', 'parseinline' ) );
+ $thisRow = Xml::tags( 'td', null, $totalLabel );
+ $thisRow .= Xml::tags('td', null, $totalLabel );
+ $thisRow .= Xml::tags('td', null, $total );
+ $thisRow = Xml::tags( 'tr', null, $thisRow );
+
+ $html .= "$thisRow\n";
+
+ $html = Xml::tags( 'table', null, Xml::tags( 'tbody', null, $html ) );
+ $wgOut->addHTML( $html );
+
+ $wgOut->addWikitext( 'Purty graph goes here' );
+
+ ## TODO purty graph :)
+ }
+}
\ No newline at end of file
$numJobs = SiteStats::jobs();
# Staticic - views
+ ## Maybe re-enablable with new hitcounter infrastructure, plus more goodies like newly popular pages.
$viewsStats = '';
if( !$wgDisableCounters ) {
$viewsStats = Xml::tags( 'th', array( 'colspan' => '2' ), wfMsg( 'statistics-header-views' ) ) .
'fileduplicatesearch-result-1' => 'The file "$1" has no identical duplication.',
'fileduplicatesearch-result-n' => 'The file "$1" has {{PLURAL:$2|1 identical duplication|$2 identical duplications}}.',
+## Special:PageStatistics
+'pagestatistics' => 'Page statistics',
+'pagestatistics-intro' => 'This page allows you to search page-view statistics for given pages on the wiki.',
+'pagestatistics-search-legend' => 'Search for statistics',
+'pagestatistics-page' => 'Page:',
+'pagestatistics-periodstart' => 'Start of period:',
+'pagestatistics-periodend' => 'End of period:',
+'pagestatistics-search' => 'Search',
+'pagestatistics-datatable-periodstart' => 'Start of period',
+'pagestatistics-datatable-periodend' => 'End of period',
+'pagestatistics-datatable-count' => 'Count',
+'pagestatistics-datatable-total' => 'Total',
+
# Special:SpecialPages
'specialpages' => 'Special pages',
'specialpages-summary' => '', # do not translate or duplicate this message to other languages
--- /dev/null
+-- Creates the hit_statistics table, for storing, as the name implies, hit statistics.
+
+CREATE TABLE /*$wgDBprefix*/hit_statistics (
+ hs_page bigint(20) NOT NULL, -- Maybe this should be a namespace/title tuple instead.
+ hs_period_start binary(14) NOT NULL,
+ hs_period_end binary(14) NOT NULL,
+ hs_period_length bigint(20) NOT NULL,
+ hs_count bigint(20) NOT NULL,
+
+ PRIMARY KEY (hs_page,hs_period_start),
+ KEY hs_period_start (hs_period_start),
+ KEY hs_period_length (hs_period_length),
+ KEY hs_count (hs_count)
+) /*$wgDBTableOptions*/;
\ No newline at end of file