(bug 11632) API: Breaking change: Specify the type of a change in the recentchanges...
[lhc/web/wiklou.git] / includes / api / ApiFormatBase.php
index 716201f..dc5b744 100644 (file)
@@ -1,12 +1,11 @@
 <?php
 
-
 /*
  * Created on Sep 19, 2006
  *
  * API for MediaWiki 1.8+
  *
- * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>
+ * Copyright (C) 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 if (!defined('MEDIAWIKI')) {
        // Eclipse helper - will be ignored in production
-       require_once ("ApiBase.php");
+       require_once ('ApiBase.php');
 }
 
+/**
+ * This is the abstract base class for API formatters.
+ * 
+ * @addtogroup API
+ */
 abstract class ApiFormatBase extends ApiBase {
 
-       private $mIsHtml, $mFormat, $mOriginalFormat;
+       private $mIsHtml, $mFormat, $mUnescapeAmps;
 
        /**
-       * Constructor
+       * Create a new instance of the formatter.
+       * If the format name ends with 'fm', wrap its output in the proper HTML.
        */
        public function __construct($main, $format) {
-               parent :: __construct($main);
+               parent :: __construct($main, $format);
 
-               $this->mOriginalFormat = $format;
                $this->mIsHtml = (substr($format, -2, 2) === 'fm'); // ends with 'fm'
                if ($this->mIsHtml)
                        $this->mFormat = substr($format, 0, -2); // remove ending 'fm'
@@ -50,21 +54,38 @@ abstract class ApiFormatBase extends ApiBase {
 
        /**
         * Overriding class returns the mime type that should be sent to the client.
-        * This method is not called if GetIsHtml() returns true.
+        * This method is not called if getIsHtml() returns true.
         * @return string
         */
-       public abstract function GetMimeType();
+       public abstract function getMimeType();
 
-       public function GetNeedsRawData() {
+       /**
+        * If formatter outputs data results as is, the results must first be sanitized.
+        * An XML formatter on the other hand uses special tags, such as "_element" for special handling,
+        * and thus needs to override this function to return true.  
+        */
+       public function getNeedsRawData() {
                return false;
        }
 
+       /**
+        * Specify whether or not ampersands should be escaped to '&amp;' when rendering. This
+        * should only be set to true for the help message when rendered in the default (xmlfm)
+        * format. This is a temporary special-case fix that should be removed once the help
+        * has been reworked to use a fully html interface.
+        *
+        * @param boolean Whether or not ampersands should be escaped.
+        */
+       public function setUnescapeAmps ( $b ) {
+               $this->mUnescapeAmps = $b;
+       }
+
        /**
         * Returns true when an HTML filtering printer should be used.
         * The default implementation assumes that formats ending with 'fm' 
         * should be formatted in HTML. 
         */
-       public function GetIsHtml() {
+       public function getIsHtml() {
                return $this->mIsHtml;
        }
 
@@ -73,35 +94,44 @@ abstract class ApiFormatBase extends ApiBase {
         * This method must be the first outputing method during execution.
         * A help screen's header is printed for the HTML-based output
         */
-       function InitPrinter($isError) {
-               $isHtml = $this->GetIsHtml();
-               $mime = $isHtml ? 'text/html' : $this->GetMimeType();
-               header("Content-Type: $mime; charset=utf-8;");
+       function initPrinter($isError) {
+               $isHtml = $this->getIsHtml();
+               $mime = $isHtml ? 'text/html' : $this->getMimeType();
+               $script = wfScript( 'api' );
+
+               // Some printers (ex. Feed) do their own header settings,
+               // in which case $mime will be set to null
+               if (is_null($mime))
+                       return; // skip any initialization
+
+               header("Content-Type: $mime; charset=utf-8");
 
                if ($isHtml) {
 ?>
-               <html>
-               <head>
-                       <title>MediaWiki API</title>
-               </head>
-               <body>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+       <title>MediaWiki API</title>
+</head>
+<body>
 <?php
 
 
-                       if (!$isError) {
+                       if( !$isError ) {
 ?>
-                       <br/>
-                       <small>
-                       This result is being shown in <?=$this->mFormat?> format,
-                       which might not be suitable for your application.<br/>
-                       See <a href="api.php">API help</a> for more information.<br/>
-                       </small>
+<br/>
+<small>
+You are looking at the HTML representation of the <?php echo( $this->mFormat ); ?> format.<br/>
+HTML is good for debugging, but probably is not suitable for your application.<br/>
+See <a href='http://www.mediawiki.org/wiki/API'>complete documentation</a>, or 
+<a href='<?php echo( $script ); ?>'>API help</a> for more information.
+</small>
 <?php
 
 
                        }
 ?>
-               <pre>
+<pre>
 <?php
 
 
@@ -111,37 +141,56 @@ abstract class ApiFormatBase extends ApiBase {
        /**
         * Finish printing. Closes HTML tags.
         */
-       public function ClosePrinter() {
-               if ($this->GetIsHtml()) {
+       public function closePrinter() {
+               if ($this->getIsHtml()) {
 ?>
-               </pre>
-               </body>
+
+</pre>
+</body>
+</html>
 <?php
 
 
                }
        }
 
-       public function PrintText($text) {
-               if ($this->GetIsHtml())
-                       echo $this->FormatHTML($text);
+       /**
+        * The main format printing function. Call it to output the result string to the user.
+        * This function will automatically output HTML when format name ends in 'fm'.
+        */
+       public function printText($text) {
+               if ($this->getIsHtml())
+                       echo $this->formatHTML($text);
                else
                        echo $text;
        }
 
        /**
        * Prety-print various elements in HTML format, such as xml tags and URLs.
-       * This method also replaces any "<" with &lt;
+       * This method also replaces any '<' with &lt;
        */
-       protected function FormatHTML($text) {
-               // encode all tags as safe blue strings
-               $text = ereg_replace('\<([^>]+)\>', '<font color=blue>&lt;\1&gt;</font>', $text);
+       protected function formatHTML($text) {
+               // Escape everything first for full coverage
+               $text = htmlspecialchars($text);
+
+               // encode all comments or tags as safe blue strings
+               $text = preg_replace('/\&lt;(!--.*?--|.*?)\&gt;/', '<span style="color:blue;">&lt;\1&gt;</span>', $text);
                // identify URLs
-               $text = ereg_replace("[a-zA-Z]+://[^ '()<\n]+", '<a href="\\0">\\0</a>', $text);
+               $protos = "http|https|ftp|gopher";
+               $text = ereg_replace("($protos)://[^ \\'\"()<\n]+", '<a href="\\0">\\0</a>', $text);
                // identify requests to api.php
-               $text = ereg_replace("api\\.php\\?[^ ()<\n\t]+", '<a href="\\0">\\0</a>', $text);
+               $text = ereg_replace("api\\.php\\?[^ \\()<\n\t]+", '<a href="\\0">\\0</a>', $text);
                // make strings inside * bold
                $text = ereg_replace("\\*[^<>\n]+\\*", '<b>\\0</b>', $text);
+               // make strings inside $ italic
+               $text = ereg_replace("\\$[^<>\n]+\\$", '<b><i>\\0</i></b>', $text);
+               
+               /* Temporary fix for bad links in help messages. As a special case,
+                * XML-escaped metachars are de-escaped one level in the help message
+                * for legibility. Should be removed once we have completed a fully-html
+                * version of the help message. */
+               if ( $this->mUnescapeAmps )
+                       $text = preg_replace( '/&amp;(amp|quot|lt|gt);/', '&\1;', $text );
 
                return $text;
        }
@@ -149,8 +198,77 @@ abstract class ApiFormatBase extends ApiBase {
        /**
         * Returns usage examples for this format.
         */
-       protected function GetExamples() {
-               return 'api.php?action=query&meta=siteinfo&si=namespaces&format=' . $this->mOriginalFormat;
+       protected function getExamples() {
+               return 'api.php?action=query&meta=siteinfo&siprop=namespaces&format=' . $this->getModuleName();
+       }
+
+       protected function getDescription() {
+               return $this->getIsHtml() ? ' (pretty-print in HTML)' : '';
+       }
+
+       public static function getBaseVersion() {
+               return __CLASS__ . ': $Id$';
+       }
+}
+
+/**
+ * This printer is used to wrap an instance of the Feed class 
+ * @addtogroup API
+ */
+class ApiFormatFeedWrapper extends ApiFormatBase {
+
+       public function __construct($main) {
+               parent :: __construct($main, 'feed');
+       }
+
+       /**
+        * Call this method to initialize output data. See self::execute()
+        */
+       public static function setResult($result, $feed, $feedItems) {
+               // Store output in the Result data.
+               // This way we can check during execution if any error has occured
+               $data = & $result->getData();
+               $data['_feed'] = $feed;
+               $data['_feeditems'] = $feedItems;
+       }
+
+       /**
+        * Feed does its own headers
+        */
+       public function getMimeType() {
+               return null;
+       }
+
+       /**
+        * Optimization - no need to sanitize data that will not be needed
+        */
+       public function getNeedsRawData() {
+               return true;
+       }
+
+       /**
+        * This class expects the result data to be in a custom format set by self::setResult()
+        * $result['_feed']              - an instance of one of the $wgFeedClasses classes
+        * $result['_feeditems'] - an array of FeedItem instances
+        */
+       public function execute() {
+               $data = $this->getResultData();
+               if (isset ($data['_feed']) && isset ($data['_feeditems'])) {
+                       $feed = $data['_feed'];
+                       $items = $data['_feeditems'];
+
+                       $feed->outHeader();
+                       foreach ($items as & $item)
+                               $feed->outItem($item);
+                       $feed->outFooter();
+               } else {
+                       // Error has occured, print something usefull
+                       // TODO: make this error more informative using ApiBase :: dieDebug() or similar
+                       wfHttpError(500, 'Internal Server Error', '');
+               }
+       }
+       
+       public function getVersion() {
+               return __CLASS__ . ': $Id$';
        }
 }
-?>
\ No newline at end of file