Index: trunk/extensions/News/News.php
===================================================================
--- trunk/extensions/News/News.php (revision 21477)
+++ trunk/extensions/News/News.php (revision 21478)
@@ -28,8 +28,8 @@
$wgExtensionFunctions[] = "wfNewsExtension";
$wgAutoloadClasses['NewsRenderer'] = dirname( __FILE__ ) . '/NewsRenderer.php';
-$wgHooks['ArticleViewHeader'][] = 'wfNewsArticleViewHeader';
-$wgHooks['ArticlePurge'][] = 'wfNewsArticlePurge';
+$wgAutoloadClasses['NewsFeedPage'] = dirname( __FILE__ ) . '/NewsRenderer.php';
+$wgHooks['ArticleFromTitle'][] = 'wfNewsArticleFromTitle';
$wgHooks['SkinTemplateOutputPageBeforeExec'][] = 'wfNewsSkinTemplateOutputPageBeforeExec';
//FIXME: find a way to override the feed URLs generated by OutputPage::getHeadLinks
@@ -56,10 +56,6 @@
$parser->disableCache(); //TODO: use smart cache & purge...?
$wgOut->setSyndicated( true );
- #$rss = $renderer->renderFeedMetaLink( 'rss' );
- #$atom = $renderer->renderFeedMetaLink( 'atom' );
- #$parser->mOutput->addHeadItem($rss . $atom);
-
$renderer = new NewsRenderer($wgTitle, $templatetext, $argv, $parser);
$html = $renderer->renderFeedPreview();
return $html;
@@ -69,112 +65,39 @@
return NewsRenderer::renderFeedLink($linktext, $argv, $parser);
}
-function wfNewsCacheKey( $title, $format ) {
- //global $wgLang;
- //NOTE: per-language caching might be needed at some point.
- // right now, caching is done for anon users only
- // (the content language might be set individually however,
- // using an extension like LanguageSelector)
+function wfNewsArticleFromTitle( &$title, &$article ) {
+ global $wgRequest, $wgFeedClasses, $wgUser, $wgOut;
+ $fname = 'extension/News: wfNewsArticleFromTitle';
- return "@newsfeed:" . urlencode($title->getPrefixedDBKey()) . '|' . urlencode($format);
-}
+ $ns = $title->getNamespace();
+ if ($ns < 0 || $ns == NS_SPECIAL || $ns == NS_MEDIAWIKI) return true;
-function wfNewsArticleViewHeader( &$article ) {
- global $wgRequest, $wgOut, $wgFeedClasses, $wgUser;
-
$format = $wgRequest->getVal( 'feed' );
if (!$format) return true;
- $wgOut->disable();
- //XXX: returning false currently doesn't stop the rest of Article::view to execute :(
-
- $title = $article->getTitle();
$format = strtolower( trim($format) );
+ $action = strtolower( trim( $wgRequest->getVal( 'action', 'view' ) ) );
+ if ($action != 'view' && $action != 'purge') return true;
+
if ( !isset($wgFeedClasses[$format] ) ) {
+ wfDebug("$fname: unknown feed format: $format\n");
wfHttpError(400, "Bad Request", "unknown feed format: " . $format); //TODO: better code & text
return false;
}
- if (!$article->exists()) {
+ if (!$title->exists()) {
+ wfDebug("$fname: feed page not found: " . $title->getPrefixedDBKey() . "\n");
wfHttpError(404, "Not Found", "feed page not found: " . $title->getPrefixedText()); //TODO: better text
return false;
}
- $note = '';
+ wfDebug("$fname: handling feed request for " . $title->getPrefixedDBKey() . "\n");
- //NOTE: do caching for anon users only, because of user-specific
- // rendering of textual content
- if ($wgUser->isAnon()) {
- $cachekey = wfNewsCacheKey($title, $format);
- $ocache = wfGetParserCacheStorage();
- $e = $ocache ? $ocache->get( $cachekey ) : NULL;
- $note .= ' anon;';
- }
- else {
- $cachekey = NULL;
- $ocache = NULL;
- $e = NULL;
- $note .= ' user;';
- }
-
- if ( $e ) {
- $lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
- if ($lastchange < $e['timestamp']) {
- print $e['xml'] . "\n<!-- cached: $note -->\n";
- return false; //done
- }
- else {
- $note .= " stale: $lastchange >= {$e['timestamp']};";
- }
- }
-
- global $wgParser; //evil global
-
- if (!$wgParser->mOptions) { //XXX: ugly hack :(
- $wgParser->mOptions = new ParserOptions;
- $wgParser->setOutputType( OT_HTML );
- $wgParser->clearState();
- $wgParser->mTitle = $title;
- }
-
- $renderer = NewsRenderer::newFromArticle( $article, $wgParser );
- if (!$renderer) {
- wfHttpError(404, "Bad Request", "no feed found on page: " . $title->getPrefixedText() ); //TODO: better code & text
- return;
- }
-
- $description = ''; //TODO: grab from article content... but what? and how?
- $ts = time();
- $xml = $renderer->renderFeed( $format, $description );
-
- $e = array( 'xml' => $xml, 'timestamp' => $ts );
- if ($ocache) {
- $ocache->set( $cachekey, $e, $ts + 24 * 60 * 60 ); //cache for max 24 hours; cached record is discarded when anything turns up in RC anyway.
- $note .= ' updated;';
- }
-
- $wgOut->disable();
- print $xml . "\n<!-- fresh: $note -->\n";
- return false; //done
+ $article = new NewsFeedPage( $title, $format );
+ return false;
}
-function wfNewsArticlePurge( &$article ) {
- global $wgFeedClasses;
-
- $ocache = wfGetParserCacheStorage();
- if (!$ocache) return true;
-
- $title = $article->getTitle();
-
- foreach( $wgFeedClasses as $format => $class ) {
- $cachekey = wfNewsCacheKey( $title, $format );
- $ocache->delete( $cachekey );
- }
-
- return true;
-}
-
function wfNewsSkinTemplateOutputPageBeforeExec( &$skin, &$tpl ) {
$feeds = $tpl->data['feeds'];
if (!$feeds) return true;
Index: trunk/extensions/News/NewsRenderer.php
===================================================================
--- trunk/extensions/News/NewsRenderer.php (revision 21477)
+++ trunk/extensions/News/NewsRenderer.php (revision 21478)
@@ -503,10 +503,11 @@
$article = new Article( $title, $row->rc_this_oldid );
$t = $article->getContent();
- $params['content'] = NewsRenderer::sanitizeWikiText( $t );
//TODO: expand variables & templates first, so cut-off applies to effective content,
// and extension tags from templates are stripped properly
+ // this doesn't work though: $t = $this->templateparser->preprocess( $t, $this->title, new ParserOptions() );
//TODO: avoid magic categories, interwiki-links, etc
+ $params['content'] = NewsRenderer::sanitizeWikiText( $t );
if ( stripos($templatetext, '{{{head}}}')!==false ) {
$params['head'] = NewsRenderer::extractHead( $params['content'], $title );
@@ -678,4 +679,127 @@
}
}
+class NewsFeedPage extends Article {
+ var $mFeedFormat;
+
+ function __construct($title, $format) {
+ Article::__construct( $title );
+ $this->mFeedFormat = $format;
+ }
+
+ function getCacheKey( ) {
+ //global $wgLang;
+ //NOTE: per-language caching might be needed at some point.
+ // right now, caching is done for anon users only
+ // (the content language might be set individually however,
+ // using an extension like LanguageSelector)
+
+ return "@newsfeed:" . urlencode($this->mTitle->getPrefixedDBKey()) . '|' . urlencode($this->mFeedFormat);
+ }
+
+ function view( $usecache = true ) {
+ global $wgUser, $wgOut;
+
+ $fname = 'NewsFeedPage::view';
+ wfDebug("$fname: start\n");
+
+ $note = '';
+
+ $ims = @$_SERVER['HTTP_IF_MODIFIED_SINCE'];
+
+ if ( $ims && $usecache ) {
+ $lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
+
+ wfDebug("$fname: checking cache-ok: IMS $ims vs. changed $lastchange \n");
+ if ( $wgOut->checkLastModified( $lastchange ) ) {
+ wfDebug("$fname: HTTP cache ok, 304 header sent\n");
+ return; // done, 304 header sent.
+ }
+ }
+
+ //NOTE: do caching for anon users only, because of user-specific
+ // rendering of textual content
+ if ($wgUser->isAnon() && $usecache) {
+ $cachekey = $this->getCacheKey();
+ $ocache = wfGetParserCacheStorage();
+ $e = $ocache ? $ocache->get( $cachekey ) : NULL;
+ $note .= ' anon;';
+ wfDebug("$fname: " . ($e? "got cached" : "no cached") . "\n");
+ }
+ else {
+ if (!$usecache) {
+ wfDebug("$fname: purge, ignoring cache\n");
+ $note .= ' purged;';
+ }
+ else {
+ wfDebug("$fname: logged in, ignoring cache\n");
+ $note .= ' user;';
+ }
+
+ $cachekey = NULL;
+ $ocache = NULL;
+ $e = NULL;
+ $note .= ' user;';
+ }
+
+ $wgOut->disable();
+
+ if ( $e ) {
+ if (!isset($lastchange)) $lastchange = wfTimestamp(TS_UNIX, NewsRenderer::getLastChangeTime());
+ $last = wfTimestamp(TS_UNIX, $lastchange);
+
+ if ($last < $e['timestamp']) {
+ wfDebug("$fname: outputting cached copy ($cachekey): $last < {$e['timestamp']}\n");
+ print $e['xml'];
+ print "\n<!-- cached: $note -->\n";
+ return; //done
+ }
+ else {
+ wfDebug("$fname: found stale cache copy ($cachekey): $last >= {$e['timestamp']}\n");
+ $note .= " stale: $last >= {$e['timestamp']};";
+ }
+ }
+
+ //TODO: fetch actual news data and check the newest item. re-apply cache checks.
+ // this would still save the cost of rendering if the data didn't change
+
+ global $wgParser; //evil global
+
+ if (!$wgParser->mOptions) { //XXX: ugly hack :(
+ $wgParser->mOptions = new ParserOptions;
+ $wgParser->setOutputType( OT_HTML );
+ $wgParser->clearState();
+ $wgParser->mTitle = $this->mTitle;
+ }
+
+ $renderer = NewsRenderer::newFromArticle( $this, $wgParser );
+ if (!$renderer) {
+ wfDebug("$fname: no feed found on page: " . $this->mTitle->getPrefixedText() . "\n");
+ wfHttpError(404, "Not Found", "no feed found on page: " . $this->mTitle->getPrefixedText() ); //TODO: better code & text
+ return;
+ }
+
+ $description = ''; //TODO: grab from article content... but what? and how?
+ $ts = time();
+
+ //this also sends the right headers
+ $xml = $renderer->renderFeed( $this->mFeedFormat, $description );
+ wfDebug("$fname: rendered feed\n");
+
+ $e = array( 'xml' => $xml, 'timestamp' => $ts );
+ if ($ocache) {
+ wfDebug("$fname: caching feed ($cachekey)\n");
+ $ocache->set( $cachekey, $e, $ts + 24 * 60 * 60 ); //cache for max 24 hours; cached record is discarded when anything turns up in RC anyway.
+ $note .= ' updated;';
+ }
+
+ wfDebug("$fname: outputting fresh feed\n");
+ print $xml;
+ print "\n<!-- fresh: $note -->\n";
+ }
+
+ function purge() {
+ $this->view( false );
+ }
+}
?>
\ No newline at end of file