MediaWiki  REL1_24
ApiQueryLinks.php
Go to the documentation of this file.
00001 <?php
00032 class ApiQueryLinks extends ApiQueryGeneratorBase {
00033 
00034     const LINKS = 'links';
00035     const TEMPLATES = 'templates';
00036 
00037     private $table, $prefix, $description, $helpUrl;
00038 
00039     public function __construct( ApiQuery $query, $moduleName ) {
00040         switch ( $moduleName ) {
00041             case self::LINKS:
00042                 $this->table = 'pagelinks';
00043                 $this->prefix = 'pl';
00044                 $this->description = 'link';
00045                 $this->titlesParam = 'titles';
00046                 $this->titlesParamDescription = 'Only list links to these titles. Useful ' .
00047                     'for checking whether a certain page links to a certain title.';
00048                 $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#links_.2F_pl';
00049                 break;
00050             case self::TEMPLATES:
00051                 $this->table = 'templatelinks';
00052                 $this->prefix = 'tl';
00053                 $this->description = 'template';
00054                 $this->titlesParam = 'templates';
00055                 $this->titlesParamDescription = 'Only list these templates. Useful ' .
00056                     'for checking whether a certain page uses a certain template.';
00057                 $this->helpUrl = 'https://www.mediawiki.org/wiki/API:Properties#templates_.2F_tl';
00058                 break;
00059             default:
00060                 ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
00061         }
00062 
00063         parent::__construct( $query, $moduleName, $this->prefix );
00064     }
00065 
00066     public function execute() {
00067         $this->run();
00068     }
00069 
00070     public function getCacheMode( $params ) {
00071         return 'public';
00072     }
00073 
00074     public function executeGenerator( $resultPageSet ) {
00075         $this->run( $resultPageSet );
00076     }
00077 
00081     private function run( $resultPageSet = null ) {
00082         if ( $this->getPageSet()->getGoodTitleCount() == 0 ) {
00083             return; // nothing to do
00084         }
00085 
00086         $params = $this->extractRequestParams();
00087 
00088         $this->addFields( array(
00089             'pl_from' => $this->prefix . '_from',
00090             'pl_namespace' => $this->prefix . '_namespace',
00091             'pl_title' => $this->prefix . '_title'
00092         ) );
00093 
00094         $this->addTables( $this->table );
00095         $this->addWhereFld( $this->prefix . '_from', array_keys( $this->getPageSet()->getGoodTitles() ) );
00096         $this->addWhereFld( $this->prefix . '_namespace', $params['namespace'] );
00097 
00098         if ( !is_null( $params[$this->titlesParam] ) ) {
00099             $lb = new LinkBatch;
00100             foreach ( $params[$this->titlesParam] as $t ) {
00101                 $title = Title::newFromText( $t );
00102                 if ( !$title ) {
00103                     $this->setWarning( "\"$t\" is not a valid title" );
00104                 } else {
00105                     $lb->addObj( $title );
00106                 }
00107             }
00108             $cond = $lb->constructSet( $this->prefix, $this->getDB() );
00109             if ( $cond ) {
00110                 $this->addWhere( $cond );
00111             }
00112         }
00113 
00114         if ( !is_null( $params['continue'] ) ) {
00115             $cont = explode( '|', $params['continue'] );
00116             $this->dieContinueUsageIf( count( $cont ) != 3 );
00117             $op = $params['dir'] == 'descending' ? '<' : '>';
00118             $plfrom = intval( $cont[0] );
00119             $plns = intval( $cont[1] );
00120             $pltitle = $this->getDB()->addQuotes( $cont[2] );
00121             $this->addWhere(
00122                 "{$this->prefix}_from $op $plfrom OR " .
00123                 "({$this->prefix}_from = $plfrom AND " .
00124                 "({$this->prefix}_namespace $op $plns OR " .
00125                 "({$this->prefix}_namespace = $plns AND " .
00126                 "{$this->prefix}_title $op= $pltitle)))"
00127             );
00128         }
00129 
00130         $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
00131         // Here's some MySQL craziness going on: if you use WHERE foo='bar'
00132         // and later ORDER BY foo MySQL doesn't notice the ORDER BY is pointless
00133         // but instead goes and filesorts, because the index for foo was used
00134         // already. To work around this, we drop constant fields in the WHERE
00135         // clause from the ORDER BY clause
00136         $order = array();
00137         if ( count( $this->getPageSet()->getGoodTitles() ) != 1 ) {
00138             $order[] = $this->prefix . '_from' . $sort;
00139         }
00140         if ( count( $params['namespace'] ) != 1 ) {
00141             $order[] = $this->prefix . '_namespace' . $sort;
00142         }
00143 
00144         $order[] = $this->prefix . '_title' . $sort;
00145         $this->addOption( 'ORDER BY', $order );
00146         $this->addOption( 'USE INDEX', $this->prefix . '_from' );
00147         $this->addOption( 'LIMIT', $params['limit'] + 1 );
00148 
00149         $res = $this->select( __METHOD__ );
00150 
00151         if ( is_null( $resultPageSet ) ) {
00152             $count = 0;
00153             foreach ( $res as $row ) {
00154                 if ( ++$count > $params['limit'] ) {
00155                     // We've reached the one extra which shows that
00156                     // there are additional pages to be had. Stop here...
00157                     $this->setContinueEnumParameter( 'continue',
00158                         "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
00159                     break;
00160                 }
00161                 $vals = array();
00162                 ApiQueryBase::addTitleInfo( $vals, Title::makeTitle( $row->pl_namespace, $row->pl_title ) );
00163                 $fit = $this->addPageSubItem( $row->pl_from, $vals );
00164                 if ( !$fit ) {
00165                     $this->setContinueEnumParameter( 'continue',
00166                         "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
00167                     break;
00168                 }
00169             }
00170         } else {
00171             $titles = array();
00172             $count = 0;
00173             foreach ( $res as $row ) {
00174                 if ( ++$count > $params['limit'] ) {
00175                     // We've reached the one extra which shows that
00176                     // there are additional pages to be had. Stop here...
00177                     $this->setContinueEnumParameter( 'continue',
00178                         "{$row->pl_from}|{$row->pl_namespace}|{$row->pl_title}" );
00179                     break;
00180                 }
00181                 $titles[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
00182             }
00183             $resultPageSet->populateFromTitles( $titles );
00184         }
00185     }
00186 
00187     public function getAllowedParams() {
00188         return array(
00189             'namespace' => array(
00190                 ApiBase::PARAM_TYPE => 'namespace',
00191                 ApiBase::PARAM_ISMULTI => true
00192             ),
00193             'limit' => array(
00194                 ApiBase::PARAM_DFLT => 10,
00195                 ApiBase::PARAM_TYPE => 'limit',
00196                 ApiBase::PARAM_MIN => 1,
00197                 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
00198                 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
00199             ),
00200             'continue' => null,
00201             $this->titlesParam => array(
00202                 ApiBase::PARAM_ISMULTI => true,
00203             ),
00204             'dir' => array(
00205                 ApiBase::PARAM_DFLT => 'ascending',
00206                 ApiBase::PARAM_TYPE => array(
00207                     'ascending',
00208                     'descending'
00209                 )
00210             ),
00211         );
00212     }
00213 
00214     public function getParamDescription() {
00215         $desc = $this->description;
00216 
00217         return array(
00218             'namespace' => "Show {$desc}s in this namespace(s) only",
00219             'limit' => "How many {$desc}s to return",
00220             'continue' => 'When more results are available, use this to continue',
00221             $this->titlesParam => $this->titlesParamDescription,
00222             'dir' => 'The direction in which to list',
00223         );
00224     }
00225 
00226     public function getDescription() {
00227         return "Returns all {$this->description}s from the given page(s).";
00228     }
00229 
00230     public function getExamples() {
00231         $desc = $this->description;
00232         $name = $this->getModuleName();
00233 
00234         return array(
00235             "api.php?action=query&prop={$name}&titles=Main%20Page" => "Get {$desc}s from the [[Main Page]]",
00236             "api.php?action=query&generator={$name}&titles=Main%20Page&prop=info"
00237                 => "Get information about the {$desc} pages in the [[Main Page]]",
00238             "api.php?action=query&prop={$name}&titles=Main%20Page&{$this->prefix}namespace=2|10"
00239                 => "Get {$desc}s from the Main Page in the User and Template namespaces",
00240         );
00241     }
00242 
00243     public function getHelpUrls() {
00244         return $this->helpUrl;
00245     }
00246 }