MediaWiki
REL1_19
|
00001 <?php 00034 abstract class ApiQueryBase extends ApiBase { 00035 00036 private $mQueryModule, $mDb, $tables, $where, $fields, $options, $join_conds; 00037 00043 public function __construct( ApiBase $query, $moduleName, $paramPrefix = '' ) { 00044 parent::__construct( $query->getMain(), $moduleName, $paramPrefix ); 00045 $this->mQueryModule = $query; 00046 $this->mDb = null; 00047 $this->resetQueryParams(); 00048 } 00049 00061 public function getCacheMode( $params ) { 00062 return 'private'; 00063 } 00064 00068 protected function resetQueryParams() { 00069 $this->tables = array(); 00070 $this->where = array(); 00071 $this->fields = array(); 00072 $this->options = array(); 00073 $this->join_conds = array(); 00074 } 00075 00082 protected function addTables( $tables, $alias = null ) { 00083 if ( is_array( $tables ) ) { 00084 if ( !is_null( $alias ) ) { 00085 ApiBase::dieDebug( __METHOD__, 'Multiple table aliases not supported' ); 00086 } 00087 $this->tables = array_merge( $this->tables, $tables ); 00088 } else { 00089 if ( !is_null( $alias ) ) { 00090 $this->tables[$alias] = $tables; 00091 } else { 00092 $this->tables[] = $tables; 00093 } 00094 } 00095 } 00096 00106 protected function addJoinConds( $join_conds ) { 00107 if ( !is_array( $join_conds ) ) { 00108 ApiBase::dieDebug( __METHOD__, 'Join conditions have to be arrays' ); 00109 } 00110 $this->join_conds = array_merge( $this->join_conds, $join_conds ); 00111 } 00112 00117 protected function addFields( $value ) { 00118 if ( is_array( $value ) ) { 00119 $this->fields = array_merge( $this->fields, $value ); 00120 } else { 00121 $this->fields[] = $value; 00122 } 00123 } 00124 00131 protected function addFieldsIf( $value, $condition ) { 00132 if ( $condition ) { 00133 $this->addFields( $value ); 00134 return true; 00135 } 00136 return false; 00137 } 00138 00150 protected function addWhere( $value ) { 00151 if ( is_array( $value ) ) { 00152 // Sanity check: don't insert empty arrays, 00153 // Database::makeList() chokes on them 00154 if ( count( $value ) ) { 00155 $this->where = array_merge( $this->where, $value ); 00156 } 00157 } else { 00158 $this->where[] = $value; 00159 } 00160 } 00161 00168 protected function addWhereIf( $value, $condition ) { 00169 if ( $condition ) { 00170 $this->addWhere( $value ); 00171 return true; 00172 } 00173 return false; 00174 } 00175 00181 protected function addWhereFld( $field, $value ) { 00182 // Use count() to its full documented capabilities to simultaneously 00183 // test for null, empty array or empty countable object 00184 if ( count( $value ) ) { 00185 $this->where[$field] = $value; 00186 } 00187 } 00188 00201 protected function addWhereRange( $field, $dir, $start, $end, $sort = true ) { 00202 $isDirNewer = ( $dir === 'newer' ); 00203 $after = ( $isDirNewer ? '>=' : '<=' ); 00204 $before = ( $isDirNewer ? '<=' : '>=' ); 00205 $db = $this->getDB(); 00206 00207 if ( !is_null( $start ) ) { 00208 $this->addWhere( $field . $after . $db->addQuotes( $start ) ); 00209 } 00210 00211 if ( !is_null( $end ) ) { 00212 $this->addWhere( $field . $before . $db->addQuotes( $end ) ); 00213 } 00214 00215 if ( $sort ) { 00216 $order = $field . ( $isDirNewer ? '' : ' DESC' ); 00217 // Append ORDER BY 00218 $optionOrderBy = isset( $this->options['ORDER BY'] ) ? (array)$this->options['ORDER BY'] : array(); 00219 $optionOrderBy[] = $order; 00220 $this->addOption( 'ORDER BY', $optionOrderBy ); 00221 } 00222 } 00223 00234 protected function addTimestampWhereRange( $field, $dir, $start, $end, $sort = true ) { 00235 $db = $this->getDb(); 00236 return $this->addWhereRange( $field, $dir, 00237 $db->timestampOrNull( $start ), $db->timestampOrNull( $end ), $sort ); 00238 } 00239 00246 protected function addOption( $name, $value = null ) { 00247 if ( is_null( $value ) ) { 00248 $this->options[] = $name; 00249 } else { 00250 $this->options[$name] = $value; 00251 } 00252 } 00253 00262 protected function select( $method, $extraQuery = array() ) { 00263 00264 $tables = array_merge( $this->tables, isset( $extraQuery['tables'] ) ? (array)$extraQuery['tables'] : array() ); 00265 $fields = array_merge( $this->fields, isset( $extraQuery['fields'] ) ? (array)$extraQuery['fields'] : array() ); 00266 $where = array_merge( $this->where, isset( $extraQuery['where'] ) ? (array)$extraQuery['where'] : array() ); 00267 $options = array_merge( $this->options, isset( $extraQuery['options'] ) ? (array)$extraQuery['options'] : array() ); 00268 $join_conds = array_merge( $this->join_conds, isset( $extraQuery['join_conds'] ) ? (array)$extraQuery['join_conds'] : array() ); 00269 00270 // getDB has its own profileDBIn/Out calls 00271 $db = $this->getDB(); 00272 00273 $this->profileDBIn(); 00274 $res = $db->select( $tables, $fields, $where, $method, $options, $join_conds ); 00275 $this->profileDBOut(); 00276 00277 return $res; 00278 } 00279 00285 protected function checkRowCount() { 00286 $db = $this->getDB(); 00287 $this->profileDBIn(); 00288 $rowcount = $db->estimateRowCount( $this->tables, $this->fields, $this->where, __METHOD__, $this->options ); 00289 $this->profileDBOut(); 00290 00291 global $wgAPIMaxDBRows; 00292 if ( $rowcount > $wgAPIMaxDBRows ) { 00293 return false; 00294 } 00295 return true; 00296 } 00297 00305 public static function addTitleInfo( &$arr, $title, $prefix = '' ) { 00306 $arr[$prefix . 'ns'] = intval( $title->getNamespace() ); 00307 $arr[$prefix . 'title'] = $title->getPrefixedText(); 00308 } 00309 00315 public function requestExtraData( $pageSet ) { 00316 } 00317 00322 public function getQuery() { 00323 return $this->mQueryModule; 00324 } 00325 00332 protected function addPageSubItems( $pageId, $data ) { 00333 $result = $this->getResult(); 00334 $result->setIndexedTagName( $data, $this->getModulePrefix() ); 00335 return $result->addValue( array( 'query', 'pages', intval( $pageId ) ), 00336 $this->getModuleName(), 00337 $data ); 00338 } 00339 00348 protected function addPageSubItem( $pageId, $item, $elemname = null ) { 00349 if ( is_null( $elemname ) ) { 00350 $elemname = $this->getModulePrefix(); 00351 } 00352 $result = $this->getResult(); 00353 $fit = $result->addValue( array( 'query', 'pages', $pageId, 00354 $this->getModuleName() ), null, $item ); 00355 if ( !$fit ) { 00356 return false; 00357 } 00358 $result->setIndexedTagName_internal( array( 'query', 'pages', $pageId, 00359 $this->getModuleName() ), $elemname ); 00360 return true; 00361 } 00362 00368 protected function setContinueEnumParameter( $paramName, $paramValue ) { 00369 $paramName = $this->encodeParamName( $paramName ); 00370 $msg = array( $paramName => $paramValue ); 00371 $result = $this->getResult(); 00372 $result->disableSizeCheck(); 00373 $result->addValue( 'query-continue', $this->getModuleName(), $msg ); 00374 $result->enableSizeCheck(); 00375 } 00376 00381 protected function getDB() { 00382 if ( is_null( $this->mDb ) ) { 00383 $apiQuery = $this->getQuery(); 00384 $this->mDb = $apiQuery->getDB(); 00385 } 00386 return $this->mDb; 00387 } 00388 00397 public function selectNamedDB( $name, $db, $groups ) { 00398 $this->mDb = $this->getQuery()->getNamedDB( $name, $db, $groups ); 00399 } 00400 00405 protected function getPageSet() { 00406 return $this->getQuery()->getPageSet(); 00407 } 00408 00414 public function titleToKey( $title ) { 00415 // Don't throw an error if we got an empty string 00416 if ( trim( $title ) == '' ) { 00417 return ''; 00418 } 00419 $t = Title::newFromText( $title ); 00420 if ( !$t ) { 00421 $this->dieUsageMsg( array( 'invalidtitle', $title ) ); 00422 } 00423 return $t->getPrefixedDbKey(); 00424 } 00425 00431 public function keyToTitle( $key ) { 00432 // Don't throw an error if we got an empty string 00433 if ( trim( $key ) == '' ) { 00434 return ''; 00435 } 00436 $t = Title::newFromDbKey( $key ); 00437 // This really shouldn't happen but we gotta check anyway 00438 if ( !$t ) { 00439 $this->dieUsageMsg( array( 'invalidtitle', $key ) ); 00440 } 00441 return $t->getPrefixedText(); 00442 } 00443 00449 public function titlePartToKey( $titlePart ) { 00450 return substr( $this->titleToKey( $titlePart . 'x' ), 0, - 1 ); 00451 } 00452 00458 public function keyPartToTitle( $keyPart ) { 00459 return substr( $this->keyToTitle( $keyPart . 'x' ), 0, - 1 ); 00460 } 00461 00469 public function getDirectionDescription( $p = '', $extraDirText = '' ) { 00470 return array( 00471 "In which direction to enumerate{$extraDirText}", 00472 " newer - List oldest first. Note: {$p}start has to be before {$p}end.", 00473 " older - List newest first (default). Note: {$p}start has to be later than {$p}end.", 00474 ); 00475 } 00476 00482 public function prepareUrlQuerySearchString( $query = null, $protocol = null) { 00483 $db = $this->getDb(); 00484 if ( !is_null( $query ) || $query != '' ) { 00485 if ( is_null( $protocol ) ) { 00486 $protocol = 'http://'; 00487 } 00488 00489 $likeQuery = LinkFilter::makeLikeArray( $query, $protocol ); 00490 if ( !$likeQuery ) { 00491 $this->dieUsage( 'Invalid query', 'bad_query' ); 00492 } 00493 00494 $likeQuery = LinkFilter::keepOneWildcard( $likeQuery ); 00495 return 'el_index ' . $db->buildLike( $likeQuery ); 00496 } elseif ( !is_null( $protocol ) ) { 00497 return 'el_index ' . $db->buildLike( "$protocol", $db->anyString() ); 00498 } 00499 00500 return null; 00501 } 00502 00510 public function showHiddenUsersAddBlockInfo( $showBlockInfo ) { 00511 $userCanViewHiddenUsers = $this->getUser()->isAllowed( 'hideuser' ); 00512 00513 if ( $showBlockInfo || !$userCanViewHiddenUsers ) { 00514 $this->addTables( 'ipblocks' ); 00515 $this->addJoinConds( array( 00516 'ipblocks' => array( 'LEFT JOIN', 'ipb_user=user_id' ), 00517 ) ); 00518 00519 $this->addFields( 'ipb_deleted' ); 00520 00521 if ( $showBlockInfo ) { 00522 $this->addFields( array( 'ipb_reason', 'ipb_by_text', 'ipb_expiry' ) ); 00523 } 00524 00525 // Don't show hidden names 00526 if ( !$userCanViewHiddenUsers ) { 00527 $this->addWhere( 'ipb_deleted = 0 OR ipb_deleted IS NULL' ); 00528 } 00529 } 00530 } 00531 00536 public function validateSha1Hash( $hash ) { 00537 return preg_match( '/[a-fA-F0-9]{40}/', $hash ); 00538 } 00539 00544 public function validateSha1Base36Hash( $hash ) { 00545 return preg_match( '/[a-zA-Z0-9]{31}/', $hash ); 00546 } 00547 00551 public function getPossibleErrors() { 00552 return array_merge( parent::getPossibleErrors(), array( 00553 array( 'invalidtitle', 'title' ), 00554 array( 'invalidtitle', 'key' ), 00555 ) ); 00556 } 00557 00562 public static function getBaseVersion() { 00563 return __CLASS__ . ': $Id$'; 00564 } 00565 } 00566 00570 abstract class ApiQueryGeneratorBase extends ApiQueryBase { 00571 00572 private $mIsGenerator; 00573 00574 public function __construct( $query, $moduleName, $paramPrefix = '' ) { 00575 parent::__construct( $query, $moduleName, $paramPrefix ); 00576 $this->mIsGenerator = false; 00577 } 00578 00583 public function setGeneratorMode() { 00584 $this->mIsGenerator = true; 00585 } 00586 00592 public function encodeParamName( $paramName ) { 00593 if ( $this->mIsGenerator ) { 00594 return 'g' . parent::encodeParamName( $paramName ); 00595 } else { 00596 return parent::encodeParamName( $paramName ); 00597 } 00598 } 00599 00605 public abstract function executeGenerator( $resultPageSet ); 00606 }