RatingExtension/Source Code Dev
From PeacockWiki
(Difference between revisions)
| Revision as of 02:27, 31 July 2006 (edit) Trevorp (Talk | contribs) ← Previous diff |
Current revision (07:08, 1 August 2006) (edit) 137.166.81.96 (Talk) |
||
| Line 1: | Line 1: | ||
| <pre><?php | <pre><?php | ||
| + | |||
| + | ################################################################################ | ||
| + | # Setup # | ||
| + | ################################################################################ | ||
| + | # This section defines parameters of the plugin # | ||
| + | ################################################################################ | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Sets the minimum number of ratings that can be returned in a ratings tag # | ||
| + | # This helps keep performance for large wikis acceptable # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | $renderLimit=100; | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Sets the minimum number of ratings required for the rating to be valid # | ||
| + | # If the number of ratings are less, rating is 0 and bolded # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | $countLimit=3; | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Defines namespaces for which ratings are enabled # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | $allowedNamespaces=array( | ||
| + | 0=>true, //Default | ||
| + | 1=>true, //Talk | ||
| + | 2=>true, //User | ||
| + | 3=>true, //User_talk | ||
| + | 4=>true, //Project | ||
| + | 5=>true, //Project_talk | ||
| + | 6=>true, //Image | ||
| + | 7=>true, //Image_talk | ||
| + | # 8=>true, //MediaWiki | ||
| + | # 9=>true, //MediaWiki_talk | ||
| + | 10=>true, //Template | ||
| + | 11=>true, //Template_talk | ||
| + | 12=>true, //Help | ||
| + | 13=>true, //Help_talk | ||
| + | 14=>true, //Category | ||
| + | 15=>true //Category_talk | ||
| + | ); | ||
| ################################################################################ | ################################################################################ | ||
| Line 39: | Line 79: | ||
| #Record Rating | #Record Rating | ||
| #---------------- | #---------------- | ||
| + | $dbr =& wfGetDB( DB_WRITE ); | ||
| $sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) ". | $sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) ". | ||
| - | "VALUES (".$_GET['oldid'].", '". | + | "VALUES (".intval($_GET['oldid']).", '". |
| ($wgUser->getID()?$wgUser->getID():$wgUser->getName()). | ($wgUser->getID()?$wgUser->getID():$wgUser->getName()). | ||
| - | "', ".$_GET['rate'].")"; | + | "', ".intval($_GET['rate']).")"; |
| - | $dbr =& wfGetDB( DB_WRITE ); | + | |
| $res=wfQuery($sql, DB_WRITE, ""); | $res=wfQuery($sql, DB_WRITE, ""); | ||
| + | |||
| + | calculateRating($_GET['oldid']); | ||
| #Return to refering page and exit | #Return to refering page and exit | ||
| #---------------- | #---------------- | ||
| $wgTitle->invalidateCache(); | $wgTitle->invalidateCache(); | ||
| + | $dbr->immediateCommit(); | ||
| header( 'Location: '.$_SERVER["HTTP_REFERER"] ) ; | header( 'Location: '.$_SERVER["HTTP_REFERER"] ) ; | ||
| die(); | die(); | ||
| Line 59: | Line 102: | ||
| if(isset($wgScriptPath)) | if(isset($wgScriptPath)) | ||
| { | { | ||
| - | $wgExtensionCredits["parserhook"][]=array( | + | $wgExtensionCredits["parserhook"][]=array( |
| - | 'name' => 'Rating Extension', | + | 'name' => 'Rating Extension', |
| - | 'version' => '0.1', | + | 'version' => '0.3', |
| - | 'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension', | + | 'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension', |
| - | 'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]', | + | 'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]', |
| - | 'description' => 'Adds rating mechanism' ); | + | 'description' => 'Adds rating mechanism' ); |
| $wgHooks['OutputPageBeforeHTML'][] = 'InsertRating'; | $wgHooks['OutputPageBeforeHTML'][] = 'InsertRating'; | ||
| $wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss'; | $wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss'; | ||
| Line 78: | Line 121: | ||
| } | } | ||
| - | function renderWikiText($input, &$parser) | + | #------------------------------------------------------------------------------- |
| - | { | + | # Render the <rating> tag # |
| - | return $parser->parse($input, $parser->mTitle, $parser->mOptions, | + | # Shows the rating of the page specified by the text between the tags # |
| - | true, false)->getText(); | + | #------------------------------------------------------------------------------- |
| - | } | + | |
| - | + | ||
| - | function getRatingFromTitle($title) | + | |
| - | { | + | |
| - | $title=Title::newFromText($title); | + | |
| - | if($title==null) | + | |
| - | return "NoArticle"; | + | |
| - | $oldid=getOldID(new Article($title)); | + | |
| - | if(!$oldid) | + | |
| - | return "NoOldID"; | + | |
| - | return getRating($oldid); | + | |
| - | } | + | |
| - | + | ||
| function renderRating($input, $argv, &$parser) | function renderRating($input, $argv, &$parser) | ||
| { | { | ||
| - | $rating=getRatingFromTitle($input); | + | $rating=getRatingCache(getOldIDFromTitle(trim($input))); |
| - | return $rating['rating']; | + | return number_format($rating['rating'], 2); |
| } | } | ||
| + | #------------------------------------------------------------------------------- | ||
| + | # Render the <rating> tag # | ||
| + | # Shows the number of ratings of the page specified by the text between # | ||
| + | # the tags # | ||
| + | #------------------------------------------------------------------------------- | ||
| function renderRatingCount($input, $argv, &$parser) | function renderRatingCount($input, $argv, &$parser) | ||
| { | { | ||
| - | $rating=getRatingFromTitle($input); | + | $rating=getRatingCache(getOldIDFromTitle(trim($input))); |
| - | return $rating['count']; | + | return number_format($rating['count'], 2); |
| - | } | + | |
| - | + | ||
| - | function getPageList($namespace=false) | + | |
| - | { | + | |
| - | $sql="SELECT `page_title` AS `title`, `page_namespace` AS `namespace`, | + | |
| - | `page_latest` AS `oldid` FROM `page`". | + | |
| - | ($namespace===false?"":'WHERE `page_namespace` IN ('.$namespace.')').';'; | + | |
| - | return runQuery2($sql); | + | |
| - | } | + | |
| - | + | ||
| - | function getRatingList($namespace=false) | + | |
| - | { | + | |
| - | global $wgNamespaceNamesEn; | + | |
| - | $articles=getPageList($namespace); | + | |
| - | $ratings=array(); | + | |
| - | foreach($articles as $article) | + | |
| - | { | + | |
| - | $rating=getRating($article->oldid); | + | |
| - | $ratings[]=array('article' => $wgNamespaceNamesEn[$article->namespace]. | + | |
| - | ($article->namespace==0?'':':').$article->title, | + | |
| - | 'rating' => $rating['rating'], 'count' => $rating['count']); | + | |
| - | } | + | |
| - | return $ratings; | + | |
| } | } | ||
| + | #------------------------------------------------------------------------------- | ||
| + | # Displays a list of ratings based on the parameters given between the tags # | ||
| + | #------------------------------------------------------------------------------- | ||
| function renderRatings($input, $argv, &$parser) | function renderRatings($input, $argv, &$parser) | ||
| { | { | ||
| - | $ratings=getRatingList('0,1,2,3'); | + | $parameters=splitParameters($input); |
| + | $sortdata=getSortData(isset($parameters['namespace'])?$parameters['namespace']:array()); | ||
| + | $ratings=getRatingList( | ||
| + | isset($parameters['namespace'])?$parameters['namespace']:array(), $sortdata['column'], $sortdata['order'], isset($parameters['limit'])?$parameters['limit'][0]:10); | ||
| $output=''; | $output=''; | ||
| + | $displayCount=(isset($parameters['displaycount'])? | ||
| + | $parameters['displaycount'][0]:'false')!='false'; | ||
| + | $displayRating=(isset($parameters['displayrating'])? | ||
| + | $parameters['displayrating'][0]:'true')!='false'; | ||
| + | $pattern=isset($parameters['pattern'])?$parameters['pattern'][0]: | ||
| + | '[[$1|$2]]'.($displayRating?' ($3)':'').($displayCount?' ($4 ratings)':''); | ||
| + | $limit=isset($parameters['limit'])?$parameters['limit'][0]:10; | ||
| foreach($ratings as $rating) | foreach($ratings as $rating) | ||
| { | { | ||
| - | $output.=$rating['article'].' => '.$rating['rating']."\n\n"; | + | $output.=str_replace(array('$1', '$2', '$3', '$4', '$5'), |
| + | array($rating['title'], strtr($rating['title'], '_', ' '), | ||
| + | number_format($rating['rating'], 2), | ||
| + | $rating['count'], $rating['oldid']), $pattern)."\n\n"; | ||
| + | if(--$limit==0) break; | ||
| } | } | ||
| return renderWikiText(trim($output), $parser); | return renderWikiText(trim($output), $parser); | ||
| Line 145: | Line 174: | ||
| #------------------------------------------------------------------------------- | #------------------------------------------------------------------------------- | ||
| function InsertRating($parserOutput, $text) { | function InsertRating($parserOutput, $text) { | ||
| - | //TODO: Fix getOldID to get ALL articles (without revisions) | + | global $wgArticle, $allowedNamespaces; |
| - | //TODO: Limit by namespace | + | if(!$allowedNamespaces[$wgArticle->getTitle()->getNamespace()]) |
| - | global $wgArticle; | + | return; |
| $oldid=getOldID($wgArticle); | $oldid=getOldID($wgArticle); | ||
| if($oldid) | if($oldid) | ||
| $text='<div id="ratingsection">'. | $text='<div id="ratingsection">'. | ||
| - | getRatingHTML(getRating($oldid), $oldid).'</div>'.$text; | + | getRatingHTML(getRatingCache($oldid), $oldid).'</div>'.$text; |
| } | } | ||
| Line 170: | Line 199: | ||
| # These functions support the core functions of the extension # | # These functions support the core functions of the extension # | ||
| ################################################################################ | ################################################################################ | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Processes sortby parameters to determine how to sort ratings # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getSortData($sort) | ||
| + | { | ||
| + | $column='rating'; | ||
| + | $order=-1; | ||
| + | foreach($sort as $item) | ||
| + | { | ||
| + | switch($item) | ||
| + | { | ||
| + | case 'rating': | ||
| + | $column='rating'; break; | ||
| + | case 'name': | ||
| + | $column='title'; break; | ||
| + | case 'count': | ||
| + | $column='count'; break; | ||
| + | case 'ascending': | ||
| + | $order=SORT_ASC; break; | ||
| + | case 'descending': | ||
| + | $order=SORT_DESC; break; | ||
| + | } | ||
| + | } | ||
| + | if($order==-1) | ||
| + | { | ||
| + | switch($column) | ||
| + | { | ||
| + | case 'rating': | ||
| + | $order=SORT_DESC; break; | ||
| + | case 'title': | ||
| + | $order=SORT_ASC; break; | ||
| + | case 'count': | ||
| + | $order=SORT_DESC; break; | ||
| + | default: | ||
| + | $order=SORT_DESC; | ||
| + | } | ||
| + | } | ||
| + | return array('column'=>$column, 'order'=>$order); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Processes the given text using the mediawiki parser engine # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function renderWikiText($input, &$parser) | ||
| + | { | ||
| + | return $parser->parse($input, $parser->mTitle, $parser->mOptions, | ||
| + | false, false)->getText(); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Returns the page rating given the pages string title # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getOldIDFromTitle($title) | ||
| + | { | ||
| + | $title=Title::newFromText($title); | ||
| + | if($title==null) | ||
| + | { | ||
| + | echo "NoArticle"; | ||
| + | return 0; | ||
| + | } | ||
| + | $oldid=getOldID(new Article($title)); | ||
| + | if(!$oldid) | ||
| + | { | ||
| + | return "NoOldID"; | ||
| + | return 0; | ||
| + | } | ||
| + | return $oldid; | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Completes ratings_cache table for any revisions without ratings # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function doFillCache() | ||
| + | { | ||
| + | global $allowedNamespaces; | ||
| + | $namespacestring=''; | ||
| + | foreach(array_keys($allowedNamespaces) as $space) | ||
| + | { | ||
| + | if(is_numeric($space)) | ||
| + | { | ||
| + | $namespacestring.=', '.$space; | ||
| + | } | ||
| + | } | ||
| + | $namespacestring=substr($namespacestring, 2); | ||
| + | $sql="SELECT `page_latest` AS `oldid` FROM `page` WHERE".($filterByNamespace? | ||
| + | ' `page_namespace` IN ('.$namespacestring.') AND':"").' `page_latest` NOT IN (SELECT `page_oldid` FROM `ratings_cache`);'; | ||
| + | $articles=runQuery2($sql); | ||
| + | foreach($articles as $article) | ||
| + | getRating($article->oldid); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Returns a list of pages in the specified namespaces # | ||
| + | # Optionally it may return sorting rating information for results # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getPageList($namespace=array(), $ratings=false, $sort='title', $order=SORT_ASC, $limit=100) | ||
| + | { | ||
| + | global $renderLimit, $allowedNamespaces; | ||
| + | $limit=($limit>$renderLimit?$renderLimit:$limit); | ||
| + | $namespacestring=''; | ||
| + | $filterByNamespace=false; | ||
| + | foreach($namespace as $space) | ||
| + | { | ||
| + | if(is_numeric($space) && isset($allowedNamespaces[$space])) | ||
| + | { | ||
| + | $namespacestring.=', '.$space; | ||
| + | $filterByNamespace=true; | ||
| + | } | ||
| + | } | ||
| + | if($filterByNamespace) | ||
| + | $namespacestring=substr($namespacestring, 2); | ||
| + | $sql="SELECT `page_title` AS `title`, `page_namespace` AS `namespace`, | ||
| + | `page_latest` AS `oldid` FROM `page`".($filterByNamespace? | ||
| + | ' WHERE `page_namespace` IN ('.$namespacestring.')':"").';'; | ||
| + | if($ratings) | ||
| + | $sql="SELECT `page_title` AS `title`, `page_namespace` AS `namespace`, ". | ||
| + | "`page_latest` AS `oldid`, `page_oldid`, `page_rating` AS `rating`, `page_rating_count` AS `count` FROM `page`, `ratings_cache` WHERE `page_latest`=`page_oldid`".($filterByNamespace? | ||
| + | ' AND `page_namespace` IN ('.$namespacestring.')':""). | ||
| + | ' ORDER BY '.$sort.($order==SORT_ASC?'':'').($order==SORT_DESC?' DESC':'').' LIMIT '.$limit.';'; | ||
| + | return runQuery2($sql); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Returns a list of pages and their ratings for all pages in the specified # | ||
| + | # namespaces # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getRatingList($namespace=array(), $sort='title', $order=SORT_ASC, $limit=100) | ||
| + | { | ||
| + | global $wgNamespaceNamesEn, $renderLimit; | ||
| + | doFillCache(); | ||
| + | $limit=($limit>$renderLimit?$renderLimit:$limit); | ||
| + | $articles=getPageList($namespace, true, $sort, $order, $limit); | ||
| + | $ratings=array(); | ||
| + | foreach($articles as $article) | ||
| + | { | ||
| + | $rating=formatRating(array('count'=>$article->count, 'rating'=>$article->rating)); | ||
| + | $ratings[]=array('title' => $wgNamespaceNamesEn[$article->namespace]. | ||
| + | ($article->namespace==0?'':':').$article->title, | ||
| + | 'rating' => $rating['rating'], 'count' => $rating['count'], 'oldid'=>$article->oldid); | ||
| + | } | ||
| + | return $ratings; | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Splits parameters from the wikitext. # | ||
| + | # Each parameter should be on its own line in the format parameter = value # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function splitParameters($input) | ||
| + | { | ||
| + | $parameters=array(); | ||
| + | foreach(split("\n", $input) as $parameter) | ||
| + | { | ||
| + | $parameter=split('=', $parameter, 2); | ||
| + | if(count($parameter)==2) | ||
| + | { | ||
| + | foreach($parameter as $key => $val) | ||
| + | $parameter[$key]=trim($val); | ||
| + | if(isset($parameters[$parameter[0]])) | ||
| + | $parameters[$parameter[0]][]=$parameter[1]; | ||
| + | else | ||
| + | $parameters[$parameter[0]]=array($parameter[1]); | ||
| + | } | ||
| + | } | ||
| + | return $parameters; | ||
| + | } | ||
| #------------------------------------------------------------------------------- | #------------------------------------------------------------------------------- | ||
| Line 206: | Line 401: | ||
| return $oldid; | return $oldid; | ||
| $dbr =& wfGetDB( DB_SLAVE ); | $dbr =& wfGetDB( DB_SLAVE ); | ||
| - | $sql = "SELECT MAX(`rc_this_oldid`) AS `rc_this_oldid` FROM recentchanges ". | + | $sql="SELECT `page_latest` AS `oldid` FROM `page` ". |
| - | "WHERE rc_cur_id=".$article->getID().";"; | + | "WHERE `page_id`=".$article->getID().";"; |
| $res=wfQuery($sql, DB_SLAVE, ""); | $res=wfQuery($sql, DB_SLAVE, ""); | ||
| $row=$dbr->fetchObject( $res ); | $row=$dbr->fetchObject( $res ); | ||
| - | if($row->rc_this_oldid) | + | if($row->oldid) |
| - | return $row->rc_this_oldid; | + | return $row->oldid; |
| return null; | return null; | ||
| - | } | ||
| - | |||
| - | function getArticle($article) | ||
| - | { | ||
| - | $dbr =& wfGetDB( DB_SLAVE ); | ||
| - | $sql = "SELECT * FROM page ". | ||
| - | "WHERE page_title=\"".$article."\";"; | ||
| - | $res=wfQuery($sql, DB_SLAVE, ""); | ||
| - | $row=$dbr->fetchObject( $res ); | ||
| - | return $row; | ||
| } | } | ||
| Line 231: | Line 416: | ||
| { | { | ||
| $sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` ". | $sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` ". | ||
| - | "FROM ratings WHERE `page_oldid`=".$oldid." GROUP BY `page_oldid`;"; | + | "FROM ratings WHERE `page_oldid`=".intval($oldid)." GROUP BY `page_oldid`;"; |
| return runQuery($sql); | return runQuery($sql); | ||
| } | } | ||
| + | #------------------------------------------------------------------------------- | ||
| + | # Returns the ID for the revision before $revision # | ||
| + | #------------------------------------------------------------------------------- | ||
| function getPreviousRevisionID( $revision ) { | function getPreviousRevisionID( $revision ) { | ||
| $dbr =& wfGetDB( DB_SLAVE ); | $dbr =& wfGetDB( DB_SLAVE ); | ||
| Line 247: | Line 435: | ||
| # If there are not enough ratings for the current revivion, cycle # | # If there are not enough ratings for the current revivion, cycle # | ||
| # older revisions to gather a minimum number of ratings # | # older revisions to gather a minimum number of ratings # | ||
| + | # Updates cache table with calcaulated values # | ||
| #------------------------------------------------------------------------------- | #------------------------------------------------------------------------------- | ||
| - | function getRating($oldid) | + | function calculateRating($oldid) |
| { | { | ||
| - | global $wgTitle; | + | global $wgTitle, $countLimit; |
| - | + | $origid=$oldid; | |
| - | $countlimit=3; | + | |
| - | + | ||
| $ratingdata=getRatingData($oldid); | $ratingdata=getRatingData($oldid); | ||
| - | # var_dump($ratingdata); | ||
| $finalrating='?'; | $finalrating='?'; | ||
| $currentcount=number_format($ratingdata->count, 0); | $currentcount=number_format($ratingdata->count, 0); | ||
| #If there are not enough ratings for the current revision | #If there are not enough ratings for the current revision | ||
| - | if($rating->count<$countlimit) | + | if($ratingdata->count<$countLimit) |
| { | { | ||
| $count=$ratingdata->count; | $count=$ratingdata->count; | ||
| Line 268: | Line 454: | ||
| $ratingdata=getRatingData($oldid); | $ratingdata=getRatingData($oldid); | ||
| #If still not enough ratings | #If still not enough ratings | ||
| - | if($count+$ratingdata->count<$countlimit) | + | if($count+$ratingdata->count<$countLimit) |
| { | { | ||
| $count+=$ratingdata->count; | $count+=$ratingdata->count; | ||
| Line 275: | Line 461: | ||
| else #found enough ratings | else #found enough ratings | ||
| { | { | ||
| - | $rating+=($countlimit-$count)*$ratingdata->rating; | + | $rating+=($countLimit-$count)*$ratingdata->rating; |
| - | $count=$countlimit; | + | $count=$countLimit; |
| $finalrating=$rating/$count; | $finalrating=$rating/$count; | ||
| $oldid=false; | $oldid=false; | ||
| Line 283: | Line 469: | ||
| } | } | ||
| else | else | ||
| - | $finalrating=$rating/$count; | + | $finalrating=$ratingdata->rating; |
| + | $dbr =& wfGetDB( DB_WRITE ); | ||
| + | $sql = "REPLACE INTO `ratings_cache` (`page_oldid`, `page_rating`, ". | ||
| + | "`page_rating_count`) VALUES (".intval($origid).", ". | ||
| + | (is_numeric($finalrating)?$finalrating:0).", ".$currentcount.")"; | ||
| + | $res=wfQuery($sql, DB_WRITE, ""); | ||
| + | |||
| + | return array('rating'=>$finalrating, 'count'=>$currentcount); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Formats rating array for insertion to page rating section # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function formatRating($rating) | ||
| + | { | ||
| + | $finalrating=$rating['rating']; | ||
| + | $currentcount=$rating['count']; | ||
| + | |||
| #format rating data | #format rating data | ||
| - | if(is_numeric($finalrating)) | + | if(is_numeric($finalrating) && $finalrating>0) |
| $finalrating=($finalrating-1)*1.25; | $finalrating=($finalrating-1)*1.25; | ||
| $ratingarray=array('display'=> | $ratingarray=array('display'=> | ||
| Line 293: | Line 496: | ||
| 'count'=>$currentcount, | 'count'=>$currentcount, | ||
| 'rating'=>(is_numeric($finalrating)?$finalrating:0)); | 'rating'=>(is_numeric($finalrating)?$finalrating:0)); | ||
| - | # var_dump($ratingarray); | ||
| return $ratingarray; | return $ratingarray; | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Calculates rating from database for specified revision # | ||
| + | # Updates rating cache table # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getRating($oldid) | ||
| + | { | ||
| + | return formatRating(calculateRating($oldid)); | ||
| + | } | ||
| + | |||
| + | #------------------------------------------------------------------------------- | ||
| + | # Fetches the ratings from cache table # | ||
| + | # Calculates rating if it is not found in cache # | ||
| + | #------------------------------------------------------------------------------- | ||
| + | function getRatingCache($oldid) | ||
| + | { | ||
| + | $sql='SELECT * FROM `ratings_cache` WHERE `page_oldid`='.intval($oldid).';'; | ||
| + | $rating=runQuery($sql); | ||
| + | $rating=array('rating'=>$rating->page_rating, 'count'=>$rating->age_rating_count); | ||
| + | if($rating->page_oldid==null) | ||
| + | $rating=calculateRating($oldid); | ||
| + | return formatRating($rating); | ||
| } | } | ||
| Line 303: | Line 528: | ||
| function getRatingHTML($rating, $oldid) | function getRatingHTML($rating, $oldid) | ||
| { | { | ||
| - | global $wgTitle, $wgScriptPath; | + | global $wgTitle, $wgScriptPath, $countLimit; |
| - | $countlimit=3; | + | |
| $html=''; | $html=''; | ||
| #generate stars | #generate stars | ||
| Line 310: | Line 534: | ||
| { | { | ||
| $html.='<a href="'. | $html.='<a href="'. | ||
| - | $wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'">'. | + | $wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'" rel="nofollow">'. |
| - | '<img src="?file=star'; | + | '<img src="?file=Star'; |
| if($rating['rating']>=$x+1) #larger than current star : filled | if($rating['rating']>=$x+1) #larger than current star : filled | ||
| - | $html.='4'.($rating['count']<$countlimit?'b':''); | + | $html.='4'.($rating['count']<$countLimit?'b':''); |
| - | elseif($rating['rating']>$x+0.75) #3/4 current star : 3/4 filled | + | elseif($rating['rating']>=$x+0.75) #3/4 current star : 3/4 filled |
| - | $html.='3'.($rating['count']<$countlimit?'b':''); | + | $html.='3'.($rating['count']<$countLimit?'b':''); |
| - | elseif($rating['rating']>$x+0.5) #1/2 current star : 1/2 filled | + | elseif($rating['rating']>=$x+0.5) #1/2 current star : 1/2 filled |
| - | $html.='2'.($rating['count']<$countlimit?'b':''); | + | $html.='2'.($rating['count']<$countLimit?'b':''); |
| - | elseif($rating['rating']>$x+0.25) #1/4 current star : 1/4 filled | + | elseif($rating['rating']>=$x+0.25) #1/4 current star : 1/4 filled |
| - | $html.='1'.($rating['count']<$countlimit?'b':''); | + | $html.='1'.($rating['count']<$countLimit?'b':''); |
| else #less than current star : empty | else #less than current star : empty | ||
| $html.='0'; | $html.='0'; | ||
| Line 326: | Line 550: | ||
| #add text rating | #add text rating | ||
| $html.=' '.$rating['display'].''; | $html.=' '.$rating['display'].''; | ||
| - | $html=($rating['count']<$countlimit?'<b>'.$html.'</b>':$html); | + | $html=($rating['count']<$countLimit?'<b>'.$html.'</b>':$html); |
| return $html; | return $html; | ||
| } | } | ||
| Line 340: | Line 564: | ||
| { | { | ||
| #Star .png files | #Star .png files | ||
| - | case "star0.png": | + | case "Star0.png": |
| - | case "star1.png": | + | case "Star1.png": |
| - | case "star1b.png": | + | case "Star1b.png": |
| - | case "star2.png": | + | case "Star2.png": |
| - | case "star2b.png": | + | case "Star2b.png": |
| - | case "star3.png": | + | case "Star3.png": |
| - | case "star3b.png": | + | case "Star3b.png": |
| - | case "star4.png": | + | case "Star4.png": |
| - | case "star4b.png": | + | case "Star4b.png": |
| header("Content-type: image/png"); | header("Content-type: image/png"); | ||
| echo readFile('extensions/rating/'.$_GET['file']); | echo readFile('extensions/rating/'.$_GET['file']); | ||
Current revision
<?php
################################################################################
# Setup #
################################################################################
# This section defines parameters of the plugin #
################################################################################
#-------------------------------------------------------------------------------
# Sets the minimum number of ratings that can be returned in a ratings tag #
# This helps keep performance for large wikis acceptable #
#-------------------------------------------------------------------------------
$renderLimit=100;
#-------------------------------------------------------------------------------
# Sets the minimum number of ratings required for the rating to be valid #
# If the number of ratings are less, rating is 0 and bolded #
#-------------------------------------------------------------------------------
$countLimit=3;
#-------------------------------------------------------------------------------
# Defines namespaces for which ratings are enabled #
#-------------------------------------------------------------------------------
$allowedNamespaces=array(
0=>true, //Default
1=>true, //Talk
2=>true, //User
3=>true, //User_talk
4=>true, //Project
5=>true, //Project_talk
6=>true, //Image
7=>true, //Image_talk
# 8=>true, //MediaWiki
# 9=>true, //MediaWiki_talk
10=>true, //Template
11=>true, //Template_talk
12=>true, //Help
13=>true, //Help_talk
14=>true, //Category
15=>true //Category_talk
);
################################################################################
# Core Code #
################################################################################
# This section handles the core functions of this extension #
# * Serving Files #
# * Recording Ratings #
# * Displaying Ratings #
################################################################################
#-------------------------------------------------------------------------------
# If html request requests file, serve file #
# Files are requested by adding the ?file= GET parameter #
#-------------------------------------------------------------------------------
if(isset($_GET['file']))
doFile();
#-------------------------------------------------------------------------------
# If html request contains rate information, process it #
# Rating information indicated by ?rate= GET parameter #
# #
# MediaWiki engine is started by imitating the code in index.php #
# This ensures database functions are working #
#-------------------------------------------------------------------------------
if(isset($_GET['rate']))
{
#Init
#----------------
require_once( 'includes/Setup.php' );
require_once( "includes/Wiki.php" );
$mediaWiki = new MediaWiki();
$action = $wgRequest->getVal( 'action', 'view' );
$title = $wgRequest->getVal( 'title' );
$wgTitle = $mediaWiki->checkInitialQueries($title, $action, $wgOut,
$wgRequest, $wgContLang);
#Record Rating
#----------------
$dbr =& wfGetDB( DB_WRITE );
$sql = "REPLACE INTO `ratings` (`page_oldid`, `user_id`, `page_rating`) ".
"VALUES (".intval($_GET['oldid']).", '".
($wgUser->getID()?$wgUser->getID():$wgUser->getName()).
"', ".intval($_GET['rate']).")";
$res=wfQuery($sql, DB_WRITE, "");
calculateRating($_GET['oldid']);
#Return to refering page and exit
#----------------
$wgTitle->invalidateCache();
$dbr->immediateCommit();
header( 'Location: '.$_SERVER["HTTP_REFERER"] ) ;
die();
}
#-------------------------------------------------------------------------------
# Initialize extension #
# Sets up credit information, and hooks #
#-------------------------------------------------------------------------------
if(isset($wgScriptPath))
{
$wgExtensionCredits["parserhook"][]=array(
'name' => 'Rating Extension',
'version' => '0.3',
'url' => 'http://wiki.peacocktech.com/wiki/RatingExtension',
'author' => '[http://about.peacocktech.com/trevorp/ Trevor Peacock]',
'description' => 'Adds rating mechanism' );
$wgHooks['OutputPageBeforeHTML'][] = 'InsertRating';
$wgHooks['SkinTemplateSetupPageCss'][] = 'RatingCss';
$wgExtensionFunctions[] = "RatingExtension";
}
function RatingExtension()
{
global $wgParser;
$wgParser->setHook("rating", "renderRating");
$wgParser->setHook("ratingcount", "renderRatingCount");
$wgParser->setHook("ratings", "renderRatings");
}
#-------------------------------------------------------------------------------
# Render the <rating> tag #
# Shows the rating of the page specified by the text between the tags #
#-------------------------------------------------------------------------------
function renderRating($input, $argv, &$parser)
{
$rating=getRatingCache(getOldIDFromTitle(trim($input)));
return number_format($rating['rating'], 2);
}
#-------------------------------------------------------------------------------
# Render the <rating> tag #
# Shows the number of ratings of the page specified by the text between #
# the tags #
#-------------------------------------------------------------------------------
function renderRatingCount($input, $argv, &$parser)
{
$rating=getRatingCache(getOldIDFromTitle(trim($input)));
return number_format($rating['count'], 2);
}
#-------------------------------------------------------------------------------
# Displays a list of ratings based on the parameters given between the tags #
#-------------------------------------------------------------------------------
function renderRatings($input, $argv, &$parser)
{
$parameters=splitParameters($input);
$sortdata=getSortData(isset($parameters['namespace'])?$parameters['namespace']:array());
$ratings=getRatingList(
isset($parameters['namespace'])?$parameters['namespace']:array(), $sortdata['column'], $sortdata['order'], isset($parameters['limit'])?$parameters['limit'][0]:10);
$output='';
$displayCount=(isset($parameters['displaycount'])?
$parameters['displaycount'][0]:'false')!='false';
$displayRating=(isset($parameters['displayrating'])?
$parameters['displayrating'][0]:'true')!='false';
$pattern=isset($parameters['pattern'])?$parameters['pattern'][0]:
'[[$1|$2]]'.($displayRating?' ($3)':'').($displayCount?' ($4 ratings)':'');
$limit=isset($parameters['limit'])?$parameters['limit'][0]:10;
foreach($ratings as $rating)
{
$output.=str_replace(array('$1', '$2', '$3', '$4', '$5'),
array($rating['title'], strtr($rating['title'], '_', ' '),
number_format($rating['rating'], 2),
$rating['count'], $rating['oldid']), $pattern)."\n\n";
if(--$limit==0) break;
}
return renderWikiText(trim($output), $parser);
}
#-------------------------------------------------------------------------------
# Insert rating to top of page #
#-------------------------------------------------------------------------------
function InsertRating($parserOutput, $text) {
global $wgArticle, $allowedNamespaces;
if(!$allowedNamespaces[$wgArticle->getTitle()->getNamespace()])
return;
$oldid=getOldID($wgArticle);
if($oldid)
$text='<div id="ratingsection">'.
getRatingHTML(getRatingCache($oldid), $oldid).'</div>'.$text;
}
#-------------------------------------------------------------------------------
# Add CSS into skin for rating #
#-------------------------------------------------------------------------------
function RatingCss(&$css) {
global $wgScriptPath;
$css = "/*<![CDATA[*/".
" @import \"$wgScriptPath/?file=rating.css\"; ".
"/*]]>*/";
return true;
}
################################################################################
# Supporting Functions #
################################################################################
# These functions support the core functions of the extension #
################################################################################
#-------------------------------------------------------------------------------
# Processes sortby parameters to determine how to sort ratings #
#-------------------------------------------------------------------------------
function getSortData($sort)
{
$column='rating';
$order=-1;
foreach($sort as $item)
{
switch($item)
{
case 'rating':
$column='rating'; break;
case 'name':
$column='title'; break;
case 'count':
$column='count'; break;
case 'ascending':
$order=SORT_ASC; break;
case 'descending':
$order=SORT_DESC; break;
}
}
if($order==-1)
{
switch($column)
{
case 'rating':
$order=SORT_DESC; break;
case 'title':
$order=SORT_ASC; break;
case 'count':
$order=SORT_DESC; break;
default:
$order=SORT_DESC;
}
}
return array('column'=>$column, 'order'=>$order);
}
#-------------------------------------------------------------------------------
# Processes the given text using the mediawiki parser engine #
#-------------------------------------------------------------------------------
function renderWikiText($input, &$parser)
{
return $parser->parse($input, $parser->mTitle, $parser->mOptions,
false, false)->getText();
}
#-------------------------------------------------------------------------------
# Returns the page rating given the pages string title #
#-------------------------------------------------------------------------------
function getOldIDFromTitle($title)
{
$title=Title::newFromText($title);
if($title==null)
{
echo "NoArticle";
return 0;
}
$oldid=getOldID(new Article($title));
if(!$oldid)
{
return "NoOldID";
return 0;
}
return $oldid;
}
#-------------------------------------------------------------------------------
# Completes ratings_cache table for any revisions without ratings #
#-------------------------------------------------------------------------------
function doFillCache()
{
global $allowedNamespaces;
$namespacestring='';
foreach(array_keys($allowedNamespaces) as $space)
{
if(is_numeric($space))
{
$namespacestring.=', '.$space;
}
}
$namespacestring=substr($namespacestring, 2);
$sql="SELECT `page_latest` AS `oldid` FROM `page` WHERE".($filterByNamespace?
' `page_namespace` IN ('.$namespacestring.') AND':"").' `page_latest` NOT IN (SELECT `page_oldid` FROM `ratings_cache`);';
$articles=runQuery2($sql);
foreach($articles as $article)
getRating($article->oldid);
}
#-------------------------------------------------------------------------------
# Returns a list of pages in the specified namespaces #
# Optionally it may return sorting rating information for results #
#-------------------------------------------------------------------------------
function getPageList($namespace=array(), $ratings=false, $sort='title', $order=SORT_ASC, $limit=100)
{
global $renderLimit, $allowedNamespaces;
$limit=($limit>$renderLimit?$renderLimit:$limit);
$namespacestring='';
$filterByNamespace=false;
foreach($namespace as $space)
{
if(is_numeric($space) && isset($allowedNamespaces[$space]))
{
$namespacestring.=', '.$space;
$filterByNamespace=true;
}
}
if($filterByNamespace)
$namespacestring=substr($namespacestring, 2);
$sql="SELECT `page_title` AS `title`, `page_namespace` AS `namespace`,
`page_latest` AS `oldid` FROM `page`".($filterByNamespace?
' WHERE `page_namespace` IN ('.$namespacestring.')':"").';';
if($ratings)
$sql="SELECT `page_title` AS `title`, `page_namespace` AS `namespace`, ".
"`page_latest` AS `oldid`, `page_oldid`, `page_rating` AS `rating`, `page_rating_count` AS `count` FROM `page`, `ratings_cache` WHERE `page_latest`=`page_oldid`".($filterByNamespace?
' AND `page_namespace` IN ('.$namespacestring.')':"").
' ORDER BY '.$sort.($order==SORT_ASC?'':'').($order==SORT_DESC?' DESC':'').' LIMIT '.$limit.';';
return runQuery2($sql);
}
#-------------------------------------------------------------------------------
# Returns a list of pages and their ratings for all pages in the specified #
# namespaces #
#-------------------------------------------------------------------------------
function getRatingList($namespace=array(), $sort='title', $order=SORT_ASC, $limit=100)
{
global $wgNamespaceNamesEn, $renderLimit;
doFillCache();
$limit=($limit>$renderLimit?$renderLimit:$limit);
$articles=getPageList($namespace, true, $sort, $order, $limit);
$ratings=array();
foreach($articles as $article)
{
$rating=formatRating(array('count'=>$article->count, 'rating'=>$article->rating));
$ratings[]=array('title' => $wgNamespaceNamesEn[$article->namespace].
($article->namespace==0?'':':').$article->title,
'rating' => $rating['rating'], 'count' => $rating['count'], 'oldid'=>$article->oldid);
}
return $ratings;
}
#-------------------------------------------------------------------------------
# Splits parameters from the wikitext. #
# Each parameter should be on its own line in the format parameter = value #
#-------------------------------------------------------------------------------
function splitParameters($input)
{
$parameters=array();
foreach(split("\n", $input) as $parameter)
{
$parameter=split('=', $parameter, 2);
if(count($parameter)==2)
{
foreach($parameter as $key => $val)
$parameter[$key]=trim($val);
if(isset($parameters[$parameter[0]]))
$parameters[$parameter[0]][]=$parameter[1];
else
$parameters[$parameter[0]]=array($parameter[1]);
}
}
return $parameters;
}
#-------------------------------------------------------------------------------
# Use the mediawiki engine to run the given sql code and return an object #
# containing the first result of the query #
#-------------------------------------------------------------------------------
function runQuery($sql)
{
$dbr =& wfGetDB( DB_SLAVE );
$res=wfQuery($sql, DB_SLAVE, "");
if(wfNumRows($res)>0)
return $dbr->fetchObject( $res );
else
return null;
}
function runQuery2($sql)
{
$dbr =& wfGetDB( DB_SLAVE );
$res=wfQuery($sql, DB_SLAVE, "");
$array=array();
while($item=$dbr->fetchObject( $res ))
$array[]=$item;
return $array;
}
#-------------------------------------------------------------------------------
# Return the oldid of the current page #
# If oldid=0 (most current revision) take the latest oldid from the database #
# for the current article #
#-------------------------------------------------------------------------------
function getOldID($article)
{
$oldid=$article->getOldIDFromRequest();
if($oldid!=0)
return $oldid;
$dbr =& wfGetDB( DB_SLAVE );
$sql="SELECT `page_latest` AS `oldid` FROM `page` ".
"WHERE `page_id`=".$article->getID().";";
$res=wfQuery($sql, DB_SLAVE, "");
$row=$dbr->fetchObject( $res );
if($row->oldid)
return $row->oldid;
return null;
}
#-------------------------------------------------------------------------------
# Performs a SQL query to fetch a rating for page oldid #
#-------------------------------------------------------------------------------
function getRatingData($oldid)
{
$sql="SELECT COUNT(*) AS `count`, AVG(`page_rating`) AS `rating` ".
"FROM ratings WHERE `page_oldid`=".intval($oldid)." GROUP BY `page_oldid`;";
return runQuery($sql);
}
#-------------------------------------------------------------------------------
# Returns the ID for the revision before $revision #
#-------------------------------------------------------------------------------
function getPreviousRevisionID( $revision ) {
$dbr =& wfGetDB( DB_SLAVE );
return $dbr->selectField( 'revision', 'rev_id',
'rev_page=(SELECT `rev_page` from `revision` WHERE `rev_id`='.
intval( $revision ).')'.' AND rev_id<' . intval( $revision ) .
' ORDER BY rev_id DESC' );
}
#-------------------------------------------------------------------------------
# Fetch and calculate a rating for page oldid #
# If there are not enough ratings for the current revivion, cycle #
# older revisions to gather a minimum number of ratings #
# Updates cache table with calcaulated values #
#-------------------------------------------------------------------------------
function calculateRating($oldid)
{
global $wgTitle, $countLimit;
$origid=$oldid;
$ratingdata=getRatingData($oldid);
$finalrating='?';
$currentcount=number_format($ratingdata->count, 0);
#If there are not enough ratings for the current revision
if($ratingdata->count<$countLimit)
{
$count=$ratingdata->count;
$rating=$count*$ratingdata->rating;
#cycle older revisions looking for more ratings
while($oldid=getPreviousRevisionID($oldid))
{
$ratingdata=getRatingData($oldid);
#If still not enough ratings
if($count+$ratingdata->count<$countLimit)
{
$count+=$ratingdata->count;
$rating+=$ratingdata->count*$ratingdata->rating;
}
else #found enough ratings
{
$rating+=($countLimit-$count)*$ratingdata->rating;
$count=$countLimit;
$finalrating=$rating/$count;
$oldid=false;
}
}
}
else
$finalrating=$ratingdata->rating;
$dbr =& wfGetDB( DB_WRITE );
$sql = "REPLACE INTO `ratings_cache` (`page_oldid`, `page_rating`, ".
"`page_rating_count`) VALUES (".intval($origid).", ".
(is_numeric($finalrating)?$finalrating:0).", ".$currentcount.")";
$res=wfQuery($sql, DB_WRITE, "");
return array('rating'=>$finalrating, 'count'=>$currentcount);
}
#-------------------------------------------------------------------------------
# Formats rating array for insertion to page rating section #
#-------------------------------------------------------------------------------
function formatRating($rating)
{
$finalrating=$rating['rating'];
$currentcount=$rating['count'];
#format rating data
if(is_numeric($finalrating) && $finalrating>0)
$finalrating=($finalrating-1)*1.25;
$ratingarray=array('display'=>
(is_numeric($finalrating)?number_format($finalrating, 2):$finalrating).
" ($currentcount ratings)",
'count'=>$currentcount,
'rating'=>(is_numeric($finalrating)?$finalrating:0));
return $ratingarray;
}
#-------------------------------------------------------------------------------
# Calculates rating from database for specified revision #
# Updates rating cache table #
#-------------------------------------------------------------------------------
function getRating($oldid)
{
return formatRating(calculateRating($oldid));
}
#-------------------------------------------------------------------------------
# Fetches the ratings from cache table #
# Calculates rating if it is not found in cache #
#-------------------------------------------------------------------------------
function getRatingCache($oldid)
{
$sql='SELECT * FROM `ratings_cache` WHERE `page_oldid`='.intval($oldid).';';
$rating=runQuery($sql);
$rating=array('rating'=>$rating->page_rating, 'count'=>$rating->age_rating_count);
if($rating->page_oldid==null)
$rating=calculateRating($oldid);
return formatRating($rating);
}
#-------------------------------------------------------------------------------
# Given the rating array and the page oldid, generate HTML code to be #
# displayed #
#-------------------------------------------------------------------------------
function getRatingHTML($rating, $oldid)
{
global $wgTitle, $wgScriptPath, $countLimit;
$html='';
#generate stars
for($x=0;$x<=4;$x++)
{
$html.='<a href="'.
$wgTitle->getFullURL('oldid='.$oldid.'&rate='.($x+1)).'" rel="nofollow">'.
'<img src="?file=Star';
if($rating['rating']>=$x+1) #larger than current star : filled
$html.='4'.($rating['count']<$countLimit?'b':'');
elseif($rating['rating']>=$x+0.75) #3/4 current star : 3/4 filled
$html.='3'.($rating['count']<$countLimit?'b':'');
elseif($rating['rating']>=$x+0.5) #1/2 current star : 1/2 filled
$html.='2'.($rating['count']<$countLimit?'b':'');
elseif($rating['rating']>=$x+0.25) #1/4 current star : 1/4 filled
$html.='1'.($rating['count']<$countLimit?'b':'');
else #less than current star : empty
$html.='0';
$html.='.png" align=bottom/></a>'."\n";
}
#add text rating
$html.=' '.$rating['display'].'';
$html=($rating['count']<$countLimit?'<b>'.$html.'</b>':$html);
return $html;
}
#-------------------------------------------------------------------------------
# Return a file and exit. #
# File determined by ?file= GET parameter #
#-------------------------------------------------------------------------------
function doFile()
{
switch ($_GET['file'])
{
#Star .png files
case "Star0.png":
case "Star1.png":
case "Star1b.png":
case "Star2.png":
case "Star2b.png":
case "Star3.png":
case "Star3b.png":
case "Star4.png":
case "Star4b.png":
header("Content-type: image/png");
echo readFile('extensions/rating/'.$_GET['file']);
die();
#extension css styling
case "rating.css":
header("Content-type: text/css");
?>
#ratingsection {
float: right;
margin-top: -3.7em;
padding: 3px;
}
#ratingsection b {
color: red;
padding: 4px;
}
<?php
die();
}
}
?>
