MediaWiki
REL1_22
|
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 $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, ApiResult::ADD_ON_TOP ); 00374 $result->enableSizeCheck(); 00375 } 00376 00381 protected function getDB() { 00382 if ( is_null( $this->mDb ) ) { 00383 $this->mDb = $this->getQuery()->getDB(); 00384 } 00385 return $this->mDb; 00386 } 00387 00396 public function selectNamedDB( $name, $db, $groups ) { 00397 $this->mDb = $this->getQuery()->getNamedDB( $name, $db, $groups ); 00398 } 00399 00404 protected function getPageSet() { 00405 return $this->getQuery()->getPageSet(); 00406 } 00407 00413 public function titleToKey( $title ) { 00414 // Don't throw an error if we got an empty string 00415 if ( trim( $title ) == '' ) { 00416 return ''; 00417 } 00418 $t = Title::newFromText( $title ); 00419 if ( !$t ) { 00420 $this->dieUsageMsg( array( 'invalidtitle', $title ) ); 00421 } 00422 return $t->getPrefixedDBkey(); 00423 } 00424 00430 public function keyToTitle( $key ) { 00431 // Don't throw an error if we got an empty string 00432 if ( trim( $key ) == '' ) { 00433 return ''; 00434 } 00435 $t = Title::newFromDBkey( $key ); 00436 // This really shouldn't happen but we gotta check anyway 00437 if ( !$t ) { 00438 $this->dieUsageMsg( array( 'invalidtitle', $key ) ); 00439 } 00440 return $t->getPrefixedText(); 00441 } 00442 00448 public function titlePartToKey( $titlePart ) { 00449 return substr( $this->titleToKey( $titlePart . 'x' ), 0, - 1 ); 00450 } 00451 00457 public function keyPartToTitle( $keyPart ) { 00458 return substr( $this->keyToTitle( $keyPart . 'x' ), 0, - 1 ); 00459 } 00460 00468 public function getDirectionDescription( $p = '', $extraDirText = '' ) { 00469 return array( 00470 "In which direction to enumerate{$extraDirText}", 00471 " newer - List oldest first. Note: {$p}start has to be before {$p}end.", 00472 " older - List newest first (default). Note: {$p}start has to be later than {$p}end.", 00473 ); 00474 } 00475 00481 public function prepareUrlQuerySearchString( $query = null, $protocol = null ) { 00482 $db = $this->getDb(); 00483 if ( !is_null( $query ) || $query != '' ) { 00484 if ( is_null( $protocol ) ) { 00485 $protocol = 'http://'; 00486 } 00487 00488 $likeQuery = LinkFilter::makeLikeArray( $query, $protocol ); 00489 if ( !$likeQuery ) { 00490 $this->dieUsage( 'Invalid query', 'bad_query' ); 00491 } 00492 00493 $likeQuery = LinkFilter::keepOneWildcard( $likeQuery ); 00494 return 'el_index ' . $db->buildLike( $likeQuery ); 00495 } elseif ( !is_null( $protocol ) ) { 00496 return 'el_index ' . $db->buildLike( "$protocol", $db->anyString() ); 00497 } 00498 00499 return null; 00500 } 00501 00509 public function showHiddenUsersAddBlockInfo( $showBlockInfo ) { 00510 $userCanViewHiddenUsers = $this->getUser()->isAllowed( 'hideuser' ); 00511 00512 if ( $showBlockInfo || !$userCanViewHiddenUsers ) { 00513 $this->addTables( 'ipblocks' ); 00514 $this->addJoinConds( array( 00515 'ipblocks' => array( 'LEFT JOIN', 'ipb_user=user_id' ), 00516 ) ); 00517 00518 $this->addFields( 'ipb_deleted' ); 00519 00520 if ( $showBlockInfo ) { 00521 $this->addFields( array( 'ipb_id', 'ipb_by', 'ipb_by_text', 'ipb_reason', 'ipb_expiry' ) ); 00522 } 00523 00524 // Don't show hidden names 00525 if ( !$userCanViewHiddenUsers ) { 00526 $this->addWhere( 'ipb_deleted = 0 OR ipb_deleted IS NULL' ); 00527 } 00528 } 00529 } 00530 00535 public function validateSha1Hash( $hash ) { 00536 return preg_match( '/^[a-f0-9]{40}$/', $hash ); 00537 } 00538 00543 public function validateSha1Base36Hash( $hash ) { 00544 return preg_match( '/^[a-z0-9]{31}$/', $hash ); 00545 } 00546 00550 public function getPossibleErrors() { 00551 $errors = parent::getPossibleErrors(); 00552 $errors = array_merge( $errors, array( 00553 array( 'invalidtitle', 'title' ), 00554 array( 'invalidtitle', 'key' ), 00555 ) ); 00556 return $errors; 00557 } 00558 } 00559 00563 abstract class ApiQueryGeneratorBase extends ApiQueryBase { 00564 00565 private $mGeneratorPageSet = null; 00566 00574 public function setGeneratorMode( ApiPageSet $generatorPageSet ) { 00575 if ( $generatorPageSet === null ) { 00576 ApiBase::dieDebug( __METHOD__, 'Required parameter missing - $generatorPageSet' ); 00577 } 00578 $this->mGeneratorPageSet = $generatorPageSet; 00579 } 00580 00586 protected function getPageSet() { 00587 if ( $this->mGeneratorPageSet !== null ) { 00588 return $this->mGeneratorPageSet; 00589 } 00590 return parent::getPageSet(); 00591 } 00592 00598 public function encodeParamName( $paramName ) { 00599 if ( $this->mGeneratorPageSet !== null ) { 00600 return 'g' . parent::encodeParamName( $paramName ); 00601 } else { 00602 return parent::encodeParamName( $paramName ); 00603 } 00604 } 00605 00612 protected function setContinueEnumParameter( $paramName, $paramValue ) { 00613 // If this is a generator and query->setGeneratorContinue() returns false, treat as before 00614 if ( $this->mGeneratorPageSet === null 00615 || !$this->getQuery()->setGeneratorContinue( $this, $paramName, $paramValue ) 00616 ) { 00617 parent::setContinueEnumParameter( $paramName, $paramValue ); 00618 } 00619 } 00620 00626 abstract public function executeGenerator( $resultPageSet ); 00627 }