API * Added rudimentary RC list
authorYuri Astrakhan <yurik@users.mediawiki.org>
Fri, 20 Oct 2006 07:10:18 +0000 (07:10 +0000)
committerYuri Astrakhan <yurik@users.mediawiki.org>
Fri, 20 Oct 2006 07:10:18 +0000 (07:10 +0000)
* More readable query formulation

includes/AutoLoader.php
includes/api/ApiOpenSearch.php
includes/api/ApiQuery.php
includes/api/ApiQueryAllpages.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryLogEvents.php
includes/api/ApiQueryRecentchanges.php [new file with mode: 0644]
includes/api/ApiQueryWatchlist.php

index a5a58de..3885128 100644 (file)
@@ -255,6 +255,7 @@ function __autoload($className) {
                'ApiQueryBase' => 'includes/api/ApiQueryBase.php',
                'ApiQueryInfo' => 'includes/api/ApiQueryInfo.php',
                'ApiQueryLogEvents' => 'includes/api/ApiQueryLogEvents.php',
+               'ApiQueryRecentChanges'=> 'includes/api/ApiQueryRecentChanges.php',
                'ApiQueryRevisions' => 'includes/api/ApiQueryRevisions.php',
                'ApiQuerySiteinfo' => 'includes/api/ApiQuerySiteinfo.php',
                'ApiQueryWatchlist' => 'includes/api/ApiQueryWatchlist.php',
index 8b24af9..9e5afcb 100644 (file)
@@ -60,7 +60,7 @@ class ApiOpenSearch extends ApiBase {
                $module = new ApiMain($params);
                $module->execute();
 
-               // Get clean data
+               // Get resulting data
                $data = & $module->getResultData();
 
                // Reformat useful data for future printing by JSON engine
index 93d60ae..9addeb1 100644 (file)
@@ -48,7 +48,8 @@ class ApiQuery extends ApiBase {
        private $mQueryListModules = array (
                'allpages' => 'ApiQueryAllpages',
                'logevents' => 'ApiQueryLogEvents',
-               'watchlist' => 'ApiQueryWatchlist'
+               'watchlist' => 'ApiQueryWatchlist',
+               'recentchanges' => 'ApiQueryRecentChanges'
        );
        //      'backlinks' => 'ApiQueryBacklinks',
        //      'categorymembers' => 'ApiQueryCategorymembers',
index 117cfa7..123264f 100644 (file)
@@ -52,47 +52,32 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
 
                $db = $this->getDB();
 
-               $where = array (
-                       'page_namespace' => $namespace
-               );
-
-               if (isset ($from)) {
-                       $where[] = 'page_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($from));
-               }
-
-               if (isset ($prefix)) {
-                       $where[] = "page_title LIKE '{$db->strencode(ApiQueryBase :: titleToKey($prefix))}%'";
-               }
-
-               if ($filterredir === 'redirects') {
-                       $where['page_is_redirect'] = 1;
-               }
-               elseif ($filterredir === 'nonredirects') {
-                       $where['page_is_redirect'] = 0;
-               }
+               $this->addTables('page');
+               $this->addWhereIf('page_is_redirect = 1', $filterredir === 'redirects');
+               $this->addWhereIf('page_is_redirect = 0', $filterredir === 'nonredirects');
+               $this->addWhereFld('page_namespace', $namespace);
+               if (isset ($from))
+                       $this->addWhere('page_title>=' . $db->addQuotes(ApiQueryBase :: titleToKey($from)));
+               if (isset ($prefix))
+                       $this->addWhere("page_title LIKE '{$db->strencode(ApiQueryBase :: titleToKey($prefix))}%'");
 
                if (is_null($resultPageSet)) {
-                       $fields = array (
+                       $this->addFields( array (
                                'page_id',
                                'page_namespace',
                                'page_title'
-                       );
+                       ));
                } else {
-                       $fields = $resultPageSet->getPageTableFields();
+                       $this->addFields( $resultPageSet->getPageTableFields());
                }
 
-               $options = array (
-                       'USE INDEX' => 'name_title',
-                       'LIMIT' => $limit +1,
-                       'ORDER BY' => 'page_namespace, page_title'
-               );
-
-               $this->profileDBIn();
-               $res = $db->select('page', $fields, $where, __METHOD__, $options);
-               $this->profileDBOut();
+               $this->addOption( 'USE INDEX', 'name_title');
+               $this->addOption( 'LIMIT', $limit +1);
+               $this->addOption( 'ORDER BY', 'page_namespace, page_title');
 
                $data = array ();
                $count = 0;
+               $res = $this->select(__METHOD__);
                while ($row = $db->fetchObject($res)) {
                        if (++ $count > $limit) {
                                // We've reached the one extra which shows that there are additional pages to be had. Stop here...
index 4963927..297f8e1 100644 (file)
@@ -31,13 +31,88 @@ if (!defined('MEDIAWIKI')) {
 
 abstract class ApiQueryBase extends ApiBase {
 
-       private $mQueryModule;
+       private $mQueryModule, $tables, $where, $fields, $options;
 
        public function __construct($query, $moduleName, $paramPrefix = '') {
                parent :: __construct($query->getMain(), $moduleName, $paramPrefix);
                $this->mQueryModule = $query;
+
+               $this->tables = array ();
+               $this->where = array ();
+               $this->fields = array();
+               $this->options = array ();
+       }
+
+       protected function addTables($value) {
+               if(!is_array($this->tables))
+                       $this->dieDebug(__METHOD__, 'Must not call setTablesAsExpression() before this method');
+               if(is_array($value))
+                       $this->tables = array_merge($this->tables, $value);
+               else
+                       $this->tables[] = $value;
+       }
+       
+       protected function setTablesAsExpression($value) {
+               if(!empty($this->tables))
+                       $this->dieDebug(__METHOD__, 'Must not call addTables() before this method');
+               $this->tables = $value;
        }
 
+       protected function addFields($value) {  
+               if(is_array($value))
+                       $this->fields = array_merge($this->fields, $value);
+               else
+                       $this->fields[] = $value;
+       }
+
+       protected function addFieldsIf($value, $condition) {
+               if ($condition)
+                       $this->addFields($value);
+       }
+       
+       protected function addWhere($value) {
+               if(is_array($value))
+                       $this->where = array_merge($this->where, $value);
+               else
+                       $this->where[] = $value;
+       }
+       
+       protected function addWhereIf($value, $condition) {
+               if ($condition)
+                       $this->addWhere($value);
+       }
+
+       protected function addWhereFld($field, $value) {
+               if(!is_null($value))
+                       $this->where[$field] = $value;
+       }
+
+       protected function addWhereRange($field, $dir, $start, $end) {
+               $isDirNewer = ($dir === 'newer');
+               $after = ($isDirNewer ? '<=' : '>=');
+               $before = ($isDirNewer ? '>=' : '<=');
+               $db = $this->getDB();
+
+               if (!is_null($start))
+                       $this->addWhere($field . $after . $db->addQuotes($start));
+
+               if (!is_null($end))
+                       $this->addWhere($field . $before . $db->addQuotes($end));
+                       
+               $this->addOption('ORDER BY', $field . ($isDirNewer ? '' : ' DESC'));
+       }
+       
+       protected function select($method) {
+               $this->profileDBIn();
+               $res = $this->getDB()->select($this->tables, $this->fields, $this->where, $method, $this->options);
+               $this->profileDBOut();
+               return $res;
+       }
+
+       protected function addOption($name, $value) {
+               $this->options[$name] = $value;
+       }
+       
        /**
         * Override this method to request extra fields from the pageSet
         * using $this->getPageSet()->requestField('fieldName')
index cf3f30e..9b49188 100644 (file)
@@ -53,7 +53,10 @@ class ApiQueryInfo extends ApiQueryBase {
                $pageLatest = $pageSet->getCustomField('page_latest');
 
                foreach ($titles as $pageid => $title) {
-                       $pageInfo = array ('touched' => $pageTouched[$pageid], 'lastrevid' => $pageLatest[$pageid]);
+                       $pageInfo = array (
+                               'touched' => $pageTouched[$pageid],
+                               'lastrevid' => $pageLatest[$pageid]
+                       );
 
                        if ($pageIsRedir[$pageid])
                                $pageInfo['redirect'] = '';
index a6f88c3..decde3e 100644 (file)
@@ -42,11 +42,11 @@ class ApiQueryLogEvents extends ApiQueryBase {
                $db = $this->getDB();
 
                extract($db->tableNames('logging', 'page', 'user'), EXTR_PREFIX_ALL, 'tbl');
-               $tables = "$tbl_logging LEFT OUTER JOIN $tbl_page ON " .
+               $this->setTablesAsExpression("$tbl_logging LEFT OUTER JOIN $tbl_page ON " .
                "log_namespace=page_namespace AND log_title=page_title " .
-               "INNER JOIN $tbl_user ON user_id=log_user";
+               "INNER JOIN $tbl_user ON user_id=log_user");
 
-               $fields = array (
+               $this->addFields(array (
                        'log_type',
                        'log_action',
                        'log_timestamp',
@@ -57,11 +57,11 @@ class ApiQueryLogEvents extends ApiQueryBase {
                        'page_id',
                        'log_comment',
                        'log_params'
-               );
+               ));
 
-               $where = array ();
-               if (!is_null($type))
-                       $where['log_type'] = $type;
+               $this->addWhereFld('log_type', $type);
+               $this->addWhereRange('log_timestamp', $dir, $start, $end);
+               $this->addOption('LIMIT', $limit +1);
 
                if (!is_null($user)) {
                        $userid = $db->selectField('user', 'user_id', array (
@@ -69,37 +69,20 @@ class ApiQueryLogEvents extends ApiQueryBase {
                        ));
                        if (!$userid)
                                $this->dieUsage("User name $user not found", 'param_user');
-                       $where['log_user'] = $userid;
+                       $this->addWhereFld('log_user', $userid);
                }
 
                if (!is_null($title)) {
                        $titleObj = Title :: newFromText($title);
                        if (is_null($titleObj))
                                $this->dieUsage("Bad title value '$title'", 'param_title');
-                       $where['log_namespace'] = $titleObj->getNamespace();
-                       $where['log_title'] = $titleObj->getDBkey();
+                       $this->addWhereFld('log_namespace', $titleObj->getNamespace());
+                       $this->addWhereFld('log_title', $titleObj->getDBkey());
                }
 
-               $dirNewer = ($dir === 'newer');
-               $before = ($dirNewer ? '<=' : '>=');
-               $after = ($dirNewer ? '>=' : '<=');
-
-               if (!is_null($start))
-                       $where[] = 'log_timestamp' . $after . $db->addQuotes($start);
-               if (!is_null($end))
-                       $where[] = 'log_timestamp' . $before . $db->addQuotes($end);
-
-               $options = array (
-                       'LIMIT' => $limit +1,
-                       'ORDER BY' => 'log_timestamp' . ($dirNewer ? '' : ' DESC'
-               ));
-
-               $this->profileDBIn();
-               $res = $db->select($tables, $fields, $where, __METHOD__, $options);
-               $this->profileDBOut();
-
                $data = array ();
                $count = 0;
+               $res = $this->select(__METHOD__);
                while ($row = $db->fetchObject($res)) {
                        if (++ $count > $limit) {
                                // We've reached the one extra which shows that there are additional pages to be had. Stop here...
@@ -128,8 +111,8 @@ class ApiQueryLogEvents extends ApiQueryBase {
                                                $params = null;
                                        }
                                }
-                               
-                               if(!empty($params)) {
+
+                               if (!empty ($params)) {
                                        $this->getResult()->setIndexedTagName($params, 'param');
                                        $vals = array_merge($vals, $params);
                                }
diff --git a/includes/api/ApiQueryRecentchanges.php b/includes/api/ApiQueryRecentchanges.php
new file mode 100644 (file)
index 0000000..34f1c46
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+
+
+/*
+ * Created on Oct 19, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ('ApiQueryBase.php');
+}
+
+class ApiQueryRecentChanges extends ApiQueryBase {
+
+       public function __construct($query, $moduleName) {
+               parent :: __construct($query, $moduleName, 'rc');
+       }
+
+       public function execute() {
+               $limit = $from = $namespace = $hide = $dir = $start = $end = null;
+               extract($this->extractRequestParams());
+
+               $this->addTables('recentchanges');
+               $this->addWhereRange('rc_timestamp', $dir, $start, $end);
+               $this->addWhereFld('rc_namespace', $namespace);
+
+               if (!is_null($hide)) {
+                       $hide = array_flip($hide);
+                       $this->addWhereIf('rc_minor = 0', isset ($hide['minor']));
+                       $this->addWhereIf('rc_bot = 0', isset ($hide['bots']));
+                       $this->addWhereIf('rc_user != 0', isset ($hide['anons']));
+                       $this->addWhereIf('rc_user = 0', isset ($hide['liu']));
+               }
+
+               $this->addFields(array (
+                       'rc_timestamp',
+                       'rc_user',
+                       'rc_user_text',
+                       'rc_namespace',
+                       'rc_title',
+                       'rc_comment',
+                       'rc_minor',
+                       'rc_bot',
+                       'rc_new',
+                       'rc_cur_id',
+                       'rc_this_oldid',
+                       'rc_last_oldid',
+                       'rc_type',
+                       'rc_moved_to_ns',
+                       'rc_moved_to_title'
+               ));
+
+               $this->addOption('LIMIT', $limit +1);
+
+               $data = array ();
+               $count = 0;
+               $db = $this->getDB();
+               $res = $this->select(__METHOD__);
+               while ($row = $db->fetchObject($res)) {
+                       if (++ $count > $limit) {
+                               // We've reached the one extra which shows that there are additional pages to be had. Stop here...
+                               $this->setContinueEnumParameter('start', $row->rc_timestamp);
+                               break;
+                       }
+
+                       $title = Title :: makeTitle($row->rc_namespace, $row->rc_title);
+                       // skip any pages that user has no rights to read
+                       if ($title->userCanRead()) {
+
+                               $id = intval($row->rc_cur_id);
+                               $data[] = array (
+                                       'id' => $id,
+                                       'ns' => $title->getNamespace(), 'title' => $title->getPrefixedText(),
+                                       'timestamp' => $row->rc_timestamp,
+                                       'user' => $row->rc_user_text,
+                                       'comment' => $row->rc_comment,
+                                       'this_oldid' => $row->rc_this_oldid,
+                                       'last_oldid' => $row->rc_last_oldid,
+                                       'type' => $row->rc_type,
+                                       'moved_to_ns' => $row->rc_moved_to_ns,
+                                       'moved_to_title' => $row->rc_moved_to_title);
+                               
+                               if (!$row->rc_user)
+                                       $vals['anon'] = '';
+                               if ($row->rc_new)
+                                       $vals['new'] = '';
+                               if ($row->rc_bot)
+                                       $vals['bot'] = '';
+                               if ($row->rc_minor)
+                                       $vals['minor'] = '';
+                       }
+               }
+               $db->freeResult($res);
+
+               $result = $this->getResult();
+               $result->setIndexedTagName($data, 'rc');
+               $result->addValue('query', $this->getModuleName(), $data);
+       }
+
+       protected function getAllowedParams() {
+               $namespaces = $this->getQuery()->getValidNamespaces();
+               return array (
+                       'dir' => array (
+                               ApiBase :: PARAM_DFLT => 'older',
+                               ApiBase :: PARAM_TYPE => array (
+                                       'newer',
+                                       'older'
+                               )
+                       ),
+                       'start' => array (
+                               ApiBase :: PARAM_TYPE => 'timestamp'
+                       ),
+                       'end' => array (
+                               ApiBase :: PARAM_TYPE => 'timestamp'
+                       ),
+                       'namespace' => array (
+                               ApiBase :: PARAM_DFLT => 0,
+                               ApiBase :: PARAM_TYPE => $namespaces
+                       ),
+                       'hide' => array (
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => array (
+                                       'minor',
+                                       'bots',
+                                       'anons',
+                                       'liu'
+                               )
+                       ),
+                       'limit' => array (
+                               ApiBase :: PARAM_DFLT => 10,
+                               ApiBase :: PARAM_TYPE => 'limit',
+                               ApiBase :: PARAM_MIN => 1,
+                               ApiBase :: PARAM_MAX1 => ApiBase :: LIMIT_BIG1,
+                               ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
+                       )
+               );
+       }
+
+       protected function getParamDescription() {
+               return array (
+                       'start' => 'The timestamp to start enumerating from.',
+                       'end' => 'The timestamp to end enumerating.',
+                       'limit' => 'How many total pages to return.'
+               );
+       }
+
+       protected function getDescription() {
+               return 'Enumerate recent changes';
+       }
+
+       protected function getExamples() {
+               return array (
+                       'api.php?action=query&list=recentchanges',
+               );
+       }
+
+       public function getVersion() {
+               return __CLASS__ . ': $Id$';
+       }
+}
+?>
\ No newline at end of file
index 65335db..9b42698 100644 (file)
@@ -52,23 +52,6 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                $allrev = $start = $end = $namespace = $dir = $limit = $prop = null;
                extract($this->extractRequestParams());
 
-               $db = $this->getDB();
-
-               $dirNewer = ($dir === 'newer');
-               $after = ($dirNewer ? '<=' : '>=');
-               $before = ($dirNewer ? '>=' : '<=');
-
-               $tables = array (
-                       'watchlist',
-                       'page',
-                       'recentchanges'
-               );
-
-               $options = array (
-                       'LIMIT' => $limit +1,
-                       'ORDER BY' => 'rc_timestamp' . ($dirNewer ? '' : ' DESC'
-               ));
-
                $patrol = $timestamp = $user = $comment = false;
                if (!is_null($prop)) {
                        if (!is_null($resultPageSet))
@@ -87,67 +70,62 @@ class ApiQueryWatchlist extends ApiQueryGeneratorBase {
                }
 
                if (is_null($resultPageSet)) {
-                       $fields = array (
+                       $this->addFields(array (
                                'rc_cur_id AS page_id',
                                'rc_this_oldid AS rev_id',
                                'rc_namespace AS page_namespace',
                                'rc_title AS page_title',
                                'rc_new AS page_is_new',
-                               'rc_minor AS rev_minor_edit'
-                       );
-                       if ($user) {
-                               $fields[] = 'rc_user AS rev_user';
-                               $fields[] = 'rc_user_text AS rev_user_text';
-                       }
-                       if ($comment)
-                               $fields[] = 'rc_comment AS rev_comment';
-                       if ($timestamp)
-                               $fields[] = 'rc_timestamp AS rev_timestamp';
-                       if ($patrol)
-                               $fields[] = 'rc_patrolled';
+                               'rc_minor AS rev_minor_edit',
+                               'rc_timestamp AS rev_timestamp'
+                       ));
+
+                       $this->addFieldsIf('rc_user AS rev_user', $user);
+                       $this->addFieldsIf('rc_user_text AS rev_user_text', $user);
+                       $this->addFieldsIf('rc_comment AS rev_comment', $comment);
+                       $this->addFieldsIf('rc_patrolled', $patrol);
                }
                elseif ($allrev) {
-                       $fields = array (
+                       $this->addFields(array (
                                'rc_this_oldid AS rev_id',
                                'rc_namespace AS page_namespace',
                                'rc_title AS page_title',
                                'rc_timestamp AS rev_timestamp'
-                       );
+                       ));
                } else {
-                       $fields = array (
+                       $this->addFields(array (
                                'rc_cur_id AS page_id',
                                'rc_namespace AS page_namespace',
                                'rc_title AS page_title',
                                'rc_timestamp AS rev_timestamp'
-                       );
+                       ));
                }
 
-               $where = array (
+               $this->addTables(array (
+                       'watchlist',
+                       'page',
+                       'recentchanges'
+               ));
+
+               $userId = $wgUser->getID();
+               $this->addWhere(array (
                        'wl_namespace = rc_namespace',
                        'wl_title = rc_title',
                        'rc_cur_id = page_id',
-               'wl_user' => $wgUser->getID());
-
-               if (!$allrev)
-                       $where[] = 'rc_this_oldid=page_latest';
-               if (isset ($namespace))
-                       $where['wl_namespace'] = $namespace;
-
-               if (isset ($start))
-                       $where[] = 'rc_timestamp' . $after . $db->addQuotes($start);
-
-               if (isset ($end))
-                       $where[] = 'rc_timestamp' . $before . $db->addQuotes($end);
-
-               if (!isset ($start) && !isset ($end))
-                       $where[] = "rc_timestamp > ''";
-
-               $this->profileDBIn();
-               $res = $db->select($tables, $fields, $where, __METHOD__, $options);
-               $this->profileDBOut();
+                       'wl_user' => $userId
+               ));
+               $this->addWhereRange('rc_timestamp', $dir, $start, $end);
+               $this->addWhereFld('wl_namespace', $namespace);
+               $this->addWhereIf('rc_this_oldid=page_latest', !$allrev);
+               $this->addWhereIf("rc_timestamp > ''", !isset ($start) && !isset ($end));
+               
+               $this->addOption('LIMIT', $limit +1);
 
                $data = array ();
                $count = 0;
+               $res = $this->select(__METHOD__);
+
+               $db = $this->getDB();
                while ($row = $db->fetchObject($res)) {
                        if (++ $count > $limit) {
                                // We've reached the one extra which shows that there are additional pages to be had. Stop here...