Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 127
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiQueryProjectPages
0.00% covered (danger)
0.00%
0 / 127
0.00% covered (danger)
0.00%
0 / 10
870
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 executeGenerator
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 run
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
132
 buildDbQuery
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
72
 handleQueryContinuation
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 generateResultVals
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\PageAssessments\Api;
4
5use ApiBase;
6use ApiPageSet;
7use ApiQuery;
8use ApiQueryGeneratorBase;
9use MediaWiki\Extension\PageAssessments\PageAssessmentsDAO;
10use MediaWiki\Title\Title;
11use Wikimedia\ParamValidator\ParamValidator;
12use Wikimedia\ParamValidator\TypeDef\IntegerDef;
13
14/*
15 * API module for retrieving all the pages associated with a project, for example,
16 * WikiProject Medicine. (T119997)
17 */
18class ApiQueryProjectPages extends ApiQueryGeneratorBase {
19
20    /**
21     * Array of project IDs for the projects listed in the API query
22     * @var array
23     */
24    private $projectIds = [];
25
26    /** @inheritDoc */
27    public function __construct( ApiQuery $query, $moduleName ) {
28        // The prefix pp is already used by the pageprops module, so using wpp instead.
29        parent::__construct( $query, $moduleName, 'wpp' );
30    }
31
32    /**
33     * Evaluate the parameters, perform the requested query, and set up the result
34     */
35    public function execute() {
36        $this->run();
37    }
38
39    /**
40     * Evaluate the parameters, perform the requested query, and set up the result for generator mode
41     * @param ApiPageSet $resultPageSet
42     */
43    public function executeGenerator( $resultPageSet ) {
44        $this->run( $resultPageSet );
45    }
46
47    /**
48     * @param ApiPageSet|null $resultPageSet
49     */
50    private function run( $resultPageSet = null ) {
51        $params = $this->extractRequestParams();
52
53        if ( $params['assessments'] && $resultPageSet !== null ) {
54            $this->addWarning( 'apiwarn-pageassessments-nogeneratorassessments' );
55        }
56
57        $this->buildDbQuery( $params, $resultPageSet );
58
59        // If matching projects were found, run the query.
60        if ( $this->projectIds ) {
61            $db_res = $this->select( __METHOD__ );
62        // Otherwise, just set the result to an empty array (still works with foreach).
63        } else {
64            $db_res = [];
65        }
66
67        if ( $resultPageSet === null ) {
68            $result = $this->getResult();
69            $count = 0;
70            foreach ( $db_res as $row ) {
71                if ( ++$count > $params['limit'] ) {
72                    $this->setContinueEnumParameter( 'continue', "$row->project_id|$row->page_id" );
73                    break;
74                }
75
76                // Change project id back into its corresponding project title
77                $projectTitle = $row->project_name;
78                if ( !$projectTitle ) {
79                    continue;
80                }
81
82                // Add information to result
83                $vals = $this->generateResultVals( $row );
84                $fit = $result->addValue(
85                    [ 'query', 'projects', $projectTitle ], $row->page_id, $vals
86                );
87
88                if ( !$fit ) {
89                    $this->setContinueEnumParameter( 'continue', "$row->project_id|$row->page_id" );
90                    break;
91                }
92
93                // Add metadata to make XML results for pages parse better
94                $result->addIndexedTagName( [ 'query', 'projects', $projectTitle ], 'page' );
95                $result->addArrayType( [ 'query', 'projects', $projectTitle ], 'array' );
96            }
97            // Add metadata to make XML results for projects parse better
98            $result->addIndexedTagName( [ 'query', 'projects' ], 'project' );
99            $result->addArrayType( [ 'query', 'projects' ], 'kvp', 'name' );
100        } else {
101            $count = 0;
102            foreach ( $db_res as $row ) {
103                if ( ++$count > $params['limit'] ) {
104                    $this->setContinueEnumParameter( 'continue', "$row->project_id|$row->page_id" );
105                    break;
106                }
107
108                $resultPageSet->processDbRow( $row );
109            }
110        }
111    }
112
113    /**
114     * @param array $params
115     * @param ApiPageSet|null $resultPageSet
116     */
117    private function buildDbQuery( array $params, $resultPageSet ) {
118        $this->addTables( [ 'page', 'page_assessments' ] );
119        $this->addFields( [
120            'page_id' => 'pa_page_id',
121            'project_id' => 'pa_project_id',
122        ] );
123        $this->addJoinConds( [
124            'page' => [
125                'JOIN',
126                [ 'page_id = pa_page_id' ],
127            ]
128        ] );
129
130        if ( $resultPageSet === null ) {
131            $this->addTables( 'page_assessments_projects' );
132            $this->addFields( [
133                'title' => 'page_title',
134                'namespace' => 'page_namespace',
135                'project_name' => 'pap_project_title'
136            ] );
137            $this->addJoinConds( [
138                'page_assessments_projects' => [
139                    'JOIN',
140                    [ 'pa_project_id = pap_project_id' ],
141                ]
142            ] );
143            if ( $params['assessments'] ) {
144                $this->addFields( [
145                    'class' => 'pa_class',
146                    'importance' => 'pa_importance'
147                ] );
148            }
149        } else {
150            $this->addFields( $resultPageSet->getPageTableFields() );
151        }
152
153        if ( isset( $params['projects'] ) ) {
154            // Convert the project names into corresponding IDs
155            foreach ( $params['projects'] as $project ) {
156                $id = PageAssessmentsDAO::getProjectId( $project );
157                if ( $id ) {
158                    $this->projectIds[] = $id;
159                } else {
160                    $this->addWarning( [ 'apiwarn-pageassessments-badproject',
161                        wfEscapeWikiText( $project ) ] );
162                }
163            }
164        }
165
166        // DB stores project IDs, so that's what goes into the where field
167        $this->addWhereFld( 'pa_project_id', $this->projectIds );
168        $this->addOption( 'LIMIT', $params['limit'] + 1 );
169
170        if ( $params['continue'] !== null ) {
171            $this->handleQueryContinuation( $params['continue'] );
172        }
173
174        // If more than 1 project is requested, order by project first.
175        if ( count( $this->projectIds ) > 1 ) {
176            $this->addOption( 'ORDER BY', [ 'pa_project_id', 'pa_page_id' ] );
177        } else {
178            $this->addOption( 'ORDER BY', 'pa_page_id' );
179        }
180    }
181
182    /**
183     * @param string $continueParam
184     */
185    private function handleQueryContinuation( $continueParam ) {
186        $continues = $this->parseContinueParamOrDie( $continueParam, [ 'int', 'int' ] );
187        $this->addWhere( $this->getDB()->buildComparison( '>=', [
188            'pa_project_id' => $continues[0],
189            'pa_page_id' => $continues[1],
190        ] ) );
191    }
192
193    /**
194     * @param \stdClass $row
195     * @return array
196     */
197    private function generateResultVals( $row ) {
198        $title = Title::makeTitle( $row->namespace, $row->title );
199
200        $vals = [
201            'pageid' => (int)$row->page_id,
202            'ns' => (int)$row->namespace,
203            'title' => $title->getPrefixedText(),
204        ];
205
206        if ( isset( $row->class ) && isset( $row->importance ) ) {
207            $vals['assessment'] = [
208                'class' => $row->class,
209                'importance' => $row->importance,
210            ];
211        }
212
213        return $vals;
214    }
215
216    /** @inheritDoc */
217    public function getAllowedParams() {
218        return [
219            'assessments' => [
220                ParamValidator::PARAM_DEFAULT => false,
221                ParamValidator::PARAM_TYPE => 'boolean',
222            ],
223            'projects' => [
224                ParamValidator::PARAM_ISMULTI => true,
225                ParamValidator::PARAM_REQUIRED => true,
226            ],
227            'limit' => [
228                ParamValidator::PARAM_DEFAULT => 10,
229                ParamValidator::PARAM_TYPE => 'limit',
230                IntegerDef::PARAM_MIN => 1,
231                IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
232                IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
233            ],
234            'continue' => [
235                ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
236            ],
237        ];
238    }
239
240    /** @inheritDoc */
241    public function getExamplesMessages() {
242        return [
243            'action=query&list=projectpages&wppprojects=Medicine|Anatomy'
244                => 'apihelp-query+projectpages-example-simple-1',
245            'action=query&list=projectpages&wppprojects=Medicine&wppassessments=true'
246                => 'apihelp-query+projectpages-example-simple-2',
247            'action=query&generator=projectpages&prop=info&gwppprojects=Textile%20Arts'
248                => 'apihelp-query+projectpages-example-generator',
249        ];
250    }
251
252    /** @inheritDoc */
253    public function getHelpUrls() {
254        return 'https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:PageAssessments';
255    }
256}