Use SpecialPageFactory in ApiQueryQueryPage
authorLucas Werkmeister <lucas.werkmeister@wikimedia.de>
Fri, 14 Dec 2018 15:56:56 +0000 (16:56 +0100)
committerLucas Werkmeister <lucas.werkmeister@wikimedia.de>
Fri, 14 Dec 2018 17:50:22 +0000 (18:50 +0100)
Instead of assuming that all query page classes can be instantiated with
no constructor parameters, use a SpecialPageFactory.

This would not have prevented T208924 (that would just have resulted in
a later, different error), but it’s just a good idea in general.

Change-Id: I2473a53acd9fefdeffb1fa7ecb88873f3ee345cc

includes/api/ApiQueryQueryPage.php

index 8758d9c..ea20664 100644 (file)
  * @file
  */
 
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Special\SpecialPageFactory;
+
 /**
  * Query module to get the results of a QueryPage-based special page
  *
  * @ingroup API
  */
 class ApiQueryQueryPage extends ApiQueryGeneratorBase {
-       private $qpMap;
+
+       /**
+        * @var string[] list of special page names
+        */
+       private $queryPages;
+
+       /**
+        * @var SpecialPageFactory
+        */
+       private $specialPageFactory;
 
        public function __construct( ApiQuery $query, $moduleName ) {
                parent::__construct( $query, $moduleName, 'qp' );
-               // Build mapping from special page names to QueryPage classes
-               $uselessQueryPages = $this->getConfig()->get( 'APIUselessQueryPages' );
-               $this->qpMap = [];
-               foreach ( QueryPage::getPages() as $page ) {
-                       if ( !in_array( $page[1], $uselessQueryPages ) ) {
-                               $this->qpMap[$page[1]] = $page[0];
-                       }
-               }
+               $this->queryPages = array_values( array_diff(
+                       array_column( QueryPage::getPages(), 1 ), // [ class, name ]
+                       $this->getConfig()->get( 'APIUselessQueryPages' )
+               ) );
+               $this->specialPageFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
        }
 
        public function execute() {
@@ -48,6 +57,27 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase {
                $this->run( $resultPageSet );
        }
 
+       /**
+        * @param string $name
+        * @return QueryPage
+        */
+       private function getSpecialPage( $name ) {
+               $qp = $this->specialPageFactory->getPage( $name );
+               if ( !$qp ) {
+                       self::dieDebug(
+                               __METHOD__,
+                               'SpecialPageFactory failed to create special page ' . $name
+                       );
+               }
+               if ( !( $qp instanceof QueryPage ) ) {
+                       self::dieDebug(
+                               __METHOD__,
+                               'Special page ' . $name . ' is not a QueryPage'
+                       );
+               }
+               return $qp;
+       }
+
        /**
         * @param ApiPageSet|null $resultPageSet
         */
@@ -55,8 +85,7 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase {
                $params = $this->extractRequestParams();
                $result = $this->getResult();
 
-               /** @var QueryPage $qp */
-               $qp = new $this->qpMap[$params['page']]();
+               $qp = $this->getSpecialPage( $params['page'] );
                if ( !$qp->userCanExecute( $this->getUser() ) ) {
                        $this->dieWithError( 'apierror-specialpage-cantexecute' );
                }
@@ -125,8 +154,7 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase {
        }
 
        public function getCacheMode( $params ) {
-               /** @var QueryPage $qp */
-               $qp = new $this->qpMap[$params['page']]();
+               $qp = $this->getSpecialPage( $params['page'] );
                if ( $qp->getRestriction() != '' ) {
                        return 'private';
                }
@@ -137,7 +165,7 @@ class ApiQueryQueryPage extends ApiQueryGeneratorBase {
        public function getAllowedParams() {
                return [
                        'page' => [
-                               ApiBase::PARAM_TYPE => array_keys( $this->qpMap ),
+                               ApiBase::PARAM_TYPE => $this->queryPages,
                                ApiBase::PARAM_REQUIRED => true
                        ],
                        'offset' => [