1<?php 2/** 3 * Copyright © 2010 Roan Kattouw "<Firstname>.<Lastname>@gmail.com" 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 */ 22 23use MediaWiki\MediaWikiServices; 24use MediaWiki\SpecialPage\SpecialPageFactory; 25 26/** 27 * Query module to get the results of a QueryPage-based special page 28 * 29 * @ingroup API 30 */ 31class ApiQueryQueryPage extends ApiQueryGeneratorBase { 32 33 /** 34 * @var string[] list of special page names 35 */ 36 private $queryPages; 37 38 /** 39 * @var SpecialPageFactory 40 */ 41 private $specialPageFactory; 42 43 public function __construct( ApiQuery $query, $moduleName ) { 44 parent::__construct( $query, $moduleName, 'qp' ); 45 $this->queryPages = array_values( array_diff( 46 array_column( QueryPage::getPages(), 1 ), // [ class, name ] 47 $this->getConfig()->get( 'APIUselessQueryPages' ) 48 ) ); 49 $this->specialPageFactory = MediaWikiServices::getInstance()->getSpecialPageFactory(); 50 } 51 52 public function execute() { 53 $this->run(); 54 } 55 56 public function executeGenerator( $resultPageSet ) { 57 $this->run( $resultPageSet ); 58 } 59 60 /** 61 * @param string $name 62 * @return QueryPage 63 */ 64 private function getSpecialPage( $name ) : QueryPage { 65 $qp = $this->specialPageFactory->getPage( $name ); 66 if ( !$qp ) { 67 self::dieDebug( 68 __METHOD__, 69 'SpecialPageFactory failed to create special page ' . $name 70 ); 71 } 72 if ( !( $qp instanceof QueryPage ) ) { 73 self::dieDebug( 74 __METHOD__, 75 'Special page ' . $name . ' is not a QueryPage' 76 ); 77 } 78 return $qp; 79 } 80 81 /** 82 * @param ApiPageSet|null $resultPageSet 83 */ 84 public function run( $resultPageSet = null ) { 85 $params = $this->extractRequestParams(); 86 $result = $this->getResult(); 87 88 $qp = $this->getSpecialPage( $params['page'] ); 89 if ( !$qp->userCanExecute( $this->getUser() ) ) { 90 $this->dieWithError( 'apierror-specialpage-cantexecute' ); 91 } 92 93 $r = [ 'name' => $params['page'] ]; 94 if ( $qp->isCached() ) { 95 if ( !$qp->isCacheable() ) { 96 $r['disabled'] = true; 97 } else { 98 $r['cached'] = true; 99 $ts = $qp->getCachedTimestamp(); 100 if ( $ts ) { 101 $r['cachedtimestamp'] = wfTimestamp( TS_ISO_8601, $ts ); 102 } 103 $r['maxresults'] = $this->getConfig()->get( 'QueryCacheLimit' ); 104 } 105 } 106 $result->addValue( [ 'query' ], $this->getModuleName(), $r ); 107 108 if ( $qp->isCached() && !$qp->isCacheable() ) { 109 // Disabled query page, don't run the query 110 return; 111 } 112 113 $res = $qp->doQuery( $params['offset'], $params['limit'] + 1 ); 114 $count = 0; 115 $titles = []; 116 foreach ( $res as $row ) { 117 if ( ++$count > $params['limit'] ) { 118 // We've had enough 119 $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] ); 120 break; 121 } 122 123 $title = Title::makeTitle( $row->namespace, $row->title ); 124 if ( $resultPageSet === null ) { 125 $data = []; 126 if ( isset( $row->value ) ) { 127 $data['value'] = $row->value; 128 if ( $qp->usesTimestamps() ) { 129 $data['timestamp'] = wfTimestamp( TS_ISO_8601, $row->value ); 130 } 131 } 132 self::addTitleInfo( $data, $title ); 133 134 foreach ( $row as $field => $value ) { 135 if ( !in_array( $field, [ 'namespace', 'title', 'value', 'qc_type' ] ) ) { 136 $data['databaseResult'][$field] = $value; 137 } 138 } 139 140 $fit = $result->addValue( [ 'query', $this->getModuleName(), 'results' ], null, $data ); 141 if ( !$fit ) { 142 $this->setContinueEnumParameter( 'offset', $params['offset'] + $count - 1 ); 143 break; 144 } 145 } else { 146 $titles[] = $title; 147 } 148 } 149 if ( $resultPageSet === null ) { 150 $result->addIndexedTagName( 151 [ 'query', $this->getModuleName(), 'results' ], 152 'page' 153 ); 154 } else { 155 $resultPageSet->populateFromTitles( $titles ); 156 } 157 } 158 159 public function getCacheMode( $params ) { 160 $qp = $this->getSpecialPage( $params['page'] ); 161 if ( $qp->getRestriction() != '' ) { 162 return 'private'; 163 } 164 165 return 'public'; 166 } 167 168 public function getAllowedParams() { 169 return [ 170 'page' => [ 171 ApiBase::PARAM_TYPE => $this->queryPages, 172 ApiBase::PARAM_REQUIRED => true 173 ], 174 'offset' => [ 175 ApiBase::PARAM_DFLT => 0, 176 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue', 177 ], 178 'limit' => [ 179 ApiBase::PARAM_DFLT => 10, 180 ApiBase::PARAM_TYPE => 'limit', 181 ApiBase::PARAM_MIN => 1, 182 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, 183 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 184 ], 185 ]; 186 } 187 188 protected function getExamplesMessages() { 189 return [ 190 'action=query&list=querypage&qppage=Ancientpages' 191 => 'apihelp-query+querypage-example-ancientpages', 192 ]; 193 } 194 195 public function getHelpUrls() { 196 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Querypage'; 197 } 198} 199