Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
46.97% |
155 / 330 |
|
8.33% |
1 / 12 |
CRAP | |
0.00% |
0 / 1 |
BlockListPager | |
47.11% |
155 / 329 |
|
8.33% |
1 / 12 |
731.06 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
getFieldNames | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
formatValue | |
85.00% |
85 / 100 |
|
0.00% |
0 / 1 |
24.79 | |||
formatTarget | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
56 | |||
getBlockChangeLinks | |
0.00% |
0 / 46 |
|
0.00% |
0 / 1 |
30 | |||
getRestrictionListHTML | |
78.69% |
48 / 61 |
|
0.00% |
0 / 1 |
14.64 | |||
getQueryInfo | |
0.00% |
0 / 45 |
|
0.00% |
0 / 1 |
6 | |||
getTableClass | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getIndexField | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDefaultSort | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isFieldSortable | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
preprocessResults | |
100.00% |
22 / 22 |
|
100.00% |
1 / 1 |
9 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
16 | * http://www.gnu.org/copyleft/gpl.html |
17 | * |
18 | * @file |
19 | * @ingroup Pager |
20 | */ |
21 | |
22 | namespace MediaWiki\Pager; |
23 | |
24 | use MediaWiki\Block\Block; |
25 | use MediaWiki\Block\BlockActionInfo; |
26 | use MediaWiki\Block\BlockRestrictionStore; |
27 | use MediaWiki\Block\BlockUtils; |
28 | use MediaWiki\Block\HideUserUtils; |
29 | use MediaWiki\Block\Restriction\ActionRestriction; |
30 | use MediaWiki\Block\Restriction\NamespaceRestriction; |
31 | use MediaWiki\Block\Restriction\PageRestriction; |
32 | use MediaWiki\Block\Restriction\Restriction; |
33 | use MediaWiki\Cache\LinkBatchFactory; |
34 | use MediaWiki\CommentFormatter\RowCommentFormatter; |
35 | use MediaWiki\CommentStore\CommentStore; |
36 | use MediaWiki\Context\IContextSource; |
37 | use MediaWiki\Html\Html; |
38 | use MediaWiki\Linker\Linker; |
39 | use MediaWiki\Linker\LinkRenderer; |
40 | use MediaWiki\MainConfigNames; |
41 | use MediaWiki\SpecialPage\SpecialPageFactory; |
42 | use MediaWiki\User\UserIdentity; |
43 | use MediaWiki\Utils\MWTimestamp; |
44 | use stdClass; |
45 | use Wikimedia\Rdbms\IConnectionProvider; |
46 | use Wikimedia\Rdbms\IResultWrapper; |
47 | |
48 | /** |
49 | * @ingroup Pager |
50 | */ |
51 | class BlockListPager extends TablePager { |
52 | |
53 | /** @var array */ |
54 | protected $conds; |
55 | |
56 | /** |
57 | * Array of restrictions. |
58 | * |
59 | * @var Restriction[] |
60 | */ |
61 | protected $restrictions = []; |
62 | |
63 | private BlockActionInfo $blockActionInfo; |
64 | private BlockRestrictionStore $blockRestrictionStore; |
65 | private BlockUtils $blockUtils; |
66 | private HideUserUtils $hideUserUtils; |
67 | private CommentStore $commentStore; |
68 | private LinkBatchFactory $linkBatchFactory; |
69 | private RowCommentFormatter $rowCommentFormatter; |
70 | private SpecialPageFactory $specialPageFactory; |
71 | |
72 | /** @var string[] */ |
73 | private $formattedComments = []; |
74 | |
75 | /** @var string[] Cache of messages to avoid them being recreated for every row of the pager. */ |
76 | private $messages = []; |
77 | |
78 | /** |
79 | * @param IContextSource $context |
80 | * @param BlockActionInfo $blockActionInfo |
81 | * @param BlockRestrictionStore $blockRestrictionStore |
82 | * @param BlockUtils $blockUtils |
83 | * @param HideUserUtils $hideUserUtils |
84 | * @param CommentStore $commentStore |
85 | * @param LinkBatchFactory $linkBatchFactory |
86 | * @param LinkRenderer $linkRenderer |
87 | * @param IConnectionProvider $dbProvider |
88 | * @param RowCommentFormatter $rowCommentFormatter |
89 | * @param SpecialPageFactory $specialPageFactory |
90 | * @param array $conds |
91 | */ |
92 | public function __construct( |
93 | IContextSource $context, |
94 | BlockActionInfo $blockActionInfo, |
95 | BlockRestrictionStore $blockRestrictionStore, |
96 | BlockUtils $blockUtils, |
97 | HideUserUtils $hideUserUtils, |
98 | CommentStore $commentStore, |
99 | LinkBatchFactory $linkBatchFactory, |
100 | LinkRenderer $linkRenderer, |
101 | IConnectionProvider $dbProvider, |
102 | RowCommentFormatter $rowCommentFormatter, |
103 | SpecialPageFactory $specialPageFactory, |
104 | $conds |
105 | ) { |
106 | // Set database before parent constructor to avoid setting it there |
107 | $this->mDb = $dbProvider->getReplicaDatabase(); |
108 | |
109 | parent::__construct( $context, $linkRenderer ); |
110 | |
111 | $this->blockActionInfo = $blockActionInfo; |
112 | $this->blockRestrictionStore = $blockRestrictionStore; |
113 | $this->blockUtils = $blockUtils; |
114 | $this->hideUserUtils = $hideUserUtils; |
115 | $this->commentStore = $commentStore; |
116 | $this->linkBatchFactory = $linkBatchFactory; |
117 | $this->rowCommentFormatter = $rowCommentFormatter; |
118 | $this->specialPageFactory = $specialPageFactory; |
119 | $this->conds = $conds; |
120 | $this->mDefaultDirection = IndexPager::DIR_DESCENDING; |
121 | } |
122 | |
123 | protected function getFieldNames() { |
124 | static $headers = null; |
125 | |
126 | if ( $headers === null ) { |
127 | $headers = [ |
128 | 'bl_timestamp' => 'blocklist-timestamp', |
129 | 'target' => 'blocklist-target', |
130 | 'bl_expiry' => 'blocklist-expiry', |
131 | 'by' => 'blocklist-by', |
132 | 'params' => 'blocklist-params', |
133 | 'bl_reason' => 'blocklist-reason', |
134 | ]; |
135 | foreach ( $headers as $key => $val ) { |
136 | $headers[$key] = $this->msg( $val )->text(); |
137 | } |
138 | } |
139 | |
140 | return $headers; |
141 | } |
142 | |
143 | /** |
144 | * @param string $name |
145 | * @param string|null $value |
146 | * @return string |
147 | */ |
148 | public function formatValue( $name, $value ) { |
149 | if ( $this->messages === [] ) { |
150 | $keys = [ |
151 | 'anononlyblock', |
152 | 'blanknamespace', |
153 | 'createaccountblock', |
154 | 'noautoblockblock', |
155 | 'emailblock', |
156 | 'blocklist-nousertalk', |
157 | 'unblocklink', |
158 | 'remove-blocklink', |
159 | 'change-blocklink', |
160 | 'blocklist-editing', |
161 | 'blocklist-editing-sitewide', |
162 | 'blocklist-hidden-param', |
163 | 'blocklist-hidden-placeholder', |
164 | ]; |
165 | |
166 | foreach ( $keys as $key ) { |
167 | $this->messages[$key] = $this->msg( $key )->text(); |
168 | } |
169 | } |
170 | |
171 | /** @var stdClass $row */ |
172 | $row = $this->mCurrentRow; |
173 | |
174 | $language = $this->getLanguage(); |
175 | |
176 | $linkRenderer = $this->getLinkRenderer(); |
177 | |
178 | switch ( $name ) { |
179 | case 'bl_timestamp': |
180 | // Link the timestamp to the block ID. This allows users without permissions to change blocks |
181 | // to be able to generate a link to a specific block. |
182 | $formatted = $linkRenderer->makeKnownLink( |
183 | $this->specialPageFactory->getTitleForAlias( 'BlockList' ), |
184 | $language->userTimeAndDate( $value, $this->getUser() ), |
185 | [], |
186 | [ 'wpTarget' => "#{$row->bl_id}" ], |
187 | ); |
188 | break; |
189 | |
190 | case 'target': |
191 | $formatted = $this->formatTarget( $row ); |
192 | break; |
193 | |
194 | case 'bl_expiry': |
195 | $formatted = htmlspecialchars( $language->formatExpiry( |
196 | $value, |
197 | /* User preference timezone */true, |
198 | 'infinity', |
199 | $this->getUser() |
200 | ) ); |
201 | if ( $this->getAuthority()->isAllowed( 'block' ) ) { |
202 | $links = $this->getBlockChangeLinks( $row ); |
203 | $formatted .= ' ' . Html::rawElement( |
204 | 'span', |
205 | [ 'class' => 'mw-blocklist-actions' ], |
206 | $this->msg( 'parentheses' )->rawParams( |
207 | $language->pipeList( $links ) )->escaped() |
208 | ); |
209 | } |
210 | if ( $value !== 'infinity' ) { |
211 | $timestamp = new MWTimestamp( $value ); |
212 | $formatted .= '<br />' . $this->msg( |
213 | 'ipb-blocklist-duration-left', |
214 | $language->formatDurationBetweenTimestamps( |
215 | (int)$timestamp->getTimestamp( TS_UNIX ), |
216 | MWTimestamp::time(), |
217 | 4 |
218 | ) |
219 | )->escaped(); |
220 | } |
221 | break; |
222 | |
223 | case 'by': |
224 | $formatted = Linker::userLink( (int)$value, $row->bl_by_text ); |
225 | $formatted .= Linker::userToolLinks( (int)$value, $row->bl_by_text ); |
226 | break; |
227 | |
228 | case 'bl_reason': |
229 | $formatted = $this->formattedComments[$this->getResultOffset()]; |
230 | break; |
231 | |
232 | case 'params': |
233 | $properties = []; |
234 | |
235 | if ( $row->bl_deleted ) { |
236 | $properties[] = htmlspecialchars( $this->messages['blocklist-hidden-param' ] ); |
237 | } |
238 | if ( $row->bl_sitewide ) { |
239 | $properties[] = htmlspecialchars( $this->messages['blocklist-editing-sitewide'] ); |
240 | } |
241 | |
242 | if ( !$row->bl_sitewide && $this->restrictions ) { |
243 | $list = $this->getRestrictionListHTML( $row ); |
244 | if ( $list ) { |
245 | $properties[] = htmlspecialchars( $this->messages['blocklist-editing'] ) . $list; |
246 | } |
247 | } |
248 | |
249 | if ( $row->bl_anon_only ) { |
250 | $properties[] = htmlspecialchars( $this->messages['anononlyblock'] ); |
251 | } |
252 | if ( $row->bl_create_account ) { |
253 | $properties[] = htmlspecialchars( $this->messages['createaccountblock'] ); |
254 | } |
255 | if ( $row->bt_user && !$row->bl_enable_autoblock ) { |
256 | $properties[] = htmlspecialchars( $this->messages['noautoblockblock'] ); |
257 | } |
258 | |
259 | if ( $row->bl_block_email ) { |
260 | $properties[] = htmlspecialchars( $this->messages['emailblock'] ); |
261 | } |
262 | |
263 | if ( !$row->bl_allow_usertalk ) { |
264 | $properties[] = htmlspecialchars( $this->messages['blocklist-nousertalk'] ); |
265 | } |
266 | |
267 | $formatted = Html::rawElement( |
268 | 'ul', |
269 | [], |
270 | implode( '', array_map( static function ( $prop ) { |
271 | return Html::rawElement( |
272 | 'li', |
273 | [], |
274 | $prop |
275 | ); |
276 | }, $properties ) ) |
277 | ); |
278 | break; |
279 | |
280 | default: |
281 | $formatted = "Unable to format $name"; |
282 | break; |
283 | } |
284 | |
285 | return $formatted; |
286 | } |
287 | |
288 | /** |
289 | * Format the target field |
290 | * @param stdClass $row |
291 | * @return string |
292 | */ |
293 | private function formatTarget( $row ) { |
294 | if ( $row->bt_auto ) { |
295 | return $this->msg( 'autoblockid', $row->bl_id )->parse(); |
296 | } |
297 | |
298 | [ $target, $type ] = $this->blockUtils->parseBlockTargetRow( $row ); |
299 | |
300 | if ( $type === Block::TYPE_RANGE ) { |
301 | $userId = 0; |
302 | $userName = $target; |
303 | } elseif ( ( $row->hu_deleted ?? null ) |
304 | && !$this->getAuthority()->isAllowed( 'hideuser' ) |
305 | ) { |
306 | return Html::element( |
307 | 'span', |
308 | [ 'class' => 'mw-blocklist-hidden' ], |
309 | $this->messages['blocklist-hidden-placeholder'] |
310 | ); |
311 | } elseif ( $target instanceof UserIdentity ) { |
312 | $userId = $target->getId(); |
313 | $userName = $target->getName(); |
314 | } elseif ( is_string( $target ) ) { |
315 | return htmlspecialchars( $target ); |
316 | } else { |
317 | return $this->msg( 'empty-username' )->escaped(); |
318 | } |
319 | return Linker::userLink( $userId, $userName ) . |
320 | Linker::userToolLinks( |
321 | $userId, |
322 | $userName, |
323 | false, |
324 | Linker::TOOL_LINKS_NOBLOCK |
325 | ); |
326 | } |
327 | |
328 | /** |
329 | * Get unblock and change-block links. |
330 | * |
331 | * @param stdClass $row Block data. |
332 | * @return string[] Array of HTML links. |
333 | */ |
334 | private function getBlockChangeLinks( $row ): array { |
335 | $linkRenderer = $this->getLinkRenderer(); |
336 | $links = []; |
337 | if ( $row->bt_auto ) { |
338 | $target = "#{$row->bl_id}"; |
339 | } else { |
340 | $target = $row->bt_address ?? $row->bt_user_text; |
341 | } |
342 | if ( $this->getConfig()->get( MainConfigNames::UseCodexSpecialBlock ) ) { |
343 | $query = [ 'id' => $row->bl_id ]; |
344 | if ( $row->bt_auto ) { |
345 | $links[] = $linkRenderer->makeKnownLink( |
346 | $this->specialPageFactory->getTitleForAlias( 'Block' ), |
347 | $this->messages['remove-blocklink'], |
348 | [], |
349 | $query + [ |
350 | 'wpTarget' => $target, |
351 | 'remove' => '1' |
352 | ] |
353 | ); |
354 | } else { |
355 | $specialBlock = $this->specialPageFactory->getTitleForAlias( "Block/$target" ); |
356 | $links[] = $linkRenderer->makeKnownLink( |
357 | $specialBlock, |
358 | $this->messages['remove-blocklink'], |
359 | [], |
360 | $query + [ 'remove' => '1' ] |
361 | ); |
362 | $links[] = $linkRenderer->makeKnownLink( |
363 | $specialBlock, |
364 | $this->messages['change-blocklink'], |
365 | [], |
366 | $query |
367 | ); |
368 | } |
369 | } else { |
370 | if ( $row->bt_auto ) { |
371 | $links[] = $linkRenderer->makeKnownLink( |
372 | $this->specialPageFactory->getTitleForAlias( 'Unblock' ), |
373 | $this->messages['unblocklink'], |
374 | [], |
375 | [ 'wpTarget' => "#{$row->bl_id}" ] |
376 | ); |
377 | } else { |
378 | $links[] = $linkRenderer->makeKnownLink( |
379 | $this->specialPageFactory->getTitleForAlias( "Unblock/$target" ), |
380 | $this->messages['unblocklink'] |
381 | ); |
382 | $links[] = $linkRenderer->makeKnownLink( |
383 | $this->specialPageFactory->getTitleForAlias( "Block/$target" ), |
384 | $this->messages['change-blocklink'] |
385 | ); |
386 | } |
387 | } |
388 | return $links; |
389 | } |
390 | |
391 | /** |
392 | * Get Restriction List HTML |
393 | * |
394 | * @param stdClass $row |
395 | * |
396 | * @return string |
397 | */ |
398 | private function getRestrictionListHTML( stdClass $row ) { |
399 | $items = []; |
400 | $linkRenderer = $this->getLinkRenderer(); |
401 | |
402 | foreach ( $this->restrictions as $restriction ) { |
403 | if ( $restriction->getBlockId() !== (int)$row->bl_id ) { |
404 | continue; |
405 | } |
406 | |
407 | switch ( $restriction->getType() ) { |
408 | case PageRestriction::TYPE: |
409 | '@phan-var PageRestriction $restriction'; |
410 | if ( $restriction->getTitle() ) { |
411 | $items[$restriction->getType()][] = Html::rawElement( |
412 | 'li', |
413 | [], |
414 | $linkRenderer->makeLink( $restriction->getTitle() ) |
415 | ); |
416 | } |
417 | break; |
418 | case NamespaceRestriction::TYPE: |
419 | $text = $restriction->getValue() === NS_MAIN |
420 | ? $this->messages['blanknamespace'] |
421 | : $this->getLanguage()->getFormattedNsText( |
422 | $restriction->getValue() |
423 | ); |
424 | if ( $text ) { |
425 | $items[$restriction->getType()][] = Html::rawElement( |
426 | 'li', |
427 | [], |
428 | $linkRenderer->makeLink( |
429 | $this->specialPageFactory->getTitleForAlias( 'Allpages' ), |
430 | $text, |
431 | [], |
432 | [ |
433 | 'namespace' => $restriction->getValue() |
434 | ] |
435 | ) |
436 | ); |
437 | } |
438 | break; |
439 | case ActionRestriction::TYPE: |
440 | $actionName = $this->blockActionInfo->getActionFromId( $restriction->getValue() ); |
441 | $enablePartialActionBlocks = |
442 | $this->getConfig()->get( MainConfigNames::EnablePartialActionBlocks ); |
443 | if ( $actionName && $enablePartialActionBlocks ) { |
444 | $items[$restriction->getType()][] = Html::rawElement( |
445 | 'li', |
446 | [], |
447 | // The following messages may be used here: |
448 | // * ipb-action-create |
449 | // * ipb-action-move |
450 | // * ipb-action-upload |
451 | $this->msg( 'ipb-action-' . |
452 | $this->blockActionInfo->getActionFromId( $restriction->getValue() ) )->escaped() |
453 | ); |
454 | } |
455 | break; |
456 | } |
457 | } |
458 | |
459 | if ( !$items ) { |
460 | return ''; |
461 | } |
462 | |
463 | $sets = []; |
464 | foreach ( $items as $key => $value ) { |
465 | $sets[] = Html::rawElement( |
466 | 'li', |
467 | [], |
468 | // The following messages may be used here: |
469 | // * blocklist-editing-sitewide |
470 | // * blocklist-editing-page |
471 | // * blocklist-editing-ns |
472 | // * blocklist-editing-action |
473 | $this->msg( 'blocklist-editing-' . $key ) . Html::rawElement( |
474 | 'ul', |
475 | [], |
476 | implode( '', $value ) |
477 | ) |
478 | ); |
479 | } |
480 | |
481 | return Html::rawElement( |
482 | 'ul', |
483 | [], |
484 | implode( '', $sets ) |
485 | ); |
486 | } |
487 | |
488 | public function getQueryInfo() { |
489 | $db = $this->getDatabase(); |
490 | $commentQuery = $this->commentStore->getJoin( 'bl_reason' ); |
491 | $info = [ |
492 | 'tables' => array_merge( |
493 | [ |
494 | 'block', |
495 | 'block_by_actor' => 'actor', |
496 | 'block_target', |
497 | ], |
498 | $commentQuery['tables'] |
499 | ), |
500 | 'fields' => [ |
501 | // The target fields should be those accepted by BlockUtils::parseBlockTargetRow() |
502 | 'bt_address', |
503 | 'bt_user_text', |
504 | 'bt_user', |
505 | 'bt_auto', |
506 | 'bt_range_start', |
507 | 'bt_range_end', |
508 | // Block fields and aliases |
509 | 'bl_id', |
510 | 'bl_by' => 'block_by_actor.actor_user', |
511 | 'bl_by_text' => 'block_by_actor.actor_name', |
512 | 'bl_timestamp', |
513 | 'bl_anon_only', |
514 | 'bl_create_account', |
515 | 'bl_enable_autoblock', |
516 | 'bl_expiry', |
517 | 'bl_deleted', |
518 | 'bl_block_email', |
519 | 'bl_allow_usertalk', |
520 | 'bl_sitewide', |
521 | ] + $commentQuery['fields'], |
522 | 'conds' => $this->conds, |
523 | 'join_conds' => [ |
524 | 'block_by_actor' => [ 'JOIN', 'actor_id=bl_by_actor' ], |
525 | 'block_target' => [ 'JOIN', 'bt_id=bl_target' ], |
526 | ] + $commentQuery['joins'] |
527 | ]; |
528 | |
529 | # Filter out any expired blocks |
530 | $info['conds'][] = $db->expr( 'bl_expiry', '>', $db->timestamp() ); |
531 | |
532 | # Filter out blocks with the deleted option if the user doesn't |
533 | # have permission to see hidden users |
534 | # TODO: consider removing this -- we could just redact them instead. |
535 | # The mere fact that an admin has deleted a user does not need to |
536 | # be private and could be included in block lists and logs for |
537 | # transparency purposes. Previously, filtering out deleted blocks |
538 | # was a convenient way to avoid showing the target name. |
539 | if ( !$this->getAuthority()->isAllowed( 'hideuser' ) ) { |
540 | $info['conds']['bl_deleted'] = 0; |
541 | } |
542 | |
543 | # Determine if the user is hidden |
544 | # With multiblocks we can't just rely on bl_deleted in the row being formatted |
545 | $info['fields']['hu_deleted'] = $this->hideUserUtils->getExpression( |
546 | $db, |
547 | 'block_target.bt_user', |
548 | HideUserUtils::HIDDEN_USERS ); |
549 | return $info; |
550 | } |
551 | |
552 | protected function getTableClass() { |
553 | return parent::getTableClass() . ' mw-blocklist'; |
554 | } |
555 | |
556 | public function getIndexField() { |
557 | return [ [ 'bl_timestamp', 'bl_id' ] ]; |
558 | } |
559 | |
560 | public function getDefaultSort() { |
561 | return ''; |
562 | } |
563 | |
564 | protected function isFieldSortable( $name ) { |
565 | return false; |
566 | } |
567 | |
568 | /** |
569 | * Do a LinkBatch query to minimise database load when generating all these links |
570 | * @param IResultWrapper $result |
571 | */ |
572 | public function preprocessResults( $result ) { |
573 | // Do a link batch query |
574 | $lb = $this->linkBatchFactory->newLinkBatch(); |
575 | $lb->setCaller( __METHOD__ ); |
576 | |
577 | $partialBlocks = []; |
578 | foreach ( $result as $row ) { |
579 | $target = $row->bt_address ?? $row->bt_user_text; |
580 | if ( $target !== null ) { |
581 | $lb->add( NS_USER, $target ); |
582 | $lb->add( NS_USER_TALK, $target ); |
583 | } |
584 | |
585 | if ( isset( $row->bl_by_text ) ) { |
586 | $lb->add( NS_USER, $row->bl_by_text ); |
587 | $lb->add( NS_USER_TALK, $row->bl_by_text ); |
588 | } |
589 | |
590 | if ( !$row->bl_sitewide ) { |
591 | $partialBlocks[] = (int)$row->bl_id; |
592 | } |
593 | } |
594 | |
595 | if ( $partialBlocks ) { |
596 | // Mutations to the $row object are not persisted. The restrictions will |
597 | // need be stored in a separate store. |
598 | $this->restrictions = $this->blockRestrictionStore->loadByBlockId( $partialBlocks ); |
599 | |
600 | foreach ( $this->restrictions as $restriction ) { |
601 | if ( $restriction->getType() === PageRestriction::TYPE ) { |
602 | '@phan-var PageRestriction $restriction'; |
603 | $title = $restriction->getTitle(); |
604 | if ( $title ) { |
605 | $lb->addObj( $title ); |
606 | } |
607 | } |
608 | } |
609 | } |
610 | |
611 | $lb->execute(); |
612 | |
613 | // Format comments |
614 | // The keys of formattedComments will be the corresponding offset into $result |
615 | $this->formattedComments = $this->rowCommentFormatter->formatRows( $result, 'bl_reason' ); |
616 | } |
617 | |
618 | } |
619 | |
620 | /** |
621 | * Retain the old class name for backwards compatibility. |
622 | * @deprecated since 1.41 |
623 | */ |
624 | class_alias( BlockListPager::class, 'BlockListPager' ); |