Completed
Branch master (62f6c6)
by
unknown
21:31
created

LogEventsList::showOptions()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 54
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 24
nc 32
nop 9
dl 0
loc 54
rs 8.7449
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 * Contain classes to list log entries
4
 *
5
 * Copyright © 2004 Brion Vibber <[email protected]>, 2008 Aaron Schulz
6
 * https://www.mediawiki.org/
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License along
19
 * with this program; if not, write to the Free Software Foundation, Inc.,
20
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
 * http://www.gnu.org/copyleft/gpl.html
22
 *
23
 * @file
24
 */
25
26
class LogEventsList extends ContextSource {
27
	const NO_ACTION_LINK = 1;
28
	const NO_EXTRA_USER_LINKS = 2;
29
	const USE_CHECKBOXES = 4;
30
31
	public $flags;
32
33
	/**
34
	 * @var array
35
	 */
36
	protected $mDefaultQuery;
37
38
	/**
39
	 * @var bool
40
	 */
41
	protected $showTagEditUI;
42
43
	/**
44
	 * @var array
45
	 */
46
	protected $allowedActions = null;
47
48
	/**
49
	 * Constructor.
50
	 * The first two parameters used to be $skin and $out, but now only a context
51
	 * is needed, that's why there's a second unused parameter.
52
	 *
53
	 * @param IContextSource|Skin $context Context to use; formerly it was
54
	 *   a Skin object. Use of Skin is deprecated.
55
	 * @param null $unused Unused; used to be an OutputPage object.
56
	 * @param int $flags Can be a combination of self::NO_ACTION_LINK,
57
	 *   self::NO_EXTRA_USER_LINKS or self::USE_CHECKBOXES.
58
	 */
59
	public function __construct( $context, $unused = null, $flags = 0 ) {
60
		if ( $context instanceof IContextSource ) {
61
			$this->setContext( $context );
62
		} else {
63
			// Old parameters, $context should be a Skin object
64
			$this->setContext( $context->getContext() );
65
		}
66
67
		$this->flags = $flags;
68
		$this->showTagEditUI = ChangeTags::showTagEditingUI( $this->getUser() );
69
	}
70
71
	/**
72
	 * Show options for the log list
73
	 *
74
	 * @param array|string $types
75
	 * @param string $user
76
	 * @param string $page
77
	 * @param string $pattern
78
	 * @param int $year Year
79
	 * @param int $month Month
80
	 * @param array $filter
81
	 * @param string $tagFilter Tag to select by default
82
	 * @param string $action
83
	 */
84
	public function showOptions( $types = [], $user = '', $page = '', $pattern = '', $year = 0,
85
		$month = 0, $filter = null, $tagFilter = '', $action = null
86
	) {
87
		global $wgScript, $wgMiserMode;
88
89
		$title = SpecialPage::getTitleFor( 'Log' );
90
91
		// For B/C, we take strings, but make sure they are converted...
92
		$types = ( $types === '' ) ? [] : (array)$types;
93
94
		$tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter );
95
96
		$html = Html::hidden( 'title', $title->getPrefixedDBkey() );
97
98
		// Basic selectors
99
		$html .= $this->getTypeMenu( $types ) . "\n";
100
		$html .= $this->getUserInput( $user ) . "\n";
101
		$html .= $this->getTitleInput( $page ) . "\n";
102
		$html .= $this->getExtraInputs( $types ) . "\n";
103
104
		// Title pattern, if allowed
105
		if ( !$wgMiserMode ) {
106
			$html .= $this->getTitlePattern( $pattern ) . "\n";
107
		}
108
109
		// date menu
110
		$html .= Xml::tags( 'p', null, Xml::dateMenu( (int)$year, (int)$month ) );
111
112
		// Tag filter
113
		if ( $tagSelector ) {
114
			$html .= Xml::tags( 'p', null, implode( '&#160;', $tagSelector ) );
115
		}
116
117
		// Filter links
118
		if ( $filter ) {
119
			$html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) );
120
		}
121
122
		// Action filter
123
		if ( $action !== null ) {
124
			$html .= Xml::tags( 'p', null, $this->getActionSelector( $types, $action ) );
125
		}
126
127
		// Submit button
128
		$html .= Xml::submitButton( $this->msg( 'logeventslist-submit' )->text() );
129
130
		// Fieldset
131
		$html = Xml::fieldset( $this->msg( 'log' )->text(), $html );
132
133
		// Form wrapping
134
		$html = Xml::tags( 'form', [ 'action' => $wgScript, 'method' => 'get' ], $html );
135
136
		$this->getOutput()->addHTML( $html );
137
	}
138
139
	/**
140
	 * @param array $filter
141
	 * @return string Formatted HTML
142
	 */
143
	private function getFilterLinks( $filter ) {
144
		// show/hide links
145
		$messages = [ $this->msg( 'show' )->escaped(), $this->msg( 'hide' )->escaped() ];
146
		// Option value -> message mapping
147
		$links = [];
148
		$hiddens = ''; // keep track for "go" button
149
		foreach ( $filter as $type => $val ) {
150
			// Should the below assignment be outside the foreach?
151
			// Then it would have to be copied. Not certain what is more expensive.
152
			$query = $this->getDefaultQuery();
153
			$queryKey = "hide_{$type}_log";
154
155
			$hideVal = 1 - intval( $val );
156
			$query[$queryKey] = $hideVal;
157
158
			$link = Linker::linkKnown(
159
				$this->getTitle(),
160
				$messages[$hideVal],
161
				[],
162
				$query
163
			);
164
165
			// Message: log-show-hide-patrol
166
			$links[$type] = $this->msg( "log-show-hide-{$type}" )->rawParams( $link )->escaped();
167
			$hiddens .= Html::hidden( "hide_{$type}_log", $val ) . "\n";
168
		}
169
170
		// Build links
171
		return '<small>' . $this->getLanguage()->pipeList( $links ) . '</small>' . $hiddens;
172
	}
173
174 View Code Duplication
	private function getDefaultQuery() {
175
		if ( !isset( $this->mDefaultQuery ) ) {
176
			$this->mDefaultQuery = $this->getRequest()->getQueryValues();
177
			unset( $this->mDefaultQuery['title'] );
178
			unset( $this->mDefaultQuery['dir'] );
179
			unset( $this->mDefaultQuery['offset'] );
180
			unset( $this->mDefaultQuery['limit'] );
181
			unset( $this->mDefaultQuery['order'] );
182
			unset( $this->mDefaultQuery['month'] );
183
			unset( $this->mDefaultQuery['year'] );
184
		}
185
186
		return $this->mDefaultQuery;
187
	}
188
189
	/**
190
	 * @param array $queryTypes
191
	 * @return string Formatted HTML
192
	 */
193
	private function getTypeMenu( $queryTypes ) {
194
		$queryType = count( $queryTypes ) == 1 ? $queryTypes[0] : '';
195
		$selector = $this->getTypeSelector();
196
		$selector->setDefault( $queryType );
197
198
		return $selector->getHTML();
199
	}
200
201
	/**
202
	 * Returns log page selector.
203
	 * @return XmlSelect
204
	 * @since 1.19
205
	 */
206
	public function getTypeSelector() {
207
		$typesByName = []; // Temporary array
208
		// First pass to load the log names
209
		foreach ( LogPage::validTypes() as $type ) {
210
			$page = new LogPage( $type );
211
			$restriction = $page->getRestriction();
212
			if ( $this->getUser()->isAllowed( $restriction ) ) {
213
				$typesByName[$type] = $page->getName()->text();
214
			}
215
		}
216
217
		// Second pass to sort by name
218
		asort( $typesByName );
219
220
		// Always put "All public logs" on top
221
		$public = $typesByName[''];
222
		unset( $typesByName[''] );
223
		$typesByName = [ '' => $public ] + $typesByName;
224
225
		$select = new XmlSelect( 'type' );
226
		foreach ( $typesByName as $type => $name ) {
227
			$select->addOption( $name, $type );
228
		}
229
230
		return $select;
231
	}
232
233
	/**
234
	 * @param string $user
235
	 * @return string Formatted HTML
236
	 */
237
	private function getUserInput( $user ) {
238
		$label = Xml::inputLabel(
239
			$this->msg( 'specialloguserlabel' )->text(),
240
			'user',
241
			'mw-log-user',
242
			15,
243
			$user,
244
			[ 'class' => 'mw-autocomplete-user' ]
245
		);
246
247
		return '<span class="mw-input-with-label">' . $label . '</span>';
248
	}
249
250
	/**
251
	 * @param string $title
252
	 * @return string Formatted HTML
253
	 */
254
	private function getTitleInput( $title ) {
255
		$label = Xml::inputLabel(
256
			$this->msg( 'speciallogtitlelabel' )->text(),
257
			'page',
258
			'mw-log-page',
259
			20,
260
			$title
261
		);
262
263
		return '<span class="mw-input-with-label">' . $label .	'</span>';
264
	}
265
266
	/**
267
	 * @param string $pattern
268
	 * @return string Checkbox
269
	 */
270
	private function getTitlePattern( $pattern ) {
271
		return '<span class="mw-input-with-label">' .
272
			Xml::checkLabel( $this->msg( 'log-title-wildcard' )->text(), 'pattern', 'pattern', $pattern ) .
273
			'</span>';
274
	}
275
276
	/**
277
	 * @param array $types
278
	 * @return string
279
	 */
280
	private function getExtraInputs( $types ) {
281
		if ( count( $types ) == 1 ) {
282
			if ( $types[0] == 'suppress' ) {
283
				$offender = $this->getRequest()->getVal( 'offender' );
284
				$user = User::newFromName( $offender, false );
285
				if ( !$user || ( $user->getId() == 0 && !IP::isIPAddress( $offender ) ) ) {
286
					$offender = ''; // Blank field if invalid
287
				}
288
				return Xml::inputLabel( $this->msg( 'revdelete-offender' )->text(), 'offender',
289
					'mw-log-offender', 20, $offender );
290
			} else {
291
				// Allow extensions to add their own extra inputs
292
				$input = '';
293
				Hooks::run( 'LogEventsListGetExtraInputs', [ $types[0], $this, &$input ] );
294
				return $input;
295
			}
296
		}
297
298
		return '';
299
	}
300
301
	/**
302
	 * Drop down menu for selection of actions that can be used to filter the log
303
	 * @param array $types
304
	 * @param string $action
305
	 * @return string
306
	 * @since 1.27
307
	 */
308
	private function getActionSelector( $types, $action ) {
309
		if ( $this->allowedActions === null || !count( $this->allowedActions ) ) {
310
			return '';
311
		}
312
		$html = '';
313
		$html .= xml::label( wfMessage( 'log-action-filter-' . $types[0] )->text(),
314
			'action-filter-' .$types[0] ) . "\n";
315
		$select = new XmlSelect( 'subtype' );
316
		$select->addOption( wfMessage( 'log-action-filter-all' )->text(), '' );
317
		foreach ( $this->allowedActions as $value ) {
318
			$msgKey = 'log-action-filter-' . $types[0] . '-' . $value;
319
			$select->addOption( wfMessage( $msgKey )->text(), $value );
320
		}
321
		$select->setDefault( $action );
322
		$html .= $select->getHtml();
323
		return $html;
324
	}
325
326
	/**
327
	 * Sets the action types allowed for log filtering
328
	 * To one action type may correspond several log_actions
329
	 * @param array $actions
330
	 * @since 1.27
331
	 */
332
	public function setAllowedActions( $actions ) {
333
		$this->allowedActions = $actions;
334
	}
335
336
	/**
337
	 * @return string
338
	 */
339
	public function beginLogEventsList() {
340
		return "<ul>\n";
341
	}
342
343
	/**
344
	 * @return string
345
	 */
346
	public function endLogEventsList() {
347
		return "</ul>\n";
348
	}
349
350
	/**
351
	 * @param stdClass $row A single row from the result set
352
	 * @return string Formatted HTML list item
353
	 */
354
	public function logLine( $row ) {
355
		$entry = DatabaseLogEntry::newFromRow( $row );
356
		$formatter = LogFormatter::newFromEntry( $entry );
357
		$formatter->setContext( $this->getContext() );
358
		$formatter->setShowUserToolLinks( !( $this->flags & self::NO_EXTRA_USER_LINKS ) );
359
360
		$time = htmlspecialchars( $this->getLanguage()->userTimeAndDate(
361
			$entry->getTimestamp(), $this->getUser() ) );
362
363
		$action = $formatter->getActionText();
364
365
		if ( $this->flags & self::NO_ACTION_LINK ) {
366
			$revert = '';
367
		} else {
368
			$revert = $formatter->getActionLinks();
369
			if ( $revert != '' ) {
370
				$revert = '<span class="mw-logevent-actionlink">' . $revert . '</span>';
371
			}
372
		}
373
374
		$comment = $formatter->getComment();
375
376
		// Some user can hide log items and have review links
377
		$del = $this->getShowHideLinks( $row );
378
379
		// Any tags...
380
		list( $tagDisplay, $newClasses ) = ChangeTags::formatSummaryRow(
381
			$row->ts_tags,
382
			'logevent',
383
			$this->getContext()
384
		);
385
		$classes = array_merge(
386
			[ 'mw-logline-' . $entry->getType() ],
387
			$newClasses
388
		);
389
390
		return Html::rawElement( 'li', [ 'class' => $classes ],
391
			"$del $time $action $comment $revert $tagDisplay" ) . "\n";
392
	}
393
394
	/**
395
	 * @param stdClass $row Row
396
	 * @return string
397
	 */
398
	private function getShowHideLinks( $row ) {
399
		// We don't want to see the links and
400
		if ( $this->flags == self::NO_ACTION_LINK ) {
401
			return '';
402
		}
403
404
		$user = $this->getUser();
405
406
		// If change tag editing is available to this user, return the checkbox
407
		if ( $this->flags & self::USE_CHECKBOXES && $this->showTagEditUI ) {
408
			return Xml::check(
409
				'showhiderevisions',
410
				false,
411
				[ 'name' => 'ids[' . $row->log_id . ']' ]
412
			);
413
		}
414
415
		// no one can hide items from the suppress log.
416
		if ( $row->log_type == 'suppress' ) {
417
			return '';
418
		}
419
420
		$del = '';
421
		// Don't show useless checkbox to people who cannot hide log entries
422
		if ( $user->isAllowed( 'deletedhistory' ) ) {
423
			$canHide = $user->isAllowed( 'deletelogentry' );
424
			$canViewSuppressedOnly = $user->isAllowed( 'viewsuppressed' ) &&
425
				!$user->isAllowed( 'suppressrevision' );
426
			$entryIsSuppressed = self::isDeleted( $row, LogPage::DELETED_RESTRICTED );
427
			$canViewThisSuppressedEntry = $canViewSuppressedOnly && $entryIsSuppressed;
428
			if ( $row->log_deleted || $canHide ) {
429
				// Show checkboxes instead of links.
430
				if ( $canHide && $this->flags & self::USE_CHECKBOXES && !$canViewThisSuppressedEntry ) {
431
					// If event was hidden from sysops
432 View Code Duplication
					if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) {
433
						$del = Xml::check( 'deleterevisions', false, [ 'disabled' => 'disabled' ] );
434
					} else {
435
						$del = Xml::check(
436
							'showhiderevisions',
437
							false,
438
							[ 'name' => 'ids[' . $row->log_id . ']' ]
439
						);
440
					}
441
				} else {
442
					// If event was hidden from sysops
443
					if ( !self::userCan( $row, LogPage::DELETED_RESTRICTED, $user ) ) {
444
						$del = Linker::revDeleteLinkDisabled( $canHide );
445
					} else {
446
						$query = [
447
							'target' => SpecialPage::getTitleFor( 'Log', $row->log_type )->getPrefixedDBkey(),
448
							'type' => 'logging',
449
							'ids' => $row->log_id,
450
						];
451
						$del = Linker::revDeleteLink(
452
							$query,
453
							$entryIsSuppressed,
454
							$canHide && !$canViewThisSuppressedEntry
455
						);
456
					}
457
				}
458
			}
459
		}
460
461
		return $del;
462
	}
463
464
	/**
465
	 * @param stdClass $row Row
466
	 * @param string|array $type
467
	 * @param string|array $action
468
	 * @param string $right
469
	 * @return bool
470
	 */
471
	public static function typeAction( $row, $type, $action, $right = '' ) {
472
		$match = is_array( $type ) ?
473
			in_array( $row->log_type, $type ) : $row->log_type == $type;
474
		if ( $match ) {
475
			$match = is_array( $action ) ?
476
				in_array( $row->log_action, $action ) : $row->log_action == $action;
477
			if ( $match && $right ) {
478
				global $wgUser;
479
				$match = $wgUser->isAllowed( $right );
480
			}
481
		}
482
483
		return $match;
484
	}
485
486
	/**
487
	 * Determine if the current user is allowed to view a particular
488
	 * field of this log row, if it's marked as deleted.
489
	 *
490
	 * @param stdClass $row Row
491
	 * @param int $field
492
	 * @param User $user User to check, or null to use $wgUser
493
	 * @return bool
494
	 */
495
	public static function userCan( $row, $field, User $user = null ) {
496
		return self::userCanBitfield( $row->log_deleted, $field, $user );
497
	}
498
499
	/**
500
	 * Determine if the current user is allowed to view a particular
501
	 * field of this log row, if it's marked as deleted.
502
	 *
503
	 * @param int $bitfield Current field
504
	 * @param int $field
505
	 * @param User $user User to check, or null to use $wgUser
506
	 * @return bool
507
	 */
508
	public static function userCanBitfield( $bitfield, $field, User $user = null ) {
509
		if ( $bitfield & $field ) {
510
			if ( $user === null ) {
511
				global $wgUser;
512
				$user = $wgUser;
513
			}
514
			if ( $bitfield & LogPage::DELETED_RESTRICTED ) {
515
				$permissions = [ 'suppressrevision', 'viewsuppressed' ];
516
			} else {
517
				$permissions = [ 'deletedhistory' ];
518
			}
519
			$permissionlist = implode( ', ', $permissions );
520
			wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
521
			return call_user_func_array( [ $user, 'isAllowedAny' ], $permissions );
522
		}
523
		return true;
524
	}
525
526
	/**
527
	 * @param stdClass $row Row
528
	 * @param int $field One of DELETED_* bitfield constants
529
	 * @return bool
530
	 */
531
	public static function isDeleted( $row, $field ) {
532
		return ( $row->log_deleted & $field ) == $field;
533
	}
534
535
	/**
536
	 * Show log extract. Either with text and a box (set $msgKey) or without (don't set $msgKey)
537
	 *
538
	 * @param OutputPage|string $out By-reference
539
	 * @param string|array $types Log types to show
540
	 * @param string|Title $page The page title to show log entries for
541
	 * @param string $user The user who made the log entries
542
	 * @param array $param Associative Array with the following additional options:
543
	 * - lim Integer Limit of items to show, default is 50
544
	 * - conds Array Extra conditions for the query (e.g. "log_action != 'revision'")
545
	 * - showIfEmpty boolean Set to false if you don't want any output in case the loglist is empty
546
	 *   if set to true (default), "No matching items in log" is displayed if loglist is empty
547
	 * - msgKey Array If you want a nice box with a message, set this to the key of the message.
548
	 *   First element is the message key, additional optional elements are parameters for the key
549
	 *   that are processed with wfMessage
550
	 * - offset Set to overwrite offset parameter in WebRequest
551
	 *   set to '' to unset offset
552
	 * - wrap String Wrap the message in html (usually something like "<div ...>$1</div>").
553
	 * - flags Integer display flags (NO_ACTION_LINK,NO_EXTRA_USER_LINKS)
554
	 * - useRequestParams boolean Set true to use Pager-related parameters in the WebRequest
555
	 * - useMaster boolean Use master DB
556
	 * - extraUrlParams array|bool Additional url parameters for "full log" link (if it is shown)
557
	 * @return int Number of total log items (not limited by $lim)
558
	 */
559
	public static function showLogExtract(
560
		&$out, $types = [], $page = '', $user = '', $param = []
561
	) {
562
		$defaultParameters = [
563
			'lim' => 25,
564
			'conds' => [],
565
			'showIfEmpty' => true,
566
			'msgKey' => [ '' ],
567
			'wrap' => "$1",
568
			'flags' => 0,
569
			'useRequestParams' => false,
570
			'useMaster' => false,
571
			'extraUrlParams' => false,
572
		];
573
		# The + operator appends elements of remaining keys from the right
574
		# handed array to the left handed, whereas duplicated keys are NOT overwritten.
575
		$param += $defaultParameters;
576
		# Convert $param array to individual variables
577
		$lim = $param['lim'];
578
		$conds = $param['conds'];
579
		$showIfEmpty = $param['showIfEmpty'];
580
		$msgKey = $param['msgKey'];
581
		$wrap = $param['wrap'];
582
		$flags = $param['flags'];
583
		$extraUrlParams = $param['extraUrlParams'];
584
585
		$useRequestParams = $param['useRequestParams'];
586
		if ( !is_array( $msgKey ) ) {
587
			$msgKey = [ $msgKey ];
588
		}
589
590
		if ( $out instanceof OutputPage ) {
591
			$context = $out->getContext();
592
		} else {
593
			$context = RequestContext::getMain();
594
		}
595
596
		# Insert list of top 50 (or top $lim) items
597
		$loglist = new LogEventsList( $context, null, $flags );
598
		$pager = new LogPager( $loglist, $types, $user, $page, '', $conds );
599
		if ( !$useRequestParams ) {
600
			# Reset vars that may have been taken from the request
601
			$pager->mLimit = 50;
602
			$pager->mDefaultLimit = 50;
603
			$pager->mOffset = "";
604
			$pager->mIsBackwards = false;
605
		}
606
607
		if ( $param['useMaster'] ) {
608
			$pager->mDb = wfGetDB( DB_MASTER );
609
		}
610
		if ( isset( $param['offset'] ) ) { # Tell pager to ignore WebRequest offset
611
			$pager->setOffset( $param['offset'] );
612
		}
613
614
		if ( $lim > 0 ) {
615
			$pager->mLimit = $lim;
616
		}
617
		// Fetch the log rows and build the HTML if needed
618
		$logBody = $pager->getBody();
619
		$numRows = $pager->getNumRows();
620
621
		$s = '';
622
623
		if ( $logBody ) {
624
			if ( $msgKey[0] ) {
625
				$dir = $context->getLanguage()->getDir();
626
				$lang = $context->getLanguage()->getHtmlCode();
627
628
				$s = Xml::openElement( 'div', [
629
					'class' => "mw-warning-with-logexcerpt mw-content-$dir",
630
					'dir' => $dir,
631
					'lang' => $lang,
632
				] );
633
634
				if ( count( $msgKey ) == 1 ) {
635
					$s .= $context->msg( $msgKey[0] )->parseAsBlock();
636
				} else { // Process additional arguments
637
					$args = $msgKey;
638
					array_shift( $args );
639
					$s .= $context->msg( $msgKey[0], $args )->parseAsBlock();
640
				}
641
			}
642
			$s .= $loglist->beginLogEventsList() .
643
				$logBody .
644
				$loglist->endLogEventsList();
645
		} elseif ( $showIfEmpty ) {
646
			$s = Html::rawElement( 'div', [ 'class' => 'mw-warning-logempty' ],
647
				$context->msg( 'logempty' )->parse() );
648
		}
649
650
		if ( $numRows > $pager->mLimit ) { # Show "Full log" link
651
			$urlParam = [];
652
			if ( $page instanceof Title ) {
653
				$urlParam['page'] = $page->getPrefixedDBkey();
654
			} elseif ( $page != '' ) {
655
				$urlParam['page'] = $page;
656
			}
657
658
			if ( $user != '' ) {
659
				$urlParam['user'] = $user;
660
			}
661
662
			if ( !is_array( $types ) ) { # Make it an array, if it isn't
663
				$types = [ $types ];
664
			}
665
666
			# If there is exactly one log type, we can link to Special:Log?type=foo
667
			if ( count( $types ) == 1 ) {
668
				$urlParam['type'] = $types[0];
669
			}
670
671
			if ( $extraUrlParams !== false ) {
672
				$urlParam = array_merge( $urlParam, $extraUrlParams );
673
			}
674
675
			$s .= Linker::linkKnown(
676
				SpecialPage::getTitleFor( 'Log' ),
677
				$context->msg( 'log-fulllog' )->escaped(),
678
				[],
679
				$urlParam
680
			);
681
		}
682
683
		if ( $logBody && $msgKey[0] ) {
684
			$s .= '</div>';
685
		}
686
687
		if ( $wrap != '' ) { // Wrap message in html
688
			$s = str_replace( '$1', $s, $wrap );
689
		}
690
691
		/* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
692
		if ( Hooks::run( 'LogEventsListShowLogExtract', [ &$s, $types, $page, $user, $param ] ) ) {
693
			// $out can be either an OutputPage object or a String-by-reference
694
			if ( $out instanceof OutputPage ) {
695
				$out->addHTML( $s );
696
			} else {
697
				$out = $s;
698
			}
699
		}
700
701
		return $numRows;
702
	}
703
704
	/**
705
	 * SQL clause to skip forbidden log types for this user
706
	 *
707
	 * @param IDatabase $db
708
	 * @param string $audience Public/user
709
	 * @param User $user User to check, or null to use $wgUser
710
	 * @return string|bool String on success, false on failure.
711
	 */
712
	public static function getExcludeClause( $db, $audience = 'public', User $user = null ) {
713
		global $wgLogRestrictions;
714
715
		if ( $audience != 'public' && $user === null ) {
716
			global $wgUser;
717
			$user = $wgUser;
718
		}
719
720
		// Reset the array, clears extra "where" clauses when $par is used
721
		$hiddenLogs = [];
722
723
		// Don't show private logs to unprivileged users
724
		foreach ( $wgLogRestrictions as $logType => $right ) {
725
			if ( $audience == 'public' || !$user->isAllowed( $right ) ) {
726
				$hiddenLogs[] = $logType;
727
			}
728
		}
729
		if ( count( $hiddenLogs ) == 1 ) {
730
			return 'log_type != ' . $db->addQuotes( $hiddenLogs[0] );
731
		} elseif ( $hiddenLogs ) {
732
			return 'log_type NOT IN (' . $db->makeList( $hiddenLogs ) . ')';
733
		}
734
735
		return false;
736
	}
737
}
738