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