MediaWiki master
SpecialStatistics.php
Go to the documentation of this file.
1<?php
21namespace MediaWiki\Specials;
22
32
40 private int $edits;
41 private int $good;
42 private int $images;
43 private int $total;
44 private int $users;
45 private int $activeUsers;
46
47 private UserGroupManager $userGroupManager;
48
49 public function __construct( UserGroupManager $userGroupManager ) {
50 parent::__construct( 'Statistics' );
51 $this->userGroupManager = $userGroupManager;
52 }
53
54 public function execute( $par ) {
55 $this->setHeaders();
56 $this->outputHeader();
57 $this->getOutput()->addModuleStyles( 'mediawiki.special' );
58
59 $this->edits = SiteStats::edits();
60 $this->good = SiteStats::articles();
61 $this->images = SiteStats::images();
62 $this->total = SiteStats::pages();
63 $this->users = SiteStats::users();
64 $this->activeUsers = SiteStats::activeUsers();
65
66 $text = Xml::openElement( 'table', [ 'class' => 'wikitable mw-statistics-table' ] );
67
68 # Statistic - pages
69 $text .= $this->getPageStats();
70
71 # Statistic - edits
72 $text .= $this->getEditStats();
73
74 # Statistic - users
75 $text .= $this->getUserStats();
76
77 # Statistic - usergroups
78 $text .= $this->getGroupStats();
79
80 # Statistic - other
81 $extraStats = [];
82 if ( $this->getHookRunner()->onSpecialStatsAddExtra(
83 $extraStats, $this->getContext() )
84 ) {
85 $text .= $this->getOtherStats( $extraStats );
86 }
87
88 $text .= Xml::closeElement( 'table' );
89
90 # Customizable footer
91 $footer = $this->msg( 'statistics-footer' );
92 if ( !$footer->isBlank() ) {
93 $text .= "\n" . $footer->parse();
94 }
95
96 $this->getOutput()->addHTML( $text );
97 }
98
108 private function formatRow( $text, $number, $trExtraParams = [],
109 $descMsg = '', $descMsgParam = ''
110 ) {
111 if ( $descMsg ) {
112 $msg = $this->msg( $descMsg, $descMsgParam );
113 if ( !$msg->isDisabled() ) {
114 $descriptionHtml = $this->msg( 'parentheses' )->rawParams( $msg->parse() )
115 ->escaped();
116 $text .= "<br />" . Html::rawElement(
117 'small',
118 [ 'class' => 'mw-statistic-desc' ],
119 " $descriptionHtml"
120 );
121 }
122 }
123
124 return Html::rawElement( 'tr', $trExtraParams,
125 Html::rawElement( 'td', [], $text ) .
126 Html::rawElement( 'td', [ 'class' => 'mw-statistics-numbers' ], $number )
127 );
128 }
129
135 private function getPageStats() {
136 $linkRenderer = $this->getLinkRenderer();
137
138 $specialAllPagesTitle = SpecialPage::getTitleFor( 'Allpages' );
139 $pageStatsHtml = Html::rawElement( 'tr', [],
140 Xml::tags( 'th', [ 'colspan' => '2' ],
141 $this->msg( 'statistics-header-pages' )->parse()
142 ) ) .
143 $this->formatRow(
145 ? $this->msg( 'statistics-articles' )->escaped()
146 : $linkRenderer->makeKnownLink(
147 $specialAllPagesTitle,
148 $this->msg( 'statistics-articles' )->text(),
149 [], [ 'hideredirects' => 1 ] ),
150 $this->getLanguage()->formatNum( $this->good ),
151 [ 'class' => 'mw-statistics-articles' ],
152 'statistics-articles-desc' ) .
153 $this->formatRow( $linkRenderer->makeKnownLink( $specialAllPagesTitle,
154 $this->msg( 'statistics-pages' )->text() ),
155 $this->getLanguage()->formatNum( $this->total ),
156 [ 'class' => 'mw-statistics-pages' ],
157 'statistics-pages-desc' );
158
159 // Show the image row only, when there are files or upload is possible
160 if ( $this->images !== 0 || $this->getConfig()->get( MainConfigNames::EnableUploads ) ) {
161 $pageStatsHtml .= $this->formatRow(
162 $linkRenderer->makeKnownLink( SpecialPage::getTitleFor( 'MediaStatistics' ),
163 $this->msg( 'statistics-files' )->text() ),
164 $this->getLanguage()->formatNum( $this->images ),
165 [ 'class' => 'mw-statistics-files' ], 'statistics-files-desc' );
166 }
167
168 return $pageStatsHtml;
169 }
170
171 private function getEditStats() {
172 return Html::rawElement( 'tr', [],
173 Xml::tags( 'th', [ 'colspan' => '2' ],
174 $this->msg( 'statistics-header-edits' )->parse()
175 ) ) .
176 $this->formatRow( $this->msg( 'statistics-edits' )->parse(),
177 $this->getLanguage()->formatNum( $this->edits ),
178 [ 'class' => 'mw-statistics-edits' ]
179 ) .
180 $this->formatRow( $this->msg( 'statistics-edits-average' )->parse(),
181 $this->getLanguage()->formatNum(
182 sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 )
183 ), [ 'class' => 'mw-statistics-edits-average' ]
184 );
185 }
186
187 private function getUserStats() {
188 return Html::rawElement( 'tr', [],
189 Xml::tags( 'th', [ 'colspan' => '2' ],
190 $this->msg( 'statistics-header-users' )->parse()
191 ) ) .
192 $this->formatRow( $this->msg( 'statistics-users' )->parse() . ' ' .
193 $this->getLinkRenderer()->makeKnownLink(
194 SpecialPage::getTitleFor( 'Listusers' ),
195 $this->msg( 'listgrouprights-members' )->text()
196 ),
197 $this->getLanguage()->formatNum( $this->users ),
198 [ 'class' => 'mw-statistics-users' ]
199 ) .
200 $this->formatRow( $this->msg( 'statistics-users-active' )->parse() . ' ' .
201 $this->getLinkRenderer()->makeKnownLink(
202 SpecialPage::getTitleFor( 'Activeusers' ),
203 $this->msg( 'listgrouprights-members' )->text()
204 ),
205 $this->getLanguage()->formatNum( $this->activeUsers ),
206 [ 'class' => 'mw-statistics-users-active' ],
207 'statistics-users-active-desc',
208 $this->getLanguage()->formatNum(
210 );
211 }
212
213 private function getGroupStats() {
214 $linkRenderer = $this->getLinkRenderer();
215 $lang = $this->getLanguage();
216 $text = '';
217 foreach ( $this->userGroupManager->listAllGroups() as $group ) {
218 $groupnameLocalized = $lang->getGroupName( $group );
219 $linkTarget = UserGroupMembership::getGroupPage( $group )
220 ?: Title::makeTitleSafe( NS_PROJECT, $group );
221
222 if ( $linkTarget ) {
223 $grouppage = $linkRenderer->makeLink(
224 $linkTarget,
225 $groupnameLocalized
226 );
227 } else {
228 $grouppage = htmlspecialchars( $groupnameLocalized );
229 }
230
231 $grouplink = $linkRenderer->makeKnownLink(
232 SpecialPage::getTitleFor( 'Listusers' ),
233 $this->msg( 'listgrouprights-members' )->text(),
234 [],
235 [ 'group' => $group ]
236 );
237 # Add a class when a usergroup contains no members to allow hiding these rows
238 $classZero = '';
239 $countUsers = SiteStats::numberingroup( $group );
240 if ( $countUsers == 0 ) {
241 $classZero = ' statistics-group-zero';
242 }
243 $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
244 $this->getLanguage()->formatNum( $countUsers ),
245 [ 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) .
246 $classZero ] );
247 }
248
249 return $text;
250 }
251
259 private function getOtherStats( array $stats ) {
260 $return = '';
261
262 foreach ( $stats as $header => $items ) {
263 // Identify the structure used
264 if ( is_array( $items ) ) {
265 // Ignore headers that are recursively set as legacy header
266 if ( $header !== 'statistics-header-hooks' ) {
267 $return .= $this->formatRowHeader( $header );
268 }
269
270 // Collect all items that belong to the same header
271 foreach ( $items as $key => $value ) {
272 if ( is_array( $value ) ) {
273 $name = $value['name'];
274 $number = $value['number'];
275 } else {
276 $name = $this->msg( $key )->parse();
277 $number = $value;
278 }
279
280 $return .= $this->formatRow(
281 $name,
282 $this->getLanguage()->formatNum( htmlspecialchars( $number ) ),
283 [ 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ]
284 );
285 }
286 } else {
287 // Create the legacy header only once
288 if ( $return === '' ) {
289 $return .= $this->formatRowHeader( 'statistics-header-hooks' );
290 }
291
292 // Recursively remap the legacy structure
293 $return .= $this->getOtherStats( [ 'statistics-header-hooks' =>
294 [ $header => $items ] ] );
295 }
296 }
297
298 return $return;
299 }
300
307 private function formatRowHeader( $header ) {
308 return Html::rawElement( 'tr', [],
309 Xml::tags( 'th', [ 'colspan' => '2' ], $this->msg( $header )->parse() )
310 );
311 }
312
313 protected function getGroupName() {
314 return 'wiki';
315 }
316}
317
322class_alias( SpecialStatistics::class, 'SpecialStatistics' );
const NS_PROJECT
Definition Defines.php:69
This class is a collection of static functions that serve two purposes:
Definition Html.php:56
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition Html.php:240
static closeElement( $element)
Returns "</$element>".
Definition Html.php:304
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 By default the message key is the canonical name of...
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
Manage user group memberships.
Represents the membership of one user in one user group.
Module of static functions for generating XML.
Definition Xml.php:37
$header
$footer