Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.33% covered (warning)
73.33%
66 / 90
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiQueryTags
74.16% covered (warning)
74.16%
66 / 89
50.00% covered (danger)
50.00%
3 / 6
28.61
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
68.42% covered (warning)
68.42%
39 / 57
0.00% covered (danger)
0.00%
0 / 1
24.06
 getCacheMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllowedParams
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 4
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/**
3 * Copyright © 2009
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Api;
10
11use MediaWiki\ChangeTags\ChangeTagsFormatter;
12use MediaWiki\ChangeTags\ChangeTagsStore;
13use Wikimedia\ParamValidator\ParamValidator;
14use Wikimedia\ParamValidator\TypeDef\IntegerDef;
15
16/**
17 * Query module to enumerate change tags.
18 *
19 * @ingroup API
20 */
21class ApiQueryTags extends ApiQueryBase {
22
23    public function __construct(
24        ApiQuery $query,
25        string $moduleName,
26        private readonly ChangeTagsStore $changeTagsStore,
27        private readonly ChangeTagsFormatter $changeTagsFormatter,
28    ) {
29        parent::__construct( $query, $moduleName, 'tg' );
30    }
31
32    public function execute() {
33        $params = $this->extractRequestParams();
34
35        $prop = array_fill_keys( $params['prop'], true );
36
37        $fld_displayname = isset( $prop['displayname'] );
38        $fld_description = isset( $prop['description'] );
39        $fld_hitcount = isset( $prop['hitcount'] );
40        $fld_defined = isset( $prop['defined'] );
41        $fld_source = isset( $prop['source'] );
42        $fld_active = isset( $prop['active'] );
43
44        $limit = $params['limit'];
45        $result = $this->getResult();
46
47        $softwareDefinedTags = array_fill_keys( $this->changeTagsStore->listSoftwareDefinedTags(), 0 );
48        $explicitlyDefinedTags = array_fill_keys( $this->changeTagsStore->listExplicitlyDefinedTags(), 0 );
49        $softwareActivatedTags = array_fill_keys( $this->changeTagsStore->listSoftwareActivatedTags(), 0 );
50
51        $tagHitcounts = array_merge(
52            $softwareDefinedTags,
53            $explicitlyDefinedTags,
54            $this->changeTagsStore->tagUsageStatistics()
55        );
56        $tags = array_keys( $tagHitcounts );
57        $tags = $this->changeTagsStore->filterViewableTags( $tags, $this->getAuthority() );
58
59        # Fetch defined tags that aren't past the continuation
60        if ( $params['continue'] !== null ) {
61            $cont = $params['continue'];
62            $tags = array_filter( $tags, static function ( $v ) use ( $cont ) {
63                return $v >= $cont;
64            } );
65        }
66
67        # Now make sure the array is sorted for proper continuation
68        sort( $tags );
69
70        $count = 0;
71        foreach ( $tags as $tagName ) {
72            if ( ++$count > $limit ) {
73                $this->setContinueEnumParameter( 'continue', $tagName );
74                break;
75            }
76
77            $tag = [];
78            $tag['name'] = $tagName;
79
80            if ( $fld_displayname ) {
81                $tag['displayname'] = $this->changeTagsFormatter->getTagDescription( $tagName, $this );
82            }
83
84            if ( $fld_description ) {
85                $msg = $this->msg( "tag-$tagName-description" );
86                $tag['description'] = $msg->exists() ? $msg->text() : '';
87            }
88
89            if ( $fld_hitcount ) {
90                $tag['hitcount'] = (int)$tagHitcounts[$tagName];
91            }
92
93            $isSoftware = isset( $softwareDefinedTags[$tagName] );
94            $isExplicit = isset( $explicitlyDefinedTags[$tagName] );
95
96            if ( $fld_defined ) {
97                $tag['defined'] = $isSoftware || $isExplicit;
98            }
99
100            if ( $fld_source ) {
101                $tag['source'] = [];
102                if ( $isSoftware ) {
103                    $tag['source'][] = 'software';
104                }
105                if ( $isExplicit ) {
106                    $tag['source'][] = 'manual';
107                }
108            }
109
110            if ( $fld_active ) {
111                $tag['active'] = $isExplicit || isset( $softwareActivatedTags[$tagName] );
112            }
113
114            $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $tag );
115            if ( !$fit ) {
116                $this->setContinueEnumParameter( 'continue', $tagName );
117                break;
118            }
119        }
120
121        $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'tag' );
122    }
123
124    /**
125     * Using 'anon-public-user-private' as additional tags may be visible to users with
126     * specific rights, while anon users are likely to always see the same list of tags.
127     *
128     * @inheritDoc
129     */
130    public function getCacheMode( $params ) {
131        return 'anon-public-user-private';
132    }
133
134    /** @inheritDoc */
135    public function getAllowedParams() {
136        return [
137            'continue' => [
138                ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
139            ],
140            'limit' => [
141                ParamValidator::PARAM_DEFAULT => 10,
142                ParamValidator::PARAM_TYPE => 'limit',
143                IntegerDef::PARAM_MIN => 1,
144                IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
145                IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
146            ],
147            'prop' => [
148                ParamValidator::PARAM_DEFAULT => '',
149                ParamValidator::PARAM_TYPE => [
150                    'displayname',
151                    'description',
152                    'hitcount',
153                    'defined',
154                    'source',
155                    'active',
156                ],
157                ParamValidator::PARAM_ISMULTI => true,
158                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
159            ]
160        ];
161    }
162
163    /** @inheritDoc */
164    protected function getExamplesMessages() {
165        return [
166            'action=query&list=tags&tgprop=displayname|description|hitcount|defined'
167                => 'apihelp-query+tags-example-simple',
168        ];
169    }
170
171    /** @inheritDoc */
172    public function getHelpUrls() {
173        return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tags';
174    }
175}
176
177/** @deprecated class alias since 1.43 */
178class_alias( ApiQueryTags::class, 'ApiQueryTags' );