getBlockErrorFormatter(). * * @since 1.35 */ class BlockErrorFormatter { /** @var TitleFormatter */ private $titleFormatter; /** * @param TitleFormatter $titleFormatter */ public function __construct( TitleFormatter $titleFormatter ) { $this->titleFormatter = $titleFormatter; } /** * Get a block error message. Different message keys are chosen depending on the * block features. Message parameters are formatted for the specified user and * language. * * @param Block $block * @param UserIdentity $user * @param Language $language * @param string $ip * @return Message */ public function getMessage( Block $block, UserIdentity $user, Language $language, $ip ) { $key = $this->getBlockErrorMessageKey( $block ); $params = $this->getBlockErrorMessageParams( $block, $user, $language, $ip ); return new Message( $key, $params ); } /** * Get a standard set of block details for building a block error message. * * @param Block $block * @return mixed[] * - identifier: Information for looking up the block * - targetName: The target, as a string * - blockerName: The blocker, as a string * - reason: Reason for the block * - expiry: Expiry time * - timestamp: Time the block was created */ private function getBlockErrorInfo( Block $block ) { $blocker = $block->getBlocker(); return [ 'identifier' => $block->getIdentifier(), 'targetName' => $block->getTargetName(), 'blockerName' => $blocker ? $blocker->getName() : '', 'reason' => $block->getReasonComment(), 'expiry' => $block->getExpiry(), 'timestamp' => $block->getTimestamp(), ]; } /** * Get a standard set of block details for building a block error message, * formatted for a specified user and language. * * @since 1.35 * @param Block $block * @param UserIdentity $user * @param Language $language * @return mixed[] See getBlockErrorInfo */ private function getFormattedBlockErrorInfo( Block $block, UserIdentity $user, Language $language ) { $info = $this->getBlockErrorInfo( $block ); $info['expiry'] = $language->formatExpiry( $info['expiry'], true, 'infinity', $user ); $info['timestamp'] = $language->userTimeAndDate( $info['timestamp'], $user ); $info['blockerName'] = $language->embedBidi( $info['blockerName'] ); $info['targetName'] = $language->embedBidi( $info['targetName'] ); $info['reason'] = $this->formatBlockReason( $info['reason'], $language ); return $info; } /** * Format the block reason as plain wikitext in the specified language. * * @param CommentStoreComment $reason * @param Language $language * @return string */ private function formatBlockReason( CommentStoreComment $reason, Language $language ) { if ( $reason->text === '' ) { $message = new Message( 'blockednoreason', [], $language ); return $message->plain(); } return $reason->message->inLanguage( $language )->plain(); } /** * Create a link to the blocker's user page. This must be done here rather than in * the message translation, because the blocker may not be a local user, in which * case their page cannot be linked. * * @param ?UserIdentity $blocker * @param Language $language * @return string Link to the blocker's page; blocker's name if not a local user */ private function formatBlockerLink( ?UserIdentity $blocker, Language $language ) { if ( !$blocker ) { // TODO should we say something? This is just matching the code before // the refactoring in late July 2021 return ''; } if ( $blocker->getId() === 0 ) { // Foreign user // TODO what about blocks placed by IPs? Shouldn't we check based on // $blocker's wiki instead? This is just matching the code before the // refactoring in late July 2021. return $language->embedBidi( $blocker->getName() ); } $blockerUserpage = PageReferenceValue::localReference( NS_USER, $blocker->getName() ); $blockerText = $language->embedBidi( $this->titleFormatter->getText( $blockerUserpage ) ); $prefixedText = $this->titleFormatter->getPrefixedText( $blockerUserpage ); return "[[{$prefixedText}|{$blockerText}]]"; } /** * Determine the block error message key by examining the block. * * @param Block $block * @return string Message key */ private function getBlockErrorMessageKey( Block $block ) { $key = 'blockedtext'; if ( $block instanceof DatabaseBlock ) { if ( $block->getType() === Block::TYPE_AUTO ) { $key = 'autoblockedtext'; } elseif ( !$block->isSitewide() ) { $key = 'blockedtext-partial'; } } elseif ( $block instanceof SystemBlock ) { $key = 'systemblockedtext'; } elseif ( $block instanceof CompositeBlock ) { $key = 'blockedtext-composite'; } return $key; } /** * Get the formatted parameters needed to build the block error messages handled by * getBlockErrorMessageKey. * * @param Block $block * @param UserIdentity $user * @param Language $language * @param string $ip * @return mixed[] Params used by standard block error messages, in order: * - blockerLink: Link to the blocker's user page, if any; otherwise same as blockerName * - reason: Reason for the block * - ip: IP address of the user attempting to perform an action * - blockerName: The blocker, as a bidi-embedded string * - identifier: Information for looking up the block * - expiry: Expiry time, in the specified language * - targetName: The target, as a bidi-embedded string * - timestamp: Time the block was created, in the specified language */ private function getBlockErrorMessageParams( Block $block, UserIdentity $user, Language $language, $ip ) { $info = $this->getFormattedBlockErrorInfo( $block, $user, $language ); // Add params that are specific to the standard block errors $info['ip'] = $ip; $info['blockerLink'] = $this->formatBlockerLink( $block->getBlocker(), $language ); // Display the CompositeBlock identifier as a message containing relevant block IDs if ( $block instanceof CompositeBlock ) { $ids = $language->commaList( array_map( static function ( $id ) { return '#' . $id; }, array_filter( $info['identifier'], 'is_int' ) ) ); if ( $ids === '' ) { $idsMsg = new Message( 'blockedtext-composite-no-ids', [], $language ); } else { $idsMsg = new Message( 'blockedtext-composite-ids', [ $ids ], $language ); } $info['identifier'] = $idsMsg->plain(); } // Messages expect the params in this order $order = [ 'blockerLink', 'reason', 'ip', 'blockerName', 'identifier', 'expiry', 'targetName', 'timestamp', ]; $params = []; foreach ( $order as $item ) { $params[] = $info[$item]; } return $params; } }