MediaWiki master
SpecialStatistics.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Specials;
25
34use Xml;
35
43 private int $edits;
44 private int $good;
45 private int $images;
46 private int $total;
47 private int $users;
48 private int $activeUsers;
49
50 private UserGroupManager $userGroupManager;
51
55 public function __construct( UserGroupManager $userGroupManager ) {
56 parent::__construct( 'Statistics' );
57 $this->userGroupManager = $userGroupManager;
58 }
59
60 public function execute( $par ) {
61 $this->setHeaders();
62 $this->outputHeader();
63 $this->getOutput()->addModuleStyles( 'mediawiki.special' );
64
65 $this->edits = SiteStats::edits();
66 $this->good = SiteStats::articles();
67 $this->images = SiteStats::images();
68 $this->total = SiteStats::pages();
69 $this->users = SiteStats::users();
70 $this->activeUsers = SiteStats::activeUsers();
71
72 $text = Xml::openElement( 'table', [ 'class' => 'wikitable mw-statistics-table' ] );
73
74 # Statistic - pages
75 $text .= $this->getPageStats();
76
77 # Statistic - edits
78 $text .= $this->getEditStats();
79
80 # Statistic - users
81 $text .= $this->getUserStats();
82
83 # Statistic - usergroups
84 $text .= $this->getGroupStats();
85
86 # Statistic - other
87 $extraStats = [];
88 if ( $this->getHookRunner()->onSpecialStatsAddExtra(
89 $extraStats, $this->getContext() )
90 ) {
91 $text .= $this->getOtherStats( $extraStats );
92 }
93
94 $text .= Xml::closeElement( 'table' );
95
96 # Customizable footer
97 $footer = $this->msg( 'statistics-footer' );
98 if ( !$footer->isBlank() ) {
99 $text .= "\n" . $footer->parse();
100 }
101
102 $this->getOutput()->addHTML( $text );
103 }
104
114 private function formatRow( $text, $number, $trExtraParams = [],
115 $descMsg = '', $descMsgParam = ''
116 ) {
117 if ( $descMsg ) {
118 $msg = $this->msg( $descMsg, $descMsgParam );
119 if ( !$msg->isDisabled() ) {
120 $descriptionHtml = $this->msg( 'parentheses' )->rawParams( $msg->parse() )
121 ->escaped();
122 $text .= "<br />" . Html::rawElement(
123 'small',
124 [ 'class' => 'mw-statistic-desc' ],
125 " $descriptionHtml"
126 );
127 }
128 }
129
130 return Html::rawElement( 'tr', $trExtraParams,
131 Html::rawElement( 'td', [], $text ) .
132 Html::rawElement( 'td', [ 'class' => 'mw-statistics-numbers' ], $number )
133 );
134 }
135
141 private function getPageStats() {
142 $linkRenderer = $this->getLinkRenderer();
143
144 $specialAllPagesTitle = SpecialPage::getTitleFor( 'Allpages' );
145 $pageStatsHtml = Xml::openElement( 'tr' ) .
146 Xml::tags( 'th', [ 'colspan' => '2' ], $this->msg( 'statistics-header-pages' )
147 ->parse() ) .
148 Xml::closeElement( 'tr' ) .
149 $this->formatRow(
151 ? $this->msg( 'statistics-articles' )->escaped()
152 : $linkRenderer->makeKnownLink(
153 $specialAllPagesTitle,
154 $this->msg( 'statistics-articles' )->text(),
155 [], [ 'hideredirects' => 1 ] ),
156 $this->getLanguage()->formatNum( $this->good ),
157 [ 'class' => 'mw-statistics-articles' ],
158 'statistics-articles-desc' ) .
159 $this->formatRow( $linkRenderer->makeKnownLink( $specialAllPagesTitle,
160 $this->msg( 'statistics-pages' )->text() ),
161 $this->getLanguage()->formatNum( $this->total ),
162 [ 'class' => 'mw-statistics-pages' ],
163 'statistics-pages-desc' );
164
165 // Show the image row only, when there are files or upload is possible
166 if ( $this->images !== 0 || $this->getConfig()->get( MainConfigNames::EnableUploads ) ) {
167 $pageStatsHtml .= $this->formatRow(
168 $linkRenderer->makeKnownLink( SpecialPage::getTitleFor( 'MediaStatistics' ),
169 $this->msg( 'statistics-files' )->text() ),
170 $this->getLanguage()->formatNum( $this->images ),
171 [ 'class' => 'mw-statistics-files' ], 'statistics-files-desc' );
172 }
173
174 return $pageStatsHtml;
175 }
176
177 private function getEditStats() {
178 return Xml::openElement( 'tr' ) .
179 Xml::tags( 'th', [ 'colspan' => '2' ],
180 $this->msg( 'statistics-header-edits' )->parse() ) .
181 Xml::closeElement( 'tr' ) .
182 $this->formatRow( $this->msg( 'statistics-edits' )->parse(),
183 $this->getLanguage()->formatNum( $this->edits ),
184 [ 'class' => 'mw-statistics-edits' ]
185 ) .
186 $this->formatRow( $this->msg( 'statistics-edits-average' )->parse(),
187 $this->getLanguage()->formatNum(
188 sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 )
189 ), [ 'class' => 'mw-statistics-edits-average' ]
190 );
191 }
192
193 private function getUserStats() {
194 return Xml::openElement( 'tr' ) .
195 Xml::tags( 'th', [ 'colspan' => '2' ],
196 $this->msg( 'statistics-header-users' )->parse() ) .
197 Xml::closeElement( 'tr' ) .
198 $this->formatRow( $this->msg( 'statistics-users' )->parse() . ' ' .
199 $this->getLinkRenderer()->makeKnownLink(
200 SpecialPage::getTitleFor( 'Listusers' ),
201 $this->msg( 'listgrouprights-members' )->text()
202 ),
203 $this->getLanguage()->formatNum( $this->users ),
204 [ 'class' => 'mw-statistics-users' ]
205 ) .
206 $this->formatRow( $this->msg( 'statistics-users-active' )->parse() . ' ' .
207 $this->getLinkRenderer()->makeKnownLink(
208 SpecialPage::getTitleFor( 'Activeusers' ),
209 $this->msg( 'listgrouprights-members' )->text()
210 ),
211 $this->getLanguage()->formatNum( $this->activeUsers ),
212 [ 'class' => 'mw-statistics-users-active' ],
213 'statistics-users-active-desc',
214 $this->getLanguage()->formatNum(
216 );
217 }
218
219 private function getGroupStats() {
220 $linkRenderer = $this->getLinkRenderer();
221 $lang = $this->getLanguage();
222 $text = '';
223 foreach ( $this->userGroupManager->listAllGroups() as $group ) {
224 $groupnameLocalized = $lang->getGroupName( $group );
225 $linkTarget = UserGroupMembership::getGroupPage( $group )
226 ?: Title::makeTitleSafe( NS_PROJECT, $group );
227
228 if ( $linkTarget ) {
229 $grouppage = $linkRenderer->makeLink(
230 $linkTarget,
231 $groupnameLocalized
232 );
233 } else {
234 $grouppage = htmlspecialchars( $groupnameLocalized );
235 }
236
237 $grouplink = $linkRenderer->makeKnownLink(
238 SpecialPage::getTitleFor( 'Listusers' ),
239 $this->msg( 'listgrouprights-members' )->text(),
240 [],
241 [ 'group' => $group ]
242 );
243 # Add a class when a usergroup contains no members to allow hiding these rows
244 $classZero = '';
245 $countUsers = SiteStats::numberingroup( $group );
246 if ( $countUsers == 0 ) {
247 $classZero = ' statistics-group-zero';
248 }
249 $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
250 $this->getLanguage()->formatNum( $countUsers ),
251 [ 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) .
252 $classZero ] );
253 }
254
255 return $text;
256 }
257
265 private function getOtherStats( array $stats ) {
266 $return = '';
267
268 foreach ( $stats as $header => $items ) {
269 // Identify the structure used
270 if ( is_array( $items ) ) {
271 // Ignore headers that are recursively set as legacy header
272 if ( $header !== 'statistics-header-hooks' ) {
273 $return .= $this->formatRowHeader( $header );
274 }
275
276 // Collect all items that belong to the same header
277 foreach ( $items as $key => $value ) {
278 if ( is_array( $value ) ) {
279 $name = $value['name'];
280 $number = $value['number'];
281 } else {
282 $name = $this->msg( $key )->parse();
283 $number = $value;
284 }
285
286 $return .= $this->formatRow(
287 $name,
288 $this->getLanguage()->formatNum( htmlspecialchars( $number ) ),
289 [ 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ]
290 );
291 }
292 } else {
293 // Create the legacy header only once
294 if ( $return === '' ) {
295 $return .= $this->formatRowHeader( 'statistics-header-hooks' );
296 }
297
298 // Recursively remap the legacy structure
299 $return .= $this->getOtherStats( [ 'statistics-header-hooks' =>
300 [ $header => $items ] ] );
301 }
302 }
303
304 return $return;
305 }
306
313 private function formatRowHeader( $header ) {
314 return Xml::openElement( 'tr' ) .
315 Xml::tags( 'th', [ 'colspan' => '2' ], $this->msg( $header )->parse() ) .
316 Xml::closeElement( 'tr' );
317 }
318
319 protected function getGroupName() {
320 return 'wiki';
321 }
322}
323
328class_alias( SpecialStatistics::class, 'SpecialStatistics' );
const NS_PROJECT
Definition Defines.php:68
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
A class containing constants representing the names of configuration variables.
const EnableUploads
Name constant for the EnableUploads setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
const ActiveUserDays
Name constant for the ActiveUserDays setting, for use with Config::get()
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:46
Static accessor class for site_stats and related things.
Definition SiteStats.php:36
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getLanguage()
Shortcut to get user's language.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Special page lists various statistics, including the contents of site_stats, plus page view details i...
execute( $par)
Default execute method Checks user permissions.
__construct(UserGroupManager $userGroupManager)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Represents a title within MediaWiki.
Definition Title.php:78
Represents a "user group membership" – a specific instance of a user belonging to a group.
Module of static functions for generating XML.
Definition Xml.php:33
static closeElement( $element)
Shortcut to close an XML element.
Definition Xml.php:124
static openElement( $element, $attribs=null)
This opens an XML element.
Definition Xml.php:115
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition Xml.php:141
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
$header
$footer