Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 98 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
Hooks | |
0.00% |
0 / 98 |
|
0.00% |
0 / 11 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onInfoAction | |
0.00% |
0 / 37 |
|
0.00% |
0 / 1 |
30 | |||
onApiQuery__ModuleManager | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
onAPIQuerySiteInfoGeneralInfo | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getApiMetricsMap | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getApiScopeMap | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getApiMetricsHelp | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
getApiDaysHelp | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
2 | |||
makeWarningsOnlyStatus | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
toYmd | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
toYmdHis | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\PageViewInfo; |
4 | |
5 | use ApiBase; |
6 | use ApiModuleManager; |
7 | use ApiQuerySiteinfo; |
8 | use ExtensionRegistry; |
9 | use FormatJson; |
10 | use IContextSource; |
11 | use MediaWiki\Api\Hook\ApiQuery__moduleManagerHook; |
12 | use MediaWiki\Api\Hook\APIQuerySiteInfoGeneralInfoHook; |
13 | use MediaWiki\Hook\InfoActionHook; |
14 | use MediaWiki\Html\Html; |
15 | use MediaWiki\MediaWikiServices; |
16 | use StatusValue; |
17 | use Wikimedia\ParamValidator\ParamValidator; |
18 | use Wikimedia\ParamValidator\TypeDef\IntegerDef; |
19 | |
20 | /** |
21 | * @phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName |
22 | */ |
23 | class Hooks implements |
24 | ApiQuery__moduleManagerHook, |
25 | APIQuerySiteInfoGeneralInfoHook, |
26 | InfoActionHook |
27 | { |
28 | |
29 | private PageViewService $pageViewService; |
30 | |
31 | public function __construct( PageViewService $pageViewService ) { |
32 | $this->pageViewService = $pageViewService; |
33 | } |
34 | |
35 | /** |
36 | * Display total pageviews in the last 30 days and show a graph with details when clicked. |
37 | * @param IContextSource $ctx |
38 | * @param array &$pageInfo |
39 | */ |
40 | public function onInfoAction( $ctx, &$pageInfo ) { |
41 | if ( !$this->pageViewService->supports( PageViewService::METRIC_VIEW, |
42 | PageViewService::SCOPE_ARTICLE ) |
43 | ) { |
44 | return; |
45 | } |
46 | $title = $ctx->getTitle(); |
47 | $status = $this->pageViewService->getPageData( [ $title ], 30, PageViewService::METRIC_VIEW ); |
48 | $data = $status->getValue(); |
49 | if ( !$status->isOK() ) { |
50 | return; |
51 | } |
52 | $views = $data[$title->getPrefixedDBkey()]; |
53 | |
54 | $total = array_sum( $views ); |
55 | $start = self::toYmdHis( array_key_first( $views ) ); |
56 | $end = self::toYmdHis( array_key_last( $views ) ); |
57 | |
58 | $lang = $ctx->getLanguage(); |
59 | $formatted = $lang->formatNum( $total ); |
60 | $pageInfo['header-basic'][] = [ |
61 | $ctx->msg( 'pvi-month-count' ), |
62 | Html::rawElement( 'div', |
63 | [ 'class' => 'mw-pvi-month' ], |
64 | $ctx->msg( 'pvi-month-count-value', $formatted, $title->getPrefixedDBkey() )->parse() |
65 | ) |
66 | ]; |
67 | |
68 | if ( ExtensionRegistry::getInstance()->isLoaded( 'Graph' ) ) { |
69 | $info = FormatJson::decode( |
70 | file_get_contents( __DIR__ . '/../graphs/month.json' ), |
71 | true |
72 | ); |
73 | foreach ( $views as $day => $count ) { |
74 | $info['data'][0]['values'][] = [ 'timestamp' => self::toYmd( $day ), 'views' => $count ]; |
75 | } |
76 | |
77 | $ctx->getOutput()->addModules( 'ext.pageviewinfo' ); |
78 | // Ymd -> YmdHis |
79 | $user = $ctx->getUser(); |
80 | $ctx->getOutput()->addJsConfigVars( [ |
81 | 'wgPageViewInfo' => [ |
82 | 'graph' => $info, |
83 | 'start' => $lang->userDate( $start, $user ), |
84 | 'end' => $lang->userDate( $end, $user ), |
85 | ], |
86 | ] ); |
87 | } |
88 | } |
89 | |
90 | /** |
91 | * Limit enabled PageViewInfo API modules to those which are supported by the service. |
92 | * @param ApiModuleManager $moduleManager |
93 | */ |
94 | public function onApiQuery__ModuleManager( $moduleManager ) { |
95 | $moduleMap = [ |
96 | 'pageviews' => [ 'pageviews', 'prop', ApiQueryPageViews::class ], |
97 | 'siteviews' => [ 'siteviews', 'meta', ApiQuerySiteViews::class ], |
98 | 'mostviewed' => [ 'mostviewed', 'list', ApiQueryMostViewed::class ], |
99 | ]; |
100 | foreach ( self::getApiScopeMap() as $apiModuleName => $serviceScopeConstant ) { |
101 | foreach ( self::getApiMetricsMap() as $serviceMetricConstant ) { |
102 | if ( $this->pageViewService->supports( $serviceMetricConstant, $serviceScopeConstant ) ) { |
103 | call_user_func_array( [ $moduleManager, 'addModule' ], $moduleMap[$apiModuleName] ); |
104 | continue 2; |
105 | } |
106 | } |
107 | } |
108 | } |
109 | |
110 | /** |
111 | * Add information to the siteinfo API output about which metrics are supported. |
112 | * @param ApiQuerySiteinfo $module |
113 | * @param array &$result |
114 | */ |
115 | public function onAPIQuerySiteInfoGeneralInfo( $module, &$result ) { |
116 | $supportedMetrics = []; |
117 | foreach ( self::getApiScopeMap() as $apiModuleName => $serviceScopeConstant ) { |
118 | foreach ( self::getApiMetricsMap() as $apiMetricsName => $serviceMetricConstant ) { |
119 | $supportedMetrics[$apiModuleName][$apiMetricsName] = |
120 | $this->pageViewService->supports( $serviceMetricConstant, $serviceScopeConstant ); |
121 | } |
122 | } |
123 | $result['pageviewservice-supported-metrics'] = $supportedMetrics; |
124 | } |
125 | |
126 | /** |
127 | * Maps allowed values of the 'metric' parameter of the pageview-related APIs to service constants. |
128 | * @return array |
129 | */ |
130 | public static function getApiMetricsMap() { |
131 | return [ |
132 | 'pageviews' => PageViewService::METRIC_VIEW, |
133 | 'uniques' => PageViewService::METRIC_UNIQUE, |
134 | ]; |
135 | } |
136 | |
137 | /** |
138 | * Maps API module names to service constants. |
139 | * @return array |
140 | */ |
141 | public static function getApiScopeMap() { |
142 | return [ |
143 | 'pageviews' => PageViewService::SCOPE_ARTICLE, |
144 | 'siteviews' => PageViewService::SCOPE_SITE, |
145 | 'mostviewed' => PageViewService::SCOPE_TOP, |
146 | ]; |
147 | } |
148 | |
149 | /** |
150 | * Returns an array suitable for merging into getAllowedParams() |
151 | * @param string $scope One of the PageViewService::SCOPE_* constants |
152 | * @return array |
153 | */ |
154 | public static function getApiMetricsHelp( $scope ) { |
155 | /** @var PageViewService $service */ |
156 | $service = MediaWikiServices::getInstance()->getService( 'PageViewService' ); |
157 | $metrics = array_keys( array_filter( self::getApiMetricsMap(), |
158 | static function ( $metric ) use ( $scope, $service ) { |
159 | return $service->supports( $metric, $scope ); |
160 | } ) ); |
161 | $reverseMap = array_flip( self::getApiMetricsMap() ); |
162 | $default = $reverseMap[PageViewService::METRIC_VIEW] ?? reset( $reverseMap ); |
163 | |
164 | return $default ? [ |
165 | 'metric' => [ |
166 | ParamValidator::PARAM_TYPE => $metrics, |
167 | ParamValidator::PARAM_DEFAULT => $default, |
168 | ApiBase::PARAM_HELP_MSG => 'apihelp-pageviewinfo-param-metric', |
169 | ApiBase::PARAM_HELP_MSG_PER_VALUE => array_map( static function ( $metric ) { |
170 | return 'apihelp-pageviewinfo-paramvalue-metric-' . $metric; |
171 | }, array_combine( $metrics, $metrics ) ), |
172 | ], |
173 | ] : []; |
174 | } |
175 | |
176 | /** |
177 | * Returns an array suitable for merging into getAllowedParams() |
178 | * @return array |
179 | */ |
180 | public static function getApiDaysHelp() { |
181 | $days = MediaWikiServices::getInstance()->getConfigFactory()->makeConfig( 'PageViewInfo' ) |
182 | ->get( 'PageViewApiMaxDays' ); |
183 | return [ |
184 | 'days' => [ |
185 | ParamValidator::PARAM_TYPE => 'integer', |
186 | ParamValidator::PARAM_DEFAULT => $days, |
187 | IntegerDef::PARAM_MAX => $days, |
188 | IntegerDef::PARAM_MIN => 1, |
189 | ApiBase::PARAM_HELP_MSG => 'apihelp-pageviewinfo-param-days', |
190 | ], |
191 | ]; |
192 | } |
193 | |
194 | /** |
195 | * Transform into a status with errors replaced with warnings |
196 | * @param StatusValue $status |
197 | * @return StatusValue |
198 | */ |
199 | public static function makeWarningsOnlyStatus( StatusValue $status ) { |
200 | [ $errors, $warnings ] = $status->splitByErrorType(); |
201 | foreach ( $errors->getErrors() as $error ) { |
202 | call_user_func_array( [ $warnings, 'warning' ], |
203 | array_merge( [ $error['message'] ], $error['params'] ) ); |
204 | } |
205 | return $warnings; |
206 | } |
207 | |
208 | /** |
209 | * Convert YYYY-MM-DD to YYYYMMDD |
210 | * @param string $date |
211 | * @return string |
212 | */ |
213 | protected static function toYmd( $date ) { |
214 | return substr( $date, 0, 4 ) . substr( $date, 5, 2 ) . substr( $date, 8, 2 ); |
215 | } |
216 | |
217 | /** |
218 | * Convert YYYY-MM-DD to TS_MW |
219 | * @param string $date |
220 | * @return string |
221 | */ |
222 | protected static function toYmdHis( $date ) { |
223 | return substr( $date, 0, 4 ) . substr( $date, 5, 2 ) . substr( $date, 8, 2 ) . '000000'; |
224 | } |
225 | } |