MediaWiki  master
AllMessagesTablePager.php
Go to the documentation of this file.
1 <?php
26 
34 
38  protected $langcode;
39 
43  protected $foreign;
44 
48  protected $prefix;
49 
53  protected $suffix;
54 
58  public $lang;
59 
63  public $custom;
64 
70  public function __construct( ?IContextSource $context, FormOptions $opts,
72  ) {
73  parent::__construct( $context, $linkRenderer );
74 
75  $this->mIndexField = 'am_title';
76  // FIXME: Why does this need to be set to DIR_DESCENDING to produce ascending ordering?
77  $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
78 
79  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
80  $this->lang = wfGetLangObj( $opts->getValue( 'lang' ) );
81 
82  $this->langcode = $this->lang->getCode();
83  $this->foreign = !$this->lang->equals( $contLang );
84 
85  $filter = $opts->getValue( 'filter' );
86  if ( $filter === 'all' ) {
87  $this->custom = null; // So won't match in either case
88  } else {
89  $this->custom = ( $filter === 'unmodified' );
90  }
91 
92  $prefix = $this->getLanguage()->ucfirst( $opts->getValue( 'prefix' ) );
93  $prefix = $prefix !== '' ?
94  Title::makeTitleSafe( NS_MEDIAWIKI, $opts->getValue( 'prefix' ) ) :
95  null;
96 
97  if ( $prefix !== null ) {
98  $displayPrefix = $prefix->getDBkey();
99  $this->prefix = '/^' . preg_quote( $displayPrefix, '/' ) . '/i';
100  } else {
101  $this->prefix = false;
102  }
103 
104  // The suffix that may be needed for message names if we're in a
105  // different language (eg [[MediaWiki:Foo/fr]]: $suffix = '/fr'
106  if ( $this->foreign ) {
107  $this->suffix = '/' . $this->langcode;
108  } else {
109  $this->suffix = '';
110  }
111  }
112 
113  private function getAllMessages( $descending ) {
114  $messageNames = MediaWikiServices::getInstance()
115  ->getLocalisationCache()
116  ->getSubitemList( 'en', 'messages' );
117 
118  // Normalise message names so they look like page titles and sort correctly - T86139
119  $messageNames = array_map( [ $this->lang, 'ucfirst' ], $messageNames );
120 
121  if ( $descending ) {
122  rsort( $messageNames );
123  } else {
124  asort( $messageNames );
125  }
126 
127  return $messageNames;
128  }
129 
141  public static function getCustomisedStatuses( $messageNames, $langcode = 'en', $foreign = false ) {
142  // FIXME: This function should be moved to Language:: or something.
143 
144  $dbr = wfGetDB( DB_REPLICA );
145  $res = $dbr->select( 'page',
146  [ 'page_namespace', 'page_title' ],
147  [ 'page_namespace' => [ NS_MEDIAWIKI, NS_MEDIAWIKI_TALK ] ],
148  __METHOD__,
149  [ 'USE INDEX' => 'name_title' ]
150  );
151  $xNames = array_flip( $messageNames );
152 
153  $pageFlags = $talkFlags = [];
154 
155  foreach ( $res as $s ) {
156  $exists = false;
157 
158  if ( $foreign ) {
159  $titleParts = explode( '/', $s->page_title );
160  if ( count( $titleParts ) === 2 &&
161  $langcode === $titleParts[1] &&
162  isset( $xNames[$titleParts[0]] )
163  ) {
164  $exists = $titleParts[0];
165  }
166  } elseif ( isset( $xNames[$s->page_title] ) ) {
167  $exists = $s->page_title;
168  }
169 
171  if ( $exists && $title->inNamespace( NS_MEDIAWIKI ) ) {
172  $pageFlags[$exists] = true;
173  } elseif ( $exists && $title->inNamespace( NS_MEDIAWIKI_TALK ) ) {
174  $talkFlags[$exists] = true;
175  }
176  }
177 
178  return [ 'pages' => $pageFlags, 'talks' => $talkFlags ];
179  }
180 
189  public function reallyDoQuery( $offset, $limit, $order ) {
190  $asc = ( $order === self::QUERY_ASCENDING );
191 
192  $messageNames = $this->getAllMessages( $order );
193  $statuses = self::getCustomisedStatuses( $messageNames, $this->langcode, $this->foreign );
194 
195  $rows = [];
196  $count = 0;
197  foreach ( $messageNames as $key ) {
198  $customised = isset( $statuses['pages'][$key] );
199  if ( $customised !== $this->custom &&
200  ( $asc && ( $key < $offset || !$offset ) || !$asc && $key > $offset ) &&
201  ( ( $this->prefix && preg_match( $this->prefix, $key ) ) || $this->prefix === false )
202  ) {
203  $actual = $this->msg( $key )->inLanguage( $this->lang )->plain();
204  $default = $this->msg( $key )->inLanguage( $this->lang )->useDatabase( false )->plain();
205  $rows[] = [
206  'am_title' => $key,
207  'am_actual' => $actual,
208  'am_default' => $default,
209  'am_customised' => $customised,
210  'am_talk_exists' => isset( $statuses['talks'][$key] )
211  ];
212  $count++;
213  }
214 
215  if ( $count === $limit ) {
216  break;
217  }
218  }
219 
220  return new FakeResultWrapper( $rows );
221  }
222 
223  protected function getStartBody() {
224  $tableClass = $this->getTableClass();
225  return Xml::openElement( 'table', [
226  'class' => "mw-datatable $tableClass",
227  'id' => 'mw-allmessagestable'
228  ] ) .
229  "\n" .
230  "<thead><tr>
231  <th rowspan=\"2\">" .
232  $this->msg( 'allmessagesname' )->escaped() . "
233  </th>
234  <th>" .
235  $this->msg( 'allmessagesdefault' )->escaped() .
236  "</th>
237  </tr>\n
238  <tr>
239  <th>" .
240  $this->msg( 'allmessagescurrent' )->escaped() .
241  "</th>
242  </tr></thead>\n";
243  }
244 
245  protected function getEndBody() {
246  return Html::closeElement( 'table' );
247  }
248 
249  public function formatValue( $field, $value ) {
250  $linkRenderer = $this->getLinkRenderer();
251  switch ( $field ) {
252  case 'am_title' :
253  $title = Title::makeTitle( NS_MEDIAWIKI, $value . $this->suffix );
254  $talk = Title::makeTitle( NS_MEDIAWIKI_TALK, $value . $this->suffix );
255  $translation = Linker::makeExternalLink(
256  'https://translatewiki.net/w/i.php?' . wfArrayToCgi( [
257  'title' => 'Special:SearchTranslations',
258  'group' => 'mediawiki',
259  'grouppath' => 'mediawiki',
260  'language' => $this->getLanguage()->getCode(),
261  'query' => $value . ' ' . $this->msg( $value )->plain()
262  ] ),
263  $this->msg( 'allmessages-filter-translate' )->text()
264  );
265  $talkLink = $this->msg( 'talkpagelinktext' )->escaped();
266 
267  if ( $this->mCurrentRow->am_customised ) {
268  $title = $linkRenderer->makeKnownLink( $title, $this->getLanguage()->lcfirst( $value ) );
269  } else {
271  $title, $this->getLanguage()->lcfirst( $value )
272  );
273  }
274  if ( $this->mCurrentRow->am_talk_exists ) {
275  $talk = $linkRenderer->makeKnownLink( $talk, $talkLink );
276  } else {
277  $talk = $linkRenderer->makeBrokenLink(
278  $talk,
279  $talkLink
280  );
281  }
282 
283  return $title . ' ' .
284  $this->msg( 'parentheses' )->rawParams( $talk )->escaped() .
285  ' ' .
286  $this->msg( 'parentheses' )->rawParams( $translation )->escaped();
287 
288  case 'am_default' :
289  case 'am_actual' :
290  return Sanitizer::escapeHtmlAllowEntities( $value );
291  }
292 
293  return '';
294  }
295 
300  public function formatRow( $row ) {
301  // Do all the normal stuff
302  $s = parent::formatRow( $row );
303 
304  // But if there's a customised message, add that too.
305  if ( $row->am_customised ) {
306  $s .= Html::openElement( 'tr', $this->getRowAttrs( $row ) );
307  $formatted = strval( $this->formatValue( 'am_actual', $row->am_actual ) );
308 
309  if ( $formatted === '' ) {
310  $formatted = "\u{00A0}";
311  }
312 
313  $s .= Html::element( 'td', $this->getCellAttrs( 'am_actual', $row->am_actual ), $formatted )
314  . Html::closeElement( 'tr' );
315  }
316 
317  return Html::rawElement( 'tbody', [], $s );
318  }
319 
320  protected function getRowAttrs( $row ) {
321  return [];
322  }
323 
329  protected function getCellAttrs( $field, $value ) {
330  $attr = [];
331  if ( $field === 'am_title' ) {
332  if ( $this->mCurrentRow->am_customised ) {
333  $attr += [ 'rowspan' => '2' ];
334  }
335  } else {
336  $attr += [
337  'lang' => $this->lang->getHtmlCode(),
338  'dir' => $this->lang->getDir(),
339  ];
340  if ( $this->mCurrentRow->am_customised ) {
341  // CSS class: am_default, am_actual
342  $attr += [ 'class' => $field ];
343  }
344  }
345  return $attr;
346  }
347 
348  // This is not actually used, as getStartBody is overridden above
349  protected function getFieldNames() {
350  return [
351  'am_title' => $this->msg( 'allmessagesname' )->text(),
352  'am_default' => $this->msg( 'allmessagesdefault' )->text()
353  ];
354  }
355 
356  public function getTitle() {
357  return SpecialPage::getTitleFor( 'Allmessages', false );
358  }
359 
360  protected function isFieldSortable( $x ) {
361  return false;
362  }
363 
364  public function getDefaultSort() {
365  return '';
366  }
367 
368  public function getQueryInfo() {
369  return [];
370  }
371 
372 }
AllMessagesTablePager\getCellAttrs
getCellAttrs( $field, $value)
Definition: AllMessagesTablePager.php:329
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:37
AllMessagesTablePager
Use TablePager for prettified output.
Definition: AllMessagesTablePager.php:33
AllMessagesTablePager\$custom
null bool $custom
Definition: AllMessagesTablePager.php:63
AllMessagesTablePager\formatValue
formatValue( $field, $value)
Format a table cell.
Definition: AllMessagesTablePager.php:249
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:162
IndexPager\QUERY_ASCENDING
const QUERY_ASCENDING
Backwards-compatible constant for reallyDoQuery() (do not change)
Definition: IndexPager.php:83
FormOptions\getValue
getValue( $name)
Get the value for the given option name.
Definition: FormOptions.php:182
MediaWiki\Linker\LinkRenderer
Class that generates HTML links for pages.
Definition: LinkRenderer.php:41
TablePager\getTableClass
getTableClass()
TablePager relies on mw-datatable for styling, see T214208.
Definition: TablePager.php:283
$s
$s
Definition: mergeMessageFileList.php:184
IndexPager\$linkRenderer
LinkRenderer $linkRenderer
Definition: IndexPager.php:167
SpecialPage\getTitleFor
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,...
Definition: SpecialPage.php:92
AllMessagesTablePager\formatRow
formatRow( $row)
Definition: AllMessagesTablePager.php:300
$res
$res
Definition: testCompression.php:57
Wikimedia\Rdbms\FakeResultWrapper
Overloads the relevant methods of the real ResultsWrapper so it doesn't go anywhere near an actual da...
Definition: FakeResultWrapper.php:11
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:108
AllMessagesTablePager\$langcode
string $langcode
Definition: AllMessagesTablePager.php:38
AllMessagesTablePager\getTitle
getTitle()
Definition: AllMessagesTablePager.php:356
$dbr
$dbr
Definition: testCompression.php:54
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:143
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:315
AllMessagesTablePager\$prefix
string $prefix
Definition: AllMessagesTablePager.php:48
AllMessagesTablePager\getStartBody
getStartBody()
Stable to override.
Definition: AllMessagesTablePager.php:223
AllMessagesTablePager\getCustomisedStatuses
static getCustomisedStatuses( $messageNames, $langcode='en', $foreign=false)
Determine which of the MediaWiki and MediaWiki_talk namespace pages exist.
Definition: AllMessagesTablePager.php:141
AllMessagesTablePager\getEndBody
getEndBody()
Stable to override.
Definition: AllMessagesTablePager.php:245
Wikimedia\Rdbms\IResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: IResultWrapper.php:24
Title\newFromRow
static newFromRow( $row)
Make a Title object from a DB row.
Definition: Title.php:523
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2475
AllMessagesTablePager\$foreign
bool $foreign
Definition: AllMessagesTablePager.php:43
NS_MEDIAWIKI_TALK
const NS_MEDIAWIKI_TALK
Definition: Defines.php:78
TablePager
Table-based display with a user-selectable sort order Stable to extend.
Definition: TablePager.php:31
AllMessagesTablePager\getDefaultSort
getDefaultSort()
The database field name used as a default sort order.
Definition: AllMessagesTablePager.php:364
wfGetLangObj
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
Definition: GlobalFunctions.php:1170
$title
$title
Definition: testCompression.php:38
Linker\makeExternalLink
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:846
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:591
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
AllMessagesTablePager\getFieldNames
getFieldNames()
An array mapping database field names to a textual description of the field name, for use in the tabl...
Definition: AllMessagesTablePager.php:349
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:187
AllMessagesTablePager\$suffix
string $suffix
Definition: AllMessagesTablePager.php:53
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:617
AllMessagesTablePager\getQueryInfo
getQueryInfo()
Provides all parameters needed for the main paged query.
Definition: AllMessagesTablePager.php:368
AllMessagesTablePager\isFieldSortable
isFieldSortable( $x)
Return true if the named field should be sortable by the UI, false otherwise.
Definition: AllMessagesTablePager.php:360
IndexPager\getLinkRenderer
getLinkRenderer()
Definition: IndexPager.php:976
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:55
IndexPager\DIR_DESCENDING
const DIR_DESCENDING
Backwards-compatible constant for $mDefaultDirection field (do not change)
Definition: IndexPager.php:80
AllMessagesTablePager\__construct
__construct(?IContextSource $context, FormOptions $opts, LinkRenderer $linkRenderer)
Definition: AllMessagesTablePager.php:70
MediaWiki\Linker\LinkRenderer\makeKnownLink
makeKnownLink(LinkTarget $target, $text=null, array $extraAttribs=[], array $query=[])
Definition: LinkRenderer.php:225
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:251
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:209
AllMessagesTablePager\getAllMessages
getAllMessages( $descending)
Definition: AllMessagesTablePager.php:113
NS_MEDIAWIKI
const NS_MEDIAWIKI
Definition: Defines.php:77
FormOptions
Helper class to keep track of options when mixing links and form elements.
Definition: FormOptions.php:35
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:231
AllMessagesTablePager\getRowAttrs
getRowAttrs( $row)
Get attributes to be applied to the given row.
Definition: AllMessagesTablePager.php:320
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41
MediaWiki\Linker\LinkRenderer\makeBrokenLink
makeBrokenLink(LinkTarget $target, $text=null, array $extraAttribs=[], array $query=[])
Definition: LinkRenderer.php:254
Sanitizer\escapeHtmlAllowEntities
static escapeHtmlAllowEntities( $html)
Given HTML input, escape with htmlspecialchars but un-escape entities.
Definition: Sanitizer.php:991
AllMessagesTablePager\$lang
Language $lang
Definition: AllMessagesTablePager.php:58
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Definition: GlobalFunctions.php:346
AllMessagesTablePager\reallyDoQuery
reallyDoQuery( $offset, $limit, $order)
This function normally does a database query to get the results; we need to make a pretend result usi...
Definition: AllMessagesTablePager.php:189