X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FQueryPage.php;h=827264be8e5fc5037d7f4279c3f63be8f0e7974f;hb=44a950288a78c7cb89286271c068c2578865e0b3;hp=409a9c4bb4ac2682be6c5133cbf4a7fdeebe2850;hpb=06278e5bcfd591bb975c8ffe8efb39f1fcd0da67;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/QueryPage.php b/includes/QueryPage.php index 409a9c4bb4..827264be8e 100644 --- a/includes/QueryPage.php +++ b/includes/QueryPage.php @@ -1,13 +1,15 @@ listoutput; * - * @param bool $bool + * @param $bool Boolean */ function setListoutput( $bool ) { $this->listoutput = $bool; @@ -82,6 +89,8 @@ class QueryPage { * Subclasses return their name here. Make sure the name is also * specified in SpecialPage.php and in Language.php as a language message * param. + * + * @return String */ function getName() { return ''; @@ -117,6 +126,8 @@ class QueryPage { /** * Override to sort by increasing values + * + * @return Boolean */ function sortDescending() { return true; @@ -131,8 +142,10 @@ class QueryPage { * Is this query expensive (for some definition of expensive)? Then we * don't let it run in miser mode. $wgDisableQueryPages causes all query * pages to be declared expensive. Some query pages are always expensive. + * + * @return Boolean */ - function isExpensive( ) { + function isExpensive() { global $wgDisableQueryPages; return $wgDisableQueryPages; } @@ -141,7 +154,7 @@ class QueryPage { * Whether or not the output of the page in question is retrived from * the database cache. * - * @return bool + * @return Boolean */ function isCached() { global $wgMiserMode; @@ -151,6 +164,8 @@ class QueryPage { /** * Sometime we dont want to build rss / atom feeds. + * + * @return Boolean */ function isSyndicated() { return true; @@ -161,6 +176,9 @@ class QueryPage { * 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. + * + * @param $skin Skin object + * @param $result Object: database row */ function formatResult( $skin, $result ) { return ''; @@ -168,8 +186,10 @@ class QueryPage { /** * The content returned by this function will be output before any result + * + * @return String */ - function getPageHeader( ) { + function getPageHeader() { return ''; } @@ -177,7 +197,8 @@ class QueryPage { * 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 + * + * @return Array */ function linkParameters() { return array(); @@ -189,17 +210,20 @@ class QueryPage { * 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( ) { + function tryLastResult() { return false; } /** * Clear the cache and save new results + * + * @param $limit Integer: limit for SQL statement + * @param $ignoreErrors Boolean: whether to ignore database errors */ function recache( $limit, $ignoreErrors = true ) { - $fname = get_class($this) . '::recache'; + $fname = get_class( $this ) . '::recache'; $dbw = wfGetDB( DB_MASTER ); - $dbr = wfGetDB( DB_SLAVE, array( $this->getName(), 'QueryPage::recache', 'vslow' ) ); + $dbr = wfGetDB( DB_SLAVE, array( $this->getName(), __METHOD__, 'vslow' ) ); if ( !$dbw || !$dbr ) { return false; } @@ -215,37 +239,30 @@ class QueryPage { $dbw->delete( 'querycache', array( 'qc_type' => $this->getName() ), $fname ); # Do query $sql = $this->getSQL() . $this->getOrder(); - if ($limit !== false) - $sql = $dbr->limitResult($sql, $limit, 0); - $res = $dbr->query($sql, $fname); + 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; + $vals = array(); while ( $res && $row = $dbr->fetchObject( $res ) ) { - if ( $first ) { - $first = false; - } else { - $insertSql .= ','; - } if ( isset( $row->value ) ) { - $value = $row->value; + $value = intval( $row->value ); // @bug 14414 } else { - $value = ''; + $value = 0; } - - $insertSql .= '(' . - $dbw->addQuotes( $row->type ) . ',' . - $dbw->addQuotes( $row->namespace ) . ',' . - $dbw->addQuotes( $row->title ) . ',' . - $dbw->addQuotes( $value ) . ')'; + + $vals[] = array('qc_type' => $row->type, + 'qc_namespace' => $row->namespace, + 'qc_title' => $row->title, + 'qc_value' => $value); } # Save results into the querycache table on the master - if ( !$first ) { - if ( !$dbw->query( $insertSql, $fname ) ) { + if ( count( $vals ) ) { + if ( !$dbw->insert( 'querycache', $vals, __METHOD__ ) ) { // Set result to false to indicate error $dbr->freeResult( $res ); $res = false; @@ -302,25 +319,25 @@ class QueryPage { # 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 ); + $updated = $wgLang->timeanddate( $tRow->qci_timestamp, true, true ); + $updateddate = $wgLang->date( $tRow->qci_timestamp, true, true ); + $updatedtime = $wgLang->time( $tRow->qci_timestamp, true, true ); $wgOut->addMeta( 'Data-Cache-Time', $tRow->qci_timestamp ); - $wgOut->addScript( '' ); + $wgOut->addInlineScript( "var dataCacheTime = '{$tRow->qci_timestamp}';" ); + $wgOut->addWikiMsg( 'perfcachedts', $updated, $updateddate, $updatedtime ); } else { - $cacheNotice = wfMsg( 'perfcached' ); + $wgOut->addWikiMsg( 'perfcached' ); } - - $wgOut->addWikiText( $cacheNotice ); - + # If updates on this page have been disabled, let the user know # that the data set won't be refreshed for now global $wgDisableQueryPageUpdate; if( is_array( $wgDisableQueryPageUpdate ) && in_array( $this->getName(), $wgDisableQueryPageUpdate ) ) { - $wgOut->addWikiText( wfMsg( 'querypage-no-updates' ) ); + $wgOut->addWikiMsg( 'querypage-no-updates' ); } - + } } @@ -331,25 +348,27 @@ class QueryPage { $num = $dbr->numRows($res); $this->preprocessResults( $dbr, $res ); - $sk = $wgUser->getSkin(); - + + $wgOut->addHTML( XML::openElement( 'div', array('class' => 'mw-spcontent') ) ); + # Top header and navigation if( $shownavigation ) { - $wgOut->addHtml( $this->getPageHeader() ); + $wgOut->addHTML( $this->getPageHeader() ); if( $num > 0 ) { - $wgOut->addHtml( '

' . wfShowingResults( $offset, $num ) . '

' ); + $wgOut->addHTML( '

' . wfShowingResults( $offset, $num ) . '

' ); # Disable the "next" link when we reach the end $paging = wfViewPrevNext( $offset, $limit, $wgContLang->specialPage( $sname ), wfArrayToCGI( $this->linkParameters() ), ( $num < $limit ) ); - $wgOut->addHtml( '

' . $paging . '

' ); + $wgOut->addHTML( '

' . $paging . '

' ); } else { # No results to show, so don't bother with "showing X of Y" etc. # -- just let the user know and give up now - $wgOut->addHtml( '

' . wfMsgHtml( 'specialpage-empty' ) . '

' ); + $wgOut->addHTML( '

' . wfMsgHtml( 'specialpage-empty' ) . '

' ); + $wgOut->addHTML( XML::closeElement( 'div' ) ); return; } } - + # The actual results; specialist subclasses will want to handle this # with more than a straight list, so we hand them the info, plus # an OutputPage, and let them get on with it @@ -362,89 +381,101 @@ class QueryPage { # Repeat the paging links at the bottom if( $shownavigation ) { - $wgOut->addHtml( '

' . $paging . '

' ); + $wgOut->addHTML( '

' . $paging . '

' ); } - + + $wgOut->addHTML( XML::closeElement( 'div' ) ); + return $num; } - + /** * Format and output report results using the given information plus * OutputPage * - * @param OutputPage $out OutputPage to print to - * @param Skin $skin User skin to use - * @param Database $dbr Database (read) connection to use - * @param int $res Result pointer - * @param int $num Number of available result rows - * @param int $offset Paging offset + * @param $out OutputPage to print to + * @param $skin Skin: user skin to use + * @param $dbr Database (read) connection to use + * @param $res Integer: result pointer + * @param $num Integer: number of available result rows + * @param $offset Integer: paging offset */ protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) { global $wgContLang; - + if( $num > 0 ) { $html = array(); if( !$this->listoutput ) $html[] = $this->openList( $offset ); - + # $res might contain the whole 1,000 rows, so we read up to # $num [should update this to use a Pager] for( $i = 0; $i < $num && $row = $dbr->fetchObject( $res ); $i++ ) { $line = $this->formatResult( $skin, $row ); if( $line ) { - $attr = ( isset( $obj->usepatrol ) && $obj->usepatrol && $obj->patrolled == 0 ) + $attr = ( isset( $row->usepatrol ) && $row->usepatrol && $row->patrolled == 0 ) ? ' class="not-patrolled"' : ''; $html[] = $this->listoutput - ? $format + ? $line : "{$line}\n"; } } - + # Flush the final result if( $this->tryLastResult() ) { $row = null; $line = $this->formatResult( $skin, $row ); if( $line ) { - $attr = ( isset( $obj->usepatrol ) && $obj->usepatrol && $obj->patrolled == 0 ) + $attr = ( isset( $row->usepatrol ) && $row->usepatrol && $row->patrolled == 0 ) ? ' class="not-patrolled"' : ''; $html[] = $this->listoutput - ? $format + ? $line : "{$line}\n"; } } - + if( !$this->listoutput ) $html[] = $this->closeList(); - + $html = $this->listoutput ? $wgContLang->listToText( $html ) : implode( '', $html ); - - $out->addHtml( $html ); + + $out->addHTML( $html ); } } - + function openList( $offset ) { - return "
    "; + return "\n
      \n"; } - + function closeList() { - return '
    '; + return "
\n"; } /** * Do any necessary preprocessing of the result object. - * You should pass this by reference: &$db , &$res [although probably no longer necessary in PHP5] */ - function preprocessResults( &$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; + global $wgFeed, $wgFeedClasses; + + if ( !$wgFeed ) { + global $wgOut; + $wgOut->addWikiMsg( 'feed-unavailable' ); + return; + } + + global $wgFeedLimit; + if( $limit > $wgFeedLimit ) { + $limit = $wgFeedLimit; + } if( isset($wgFeedClasses[$class]) ) { $feed = new $wgFeedClasses[$class]( @@ -476,7 +507,7 @@ class QueryPage { */ function feedResult( $row ) { if( !isset( $row->title ) ) { - return NULL; + return null; } $title = Title::MakeTitle( intval( $row->namespace ), $row->title ); if( $title ) { @@ -495,7 +526,7 @@ class QueryPage { $this->feedItemAuthor( $row ), $comments); } else { - return NULL; + return null; } } @@ -515,7 +546,7 @@ class QueryPage { } function feedDesc() { - return wfMsg( 'tagline' ); + return wfMsgExt( 'tagline', 'parsemag' ); } function feedUrl() { @@ -524,4 +555,84 @@ class QueryPage { } } -?> \ No newline at end of file +/** + * Class definition for a wanted query page like + * WantedPages, WantedTemplates, etc + */ +abstract class WantedQueryPage extends QueryPage { + + function isExpensive() { + return true; + } + + function isSyndicated() { + return false; + } + + /** + * Cache page existence for performance + */ + function preprocessResults( $db, $res ) { + $batch = new LinkBatch; + while ( $row = $db->fetchObject( $res ) ) + $batch->add( $row->namespace, $row->title ); + $batch->execute(); + + // Back to start for display + if ( $db->numRows( $res ) > 0 ) + // If there are no rows we get an error seeking. + $db->dataSeek( $res, 0 ); + } + + /** + * Format an individual result + * + * @param $skin Skin to use for UI elements + * @param $result Result row + * @return string + */ + public function formatResult( $skin, $result ) { + $title = Title::makeTitleSafe( $result->namespace, $result->title ); + if( $title instanceof Title ) { + if( $this->isCached() ) { + $pageLink = $title->exists() + ? '' . $skin->link( $title ) . '' + : $skin->link( + $title, + null, + array(), + array(), + array( 'broken' ) + ); + } else { + $pageLink = $skin->link( + $title, + null, + array(), + array(), + array( 'broken' ) + ); + } + return wfSpecialList( $pageLink, $this->makeWlhLink( $title, $skin, $result ) ); + } else { + $tsafe = htmlspecialchars( $result->title ); + return wfMsgHtml( 'wantedpages-badtitle', $tsafe ); + } + } + + /** + * Make a "what links here" link for a given title + * + * @param $title Title to make the link for + * @param $skin Skin object to use + * @param $result Object: result row + * @return string + */ + private function makeWlhLink( $title, $skin, $result ) { + global $wgLang; + $wlh = SpecialPage::getTitleFor( 'Whatlinkshere' ); + $label = wfMsgExt( 'nlinks', array( 'parsemag', 'escape' ), + $wgLang->formatNum( $result->value ) ); + return $skin->link( $wlh, $label, array(), array( 'target' => $title->getPrefixedText() ) ); + } +}