MediaWiki  master
SpecialStatistics.php
Go to the documentation of this file.
1 <?php
26 
34  private $edits, $good, $images, $total, $users,
36 
38  private $userGroupManager;
39 
43  public function __construct( UserGroupManager $userGroupManager ) {
44  parent::__construct( 'Statistics' );
45  $this->userGroupManager = $userGroupManager;
46  }
47 
48  public function execute( $par ) {
49  $this->setHeaders();
50  $this->outputHeader();
51  $this->getOutput()->addModuleStyles( 'mediawiki.special' );
52 
53  $this->edits = SiteStats::edits();
54  $this->good = SiteStats::articles();
55  $this->images = SiteStats::images();
56  $this->total = SiteStats::pages();
57  $this->users = SiteStats::users();
58  $this->activeUsers = SiteStats::activeUsers();
59 
60  $text = Xml::openElement( 'table', [ 'class' => 'wikitable mw-statistics-table' ] );
61 
62  # Statistic - pages
63  $text .= $this->getPageStats();
64 
65  # Statistic - edits
66  $text .= $this->getEditStats();
67 
68  # Statistic - users
69  $text .= $this->getUserStats();
70 
71  # Statistic - usergroups
72  $text .= $this->getGroupStats();
73 
74  # Statistic - other
75  $extraStats = [];
76  if ( $this->getHookRunner()->onSpecialStatsAddExtra(
77  $extraStats, $this->getContext() )
78  ) {
79  $text .= $this->getOtherStats( $extraStats );
80  }
81 
82  $text .= Xml::closeElement( 'table' );
83 
84  # Customizable footer
85  $footer = $this->msg( 'statistics-footer' );
86  if ( !$footer->isBlank() ) {
87  $text .= "\n" . $footer->parse();
88  }
89 
90  $this->getOutput()->addHTML( $text );
91  }
92 
102  private function formatRow( $text, $number, $trExtraParams = [],
103  $descMsg = '', $descMsgParam = ''
104  ) {
105  if ( $descMsg ) {
106  $msg = $this->msg( $descMsg, $descMsgParam );
107  if ( !$msg->isDisabled() ) {
108  $descriptionHtml = $this->msg( 'parentheses' )->rawParams( $msg->parse() )
109  ->escaped();
110  $text .= "<br />" . Html::rawElement(
111  'small',
112  [ 'class' => 'mw-statistic-desc' ],
113  " $descriptionHtml"
114  );
115  }
116  }
117 
118  return Html::rawElement( 'tr', $trExtraParams,
119  Html::rawElement( 'td', [], $text ) .
120  Html::rawElement( 'td', [ 'class' => 'mw-statistics-numbers' ], $number )
121  );
122  }
123 
129  private function getPageStats() {
130  $linkRenderer = $this->getLinkRenderer();
131 
132  $specialAllPagesTitle = SpecialPage::getTitleFor( 'Allpages' );
133  $pageStatsHtml = Xml::openElement( 'tr' ) .
134  Xml::tags( 'th', [ 'colspan' => '2' ], $this->msg( 'statistics-header-pages' )
135  ->parse() ) .
136  Xml::closeElement( 'tr' ) .
137  $this->formatRow(
138  $this->getConfig()->get( MainConfigNames::MiserMode )
139  ? $this->msg( 'statistics-articles' )->escaped()
140  : $linkRenderer->makeKnownLink(
141  $specialAllPagesTitle,
142  $this->msg( 'statistics-articles' )->text(),
143  [], [ 'hideredirects' => 1 ] ),
144  $this->getLanguage()->formatNum( $this->good ),
145  [ 'class' => 'mw-statistics-articles' ],
146  'statistics-articles-desc' ) .
147  $this->formatRow( $linkRenderer->makeKnownLink( $specialAllPagesTitle,
148  $this->msg( 'statistics-pages' )->text() ),
149  $this->getLanguage()->formatNum( $this->total ),
150  [ 'class' => 'mw-statistics-pages' ],
151  'statistics-pages-desc' );
152 
153  // Show the image row only, when there are files or upload is possible
154  if ( $this->images !== 0 || $this->getConfig()->get( MainConfigNames::EnableUploads ) ) {
155  $pageStatsHtml .= $this->formatRow(
156  $linkRenderer->makeKnownLink( SpecialPage::getTitleFor( 'MediaStatistics' ),
157  $this->msg( 'statistics-files' )->text() ),
158  $this->getLanguage()->formatNum( $this->images ),
159  [ 'class' => 'mw-statistics-files' ], 'statistics-files-desc' );
160  }
161 
162  return $pageStatsHtml;
163  }
164 
165  private function getEditStats() {
166  return Xml::openElement( 'tr' ) .
167  Xml::tags( 'th', [ 'colspan' => '2' ],
168  $this->msg( 'statistics-header-edits' )->parse() ) .
169  Xml::closeElement( 'tr' ) .
170  $this->formatRow( $this->msg( 'statistics-edits' )->parse(),
171  $this->getLanguage()->formatNum( $this->edits ),
172  [ 'class' => 'mw-statistics-edits' ]
173  ) .
174  $this->formatRow( $this->msg( 'statistics-edits-average' )->parse(),
175  $this->getLanguage()->formatNum(
176  sprintf( '%.2f', $this->total ? $this->edits / $this->total : 0 )
177  ), [ 'class' => 'mw-statistics-edits-average' ]
178  );
179  }
180 
181  private function getUserStats() {
182  return Xml::openElement( 'tr' ) .
183  Xml::tags( 'th', [ 'colspan' => '2' ],
184  $this->msg( 'statistics-header-users' )->parse() ) .
185  Xml::closeElement( 'tr' ) .
186  $this->formatRow( $this->msg( 'statistics-users' )->parse() . ' ' .
187  $this->getLinkRenderer()->makeKnownLink(
188  SpecialPage::getTitleFor( 'Listusers' ),
189  $this->msg( 'listgrouprights-members' )->text()
190  ),
191  $this->getLanguage()->formatNum( $this->users ),
192  [ 'class' => 'mw-statistics-users' ]
193  ) .
194  $this->formatRow( $this->msg( 'statistics-users-active' )->parse() . ' ' .
195  $this->getLinkRenderer()->makeKnownLink(
196  SpecialPage::getTitleFor( 'Activeusers' ),
197  $this->msg( 'listgrouprights-members' )->text()
198  ),
199  $this->getLanguage()->formatNum( $this->activeUsers ),
200  [ 'class' => 'mw-statistics-users-active' ],
201  'statistics-users-active-desc',
202  $this->getLanguage()->formatNum(
203  $this->getConfig()->get( MainConfigNames::ActiveUserDays ) )
204  );
205  }
206 
207  private function getGroupStats() {
208  $linkRenderer = $this->getLinkRenderer();
209  $lang = $this->getLanguage();
210  $text = '';
211  foreach ( $this->userGroupManager->listAllGroups() as $group ) {
212  $groupnameLocalized = $lang->getGroupName( $group );
213  $linkTarget = UserGroupMembership::getGroupPage( $group )
214  ?: Title::makeTitleSafe( NS_PROJECT, $group );
215 
216  if ( $linkTarget ) {
217  $grouppage = $linkRenderer->makeLink(
218  $linkTarget,
219  $groupnameLocalized
220  );
221  } else {
222  $grouppage = htmlspecialchars( $groupnameLocalized );
223  }
224 
225  $grouplink = $linkRenderer->makeKnownLink(
226  SpecialPage::getTitleFor( 'Listusers' ),
227  $this->msg( 'listgrouprights-members' )->text(),
228  [],
229  [ 'group' => $group ]
230  );
231  # Add a class when a usergroup contains no members to allow hiding these rows
232  $classZero = '';
233  $countUsers = SiteStats::numberingroup( $group );
234  if ( $countUsers == 0 ) {
235  $classZero = ' statistics-group-zero';
236  }
237  $text .= $this->formatRow( $grouppage . ' ' . $grouplink,
238  $this->getLanguage()->formatNum( $countUsers ),
239  [ 'class' => 'statistics-group-' . Sanitizer::escapeClass( $group ) .
240  $classZero ] );
241  }
242 
243  return $text;
244  }
245 
253  private function getOtherStats( array $stats ) {
254  $return = '';
255 
256  foreach ( $stats as $header => $items ) {
257  // Identify the structure used
258  if ( is_array( $items ) ) {
259  // Ignore headers that are recursively set as legacy header
260  if ( $header !== 'statistics-header-hooks' ) {
261  $return .= $this->formatRowHeader( $header );
262  }
263 
264  // Collect all items that belong to the same header
265  foreach ( $items as $key => $value ) {
266  if ( is_array( $value ) ) {
267  $name = $value['name'];
268  $number = $value['number'];
269  } else {
270  $name = $this->msg( $key )->parse();
271  $number = $value;
272  }
273 
274  $return .= $this->formatRow(
275  $name,
276  $this->getLanguage()->formatNum( htmlspecialchars( $number ) ),
277  [ 'class' => 'mw-statistics-hook', 'id' => 'mw-' . $key ]
278  );
279  }
280  } else {
281  // Create the legacy header only once
282  if ( $return === '' ) {
283  $return .= $this->formatRowHeader( 'statistics-header-hooks' );
284  }
285 
286  // Recursively remap the legacy structure
287  $return .= $this->getOtherStats( [ 'statistics-header-hooks' =>
288  [ $header => $items ] ] );
289  }
290  }
291 
292  return $return;
293  }
294 
301  private function formatRowHeader( $header ) {
302  return Xml::openElement( 'tr' ) .
303  Xml::tags( 'th', [ 'colspan' => '2' ], $this->msg( $header )->parse() ) .
304  Xml::closeElement( 'tr' );
305  }
306 
307  protected function getGroupName() {
308  return 'wiki';
309  }
310 }
const NS_PROJECT
Definition: Defines.php:68
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:214
A class containing constants representing the names of configuration variables.
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:1106
static articles()
Definition: SiteStats.php:104
static images()
Definition: SiteStats.php:140
static edits()
Definition: SiteStats.php:95
static users()
Definition: SiteStats.php:122
static pages()
Definition: SiteStats.php:113
static numberingroup( $group)
Find the number of users in a given user group.
Definition: SiteStats.php:151
static activeUsers()
Definition: SiteStats.php:131
Parent class for all special pages.
Definition: SpecialPage.php:44
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
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,...
getContext()
Gets the context this SpecialPage is executed in.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getConfig()
Shortcut to get main config object.
getLanguage()
Shortcut to get user's language.
Special page lists various statistics, including the contents of site_stats, plus page view details i...
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
__construct(UserGroupManager $userGroupManager)
execute( $par)
Default execute method Checks user permissions.
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:664
static getGroupPage( $group)
Gets the title of a page describing a particular user group.
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:121
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:112
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Definition: Xml.php:134
if(!isset( $args[0])) $lang
$header
$footer