Move creation of BlockErrorFormatter into FormatterFactory

The idea is that all formatters that need the user language or
other request specific context should be instantiated by
FormatterFactory.

Change-Id: I8334cc89dcf0f293298b82e004116be50a90f0d1
This commit is contained in:
daniel 2023-10-01 14:03:37 +02:00 committed by James D. Forrester
parent edfc0acede
commit 3d55397207
23 changed files with 397 additions and 106 deletions

View file

@ -456,6 +456,15 @@ because of Phabricator reports.
Use PageUpdater instance.
* SpecialBlock::getSuggestedDurations() has been deprecated, use
Language::getBlockDurations() instead.
* MediaWikiServices::getBlockErrorFormatter() has been deprecated, use
MediaWikiServices::getFormatterFactory()->getBlockErrorFormatter() instead.
* (T352284) Some user options-related classes were moved over to the existing
MediaWiki\User\Options namespace. Old names are deprecated and kept as
aliases for backwards-compatibility:
- DefaultOptionsLookup
- UserOptionsLookup
- UserOptionsManager
- StaticUserOptionsLookup
* Database::listViews() has been deprecated. This was previously used to filter
views out of the return value of Database::listTables(). Now listTables()
will not include views. MediaWiki does not use views.

View file

@ -1527,6 +1527,8 @@ $wgAutoloadLocalClasses = [
'MediaWiki\\Json\\JsonUnserializableTrait' => __DIR__ . '/includes/json/JsonUnserializableTrait.php',
'MediaWiki\\Json\\JsonUnserializer' => __DIR__ . '/includes/json/JsonUnserializer.php',
'MediaWiki\\Language\\FormatterFactory' => __DIR__ . '/includes/language/FormatterFactory.php',
'MediaWiki\\Language\\LazyLocalizationContext' => __DIR__ . '/includes/language/LazyLocalizationContext.php',
'MediaWiki\\Language\\LocalizationContext' => __DIR__ . '/includes/language/LocalizationContext.php',
'MediaWiki\\Language\\RawMessage' => __DIR__ . '/includes/language/RawMessage.php',
'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/includes/languages/data/CrhExceptions.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/includes/languages/data/Names.php',

View file

@ -773,8 +773,10 @@ class MediaWikiServices extends ServiceContainer {
/**
* @since 1.35
* @deprecated since 1.42, use getFormatterFactory()->getBlockErrorFormatter() instead.
*/
public function getBlockErrorFormatter(): BlockErrorFormatter {
wfDeprecated( __METHOD__, '1.42' );
return $this->getService( 'BlockErrorFormatter' );
}

View file

@ -833,7 +833,6 @@ class PermissionManager {
$messages = $this->blockErrorFormatter->getMessages(
$block,
$user,
$context->getLanguage(),
$context->getRequest()->getIP()
);

View file

@ -304,7 +304,6 @@ class UserAuthority implements Authority {
$messages = $this->blockErrorFormatter->getMessages(
$userBlock,
$this->actor,
$this->uiContext->getLanguage(),
$this->request->getIP()
);

View file

@ -103,6 +103,7 @@ use MediaWiki\JobQueue\JobFactory;
use MediaWiki\JobQueue\JobQueueGroupFactory;
use MediaWiki\Json\JsonCodec;
use MediaWiki\Language\FormatterFactory;
use MediaWiki\Language\LazyLocalizationContext;
use MediaWiki\Languages\LanguageConverterFactory;
use MediaWiki\Languages\LanguageFactory;
use MediaWiki\Languages\LanguageFallback;
@ -369,10 +370,10 @@ return [
},
'BlockErrorFormatter' => static function ( MediaWikiServices $services ): BlockErrorFormatter {
return new BlockErrorFormatter(
$services->getTitleFormatter(),
$services->getHookContainer(),
$services->getUserIdentityUtils()
return $services->getFormatterFactory()->getBlockErrorFormatter(
new LazyLocalizationContext( static function () {
return RequestContext::getMain();
} )
);
},
@ -843,7 +844,13 @@ return [
},
'FormatterFactory' => static function ( MediaWikiServices $services ): FormatterFactory {
return new FormatterFactory( $services->getMessageCache() );
return new FormatterFactory(
$services->getMessageCache(),
$services->getTitleFormatter(),
$services->getHookContainer(),
$services->getUserIdentityUtils(),
$services->getLanguageFactory()
);
},
'GenderCache' => static function ( MediaWikiServices $services ): GenderCache {
@ -1704,7 +1711,11 @@ return [
$services->getGroupPermissionsLookup(),
$services->getUserGroupManager(),
$services->getBlockManager(),
$services->getBlockErrorFormatter(),
$services->getFormatterFactory()->getBlockErrorFormatter(
new LazyLocalizationContext( static function () {
return RequestContext::getMain();
} )
),
$services->getHookContainer(),
$services->getUserCache(),
$services->getRedirectLookup(),

View file

@ -1556,12 +1556,13 @@ abstract class ApiBase extends ContextSource {
* @return never
*/
public function dieBlocked( Block $block ) {
$blockErrorFormatter = MediaWikiServices::getInstance()->getBlockErrorFormatter();
$blockErrorFormatter = MediaWikiServices::getInstance()->getFormatterFactory()
->getBlockErrorFormatter( $this->getContext() );
$msg = $blockErrorFormatter->getMessage(
$block,
$this->getUser(),
$this->getLanguage(),
null,
$this->getRequest()->getIP()
);

View file

@ -425,10 +425,11 @@ abstract class AbstractBlock implements Block {
public function getPermissionsError( IContextSource $context ) {
wfDeprecated( __METHOD__, '1.35' );
$message = MediaWikiServices::getInstance()
->getBlockErrorFormatter()->getMessage(
->getFormatterFactory()->getBlockErrorFormatter( $context )
->getMessage(
$this,
$context->getUser(),
$context->getLanguage(),
null,
$context->getRequest()->getIP()
);
return array_merge( [ $message->getKey() ], $message->getParams() );

View file

@ -24,6 +24,8 @@ use Language;
use MediaWiki\CommentStore\CommentStoreComment;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Language\LocalizationContext;
use MediaWiki\Languages\LanguageFactory;
use MediaWiki\Page\PageReferenceValue;
use MediaWiki\Title\TitleFormatter;
use MediaWiki\User\UserIdentity;
@ -38,30 +40,32 @@ use Message;
*/
class BlockErrorFormatter {
/** @var TitleFormatter */
private $titleFormatter;
private TitleFormatter $titleFormatter;
private HookRunner $hookRunner;
private UserIdentityUtils $userIdentityUtils;
private LocalizationContext $uiContext;
private LanguageFactory $languageFactory;
/** @var HookRunner */
private $hookRunner;
/**
* @var UserIdentityUtils
*/
private $userIdentityUtils;
/**
* @param TitleFormatter $titleFormatter
* @param HookContainer $hookContainer
* @param UserIdentityUtils $userIdentityUtils
*/
public function __construct(
TitleFormatter $titleFormatter,
HookContainer $hookContainer,
UserIdentityUtils $userIdentityUtils
UserIdentityUtils $userIdentityUtils,
LanguageFactory $languageFactory,
LocalizationContext $uiContext
) {
$this->titleFormatter = $titleFormatter;
$this->hookRunner = new HookRunner( $hookContainer );
$this->userIdentityUtils = $userIdentityUtils;
$this->languageFactory = $languageFactory;
$this->uiContext = $uiContext;
}
/**
* @return Language
*/
private function getLanguage(): Language {
return $this->languageFactory->getLanguage( $this->uiContext->getLanguageCode() );
}
/**
@ -74,19 +78,19 @@ class BlockErrorFormatter {
*
* @param Block $block
* @param UserIdentity $user
* @param Language $language
* @param mixed $language Unused since 1.42
* @param string $ip
* @return Message
*/
public function getMessage(
Block $block,
UserIdentity $user,
Language $language,
$language,
string $ip
): Message {
$key = $this->getBlockErrorMessageKey( $block, $user );
$params = $this->getBlockErrorMessageParams( $block, $user, $language, $ip );
return new Message( $key, $params );
$params = $this->getBlockErrorMessageParams( $block, $user, $ip );
return $this->uiContext->msg( $key, $params );
}
/**
@ -95,19 +99,17 @@ class BlockErrorFormatter {
* @since 1.42
* @param Block $block
* @param UserIdentity $user
* @param Language $language
* @param string $ip
* @return Message[]
*/
public function getMessages(
Block $block,
UserIdentity $user,
Language $language,
string $ip
): array {
$messages = [];
foreach ( $block->toArray() as $singleBlock ) {
$messages[] = $this->getMessage( $singleBlock, $user, $language, $ip );
$messages[] = $this->getMessage( $singleBlock, $user, null, $ip );
}
return $messages;
@ -144,16 +146,16 @@ class BlockErrorFormatter {
* @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
UserIdentity $user
) {
$info = $this->getBlockErrorInfo( $block );
$language = $this->getLanguage();
$info['expiry'] = $language->formatExpiry( $info['expiry'], true, 'infinity', $user );
$info['timestamp'] = $language->userTimeAndDate( $info['timestamp'], $user );
$info['blockerName'] = $language->embedBidi( $info['blockerName'] );
@ -185,16 +187,17 @@ class BlockErrorFormatter {
* 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 ) {
private function formatBlockerLink( ?UserIdentity $blocker ) {
if ( !$blocker ) {
// TODO should we say something? This is just matching the code before
// the refactoring in late July 2021
return '';
}
$language = $this->getLanguage();
if ( $blocker->getId() === 0 ) {
// Foreign user
// TODO what about blocks placed by IPs? Shouldn't we check based on
@ -245,7 +248,6 @@ class BlockErrorFormatter {
*
* @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
@ -260,30 +262,26 @@ class BlockErrorFormatter {
private function getBlockErrorMessageParams(
Block $block,
UserIdentity $user,
Language $language,
string $ip
) {
$info = $this->getFormattedBlockErrorInfo( $block, $user, $language );
$info = $this->getFormattedBlockErrorInfo( $block, $user );
// Add params that are specific to the standard block errors
$info['ip'] = $ip;
$info['blockerLink'] = $this->formatBlockerLink(
$block->getBlocker(),
$language
);
$info['blockerLink'] = $this->formatBlockerLink( $block->getBlocker() );
// Display the CompositeBlock identifier as a message containing relevant block IDs
if ( $block instanceof CompositeBlock ) {
$ids = $language->commaList( array_map(
$ids = $this->getLanguage()->commaList( array_map(
static function ( $id ) {
return '#' . $id;
},
array_filter( $info['identifier'], 'is_int' )
) );
if ( $ids === '' ) {
$idsMsg = new Message( 'blockedtext-composite-no-ids', [], $language );
$idsMsg = $this->uiContext->msg( 'blockedtext-composite-no-ids', [] );
} else {
$idsMsg = new Message( 'blockedtext-composite-ids', [ $ids ], $language );
$idsMsg = $this->uiContext->msg( 'blockedtext-composite-ids', [ $ids ] );
}
$info['identifier'] = $idsMsg->plain();
}
@ -307,4 +305,5 @@ class BlockErrorFormatter {
return $params;
}
}

View file

@ -25,6 +25,7 @@ use MediaWiki\Request\WebRequest;
use MediaWiki\Session\CsrfTokenSet;
use MediaWiki\Title\Title;
use MediaWiki\User\User;
use Wikimedia\Bcp47Code\Bcp47Code;
use Wikimedia\NonSerializable\NonSerializableTrait;
/**
@ -170,6 +171,16 @@ abstract class ContextSource implements IContextSource {
return $this->getContext()->getLanguage();
}
/**
* @since 1.42
* @stable to override
* @note When overriding, keep consistent with getLanguage()!
* @return Bcp47Code
*/
public function getLanguageCode(): Bcp47Code {
return $this->getLanguage();
}
/**
* @since 1.18
* @stable to override

View file

@ -19,6 +19,7 @@
*/
use MediaWiki\Config\Config;
use MediaWiki\Language\LocalizationContext;
use MediaWiki\Output\OutputPage;
use MediaWiki\Permissions\Authority;
use MediaWiki\Request\WebRequest;
@ -61,7 +62,7 @@ use MediaWiki\User\User;
* @stable to type
* @author Happy-melon
*/
interface IContextSource extends MessageLocalizer, CsrfTokenSetProvider {
interface IContextSource extends LocalizationContext, CsrfTokenSetProvider {
/**
* @return WebRequest
@ -121,7 +122,7 @@ interface IContextSource extends MessageLocalizer, CsrfTokenSetProvider {
public function getAuthority(): Authority;
/**
* @return Language
* @inheritDoc
* @since 1.19
*/
public function getLanguage();

View file

@ -37,6 +37,7 @@ use MediaWiki\Title\Title;
use MediaWiki\User\User;
use Wikimedia\Assert\Assert;
use Wikimedia\AtEase\AtEase;
use Wikimedia\Bcp47Code\Bcp47Code;
use Wikimedia\IPUtils;
use Wikimedia\NonSerializable\NonSerializableTrait;
use Wikimedia\ScopedCallback;
@ -489,6 +490,14 @@ class RequestContext implements IContextSource, MutableContext {
return $this->lang;
}
/**
* @since 1.42
* @return Bcp47Code
*/
public function getLanguageCode() {
return $this->getLanguage();
}
/**
* @param Skin $skin
*/

View file

@ -32,6 +32,7 @@ use IContextSource;
use IDBAccessObject;
use LogPage;
use ManualLogEntry;
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\Cache\LinkBatchFactory;
use MediaWiki\CommentStore\CommentStore;
use MediaWiki\CommentStore\CommentStoreComment;
@ -447,6 +448,7 @@ class EditPage implements IEditObject {
private TempUserCreator $tempUserCreator;
private UserFactory $userFactory;
private IConnectionProvider $connectionProvider;
private BlockErrorFormatter $blockErrorFormatter;
/** @var User|null */
private $placeholderTempUser;
@ -516,6 +518,8 @@ class EditPage implements IEditObject {
$this->restrictionStore = $services->getRestrictionStore();
$this->commentStore = $services->getCommentStore();
$this->connectionProvider = $services->getConnectionProvider();
$this->blockErrorFormatter = $services->getFormatterFactory()
->getBlockErrorFormatter( $this->context );
// XXX: Restore this deprecation as soon as TwoColConflict is fixed (T305028)
// $this->deprecatePublicProperty( 'textbox2', '1.38', __CLASS__ );

View file

@ -35,26 +35,27 @@ class UserBlockedError extends ErrorPageError {
* @stable to call
* @param Block $block
* @param UserIdentity|null $user
* @param Language|null $language
* @param mixed $language Unused since 1.42
* @param string|null $ip
*/
public function __construct(
Block $block,
UserIdentity $user = null,
Language $language = null,
$language = null,
$ip = null
) {
if ( $user === null || $language === null || $ip === null ) {
$context = RequestContext::getMain();
if ( $user === null || $ip === null ) {
// If any of these are not passed in, use the global context
$context = RequestContext::getMain();
$user = $context->getUser();
$language = $context->getLanguage();
$ip = $context->getRequest()->getIP();
}
// @todo This should be passed in via the constructor
$messages = MediaWikiServices::getInstance()->getBlockErrorFormatter()
->getMessages( $block, $user, $language, $ip );
$messages = MediaWikiServices::getInstance()->getFormatterFactory()
->getBlockErrorFormatter( $context )
->getMessages( $block, $user, $ip );
if ( count( $messages ) === 1 ) {
$message = $messages[0];
} else {

View file

@ -2,7 +2,12 @@
namespace MediaWiki\Language;
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\Languages\LanguageFactory;
use MediaWiki\Status\StatusFormatter;
use MediaWiki\Title\TitleFormatter;
use MediaWiki\User\UserIdentityUtils;
use MessageCache;
use MessageLocalizer;
@ -14,16 +19,37 @@ use MessageLocalizer;
class FormatterFactory {
private MessageCache $messageCache;
private TitleFormatter $titleFormatter;
private HookContainer $hookContainer;
private UserIdentityUtils $userIdentityUtils;
private LanguageFactory $languageFactory;
/**
* @param MessageCache $messageCache
*/
public function __construct( MessageCache $messageCache ) {
public function __construct(
MessageCache $messageCache,
TitleFormatter $titleFormatter,
HookContainer $hookContainer,
UserIdentityUtils $userIdentityUtils,
LanguageFactory $languageFactory
) {
$this->messageCache = $messageCache;
$this->titleFormatter = $titleFormatter;
$this->hookContainer = $hookContainer;
$this->userIdentityUtils = $userIdentityUtils;
$this->languageFactory = $languageFactory;
}
public function getStatusFormatter( MessageLocalizer $messageLocalizer ): StatusFormatter {
return new StatusFormatter( $messageLocalizer, $this->messageCache );
}
public function getBlockErrorFormatter( LocalizationContext $context ): BlockErrorFormatter {
return new BlockErrorFormatter(
$this->titleFormatter,
$this->hookContainer,
$this->userIdentityUtils,
$this->languageFactory,
$context
);
}
}

View file

@ -0,0 +1,58 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Language;
/**
* Wrapper for injecting a LocalizationContext with lazy initialization.
*
* @since 1.42
* @ingroup Language
*/
class LazyLocalizationContext implements LocalizationContext {
/** @var callable */
private $instantiator;
private ?LocalizationContext $context = null;
/**
* @param callable $instantiator
*/
public function __construct( callable $instantiator ) {
$this->instantiator = $instantiator;
}
private function resolve(): LocalizationContext {
if ( !$this->context ) {
$this->context = ( $this->instantiator )();
}
return $this->context;
}
public function getLanguageCode() {
return $this->resolve()->getLanguageCode();
}
public function msg( $key, ...$params ) {
return $this->resolve()->msg( $key, ...$params );
}
}

View file

@ -0,0 +1,40 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace MediaWiki\Language;
use MessageLocalizer;
use Wikimedia\Bcp47Code\Bcp47Code;
/**
* Interface supporting message localization in MediaWiki
*
* @since 1.42
* @ingroup Language
*/
interface LocalizationContext extends MessageLocalizer {
/**
* Returns the target language for UI localization.
* @return Bcp47Code
*/
public function getLanguageCode();
}

View file

@ -3488,13 +3488,14 @@ class User implements Authority, UserIdentity, UserEmailContact {
$request = $this->getRequest();
$uiContext = RequestContext::getMain();
$services = MediaWikiServices::getInstance();
$this->mThisAsAuthority = new UserAuthority(
$this,
$request,
$uiContext,
MediaWikiServices::getInstance()->getPermissionManager(),
MediaWikiServices::getInstance()->getRateLimiter(),
MediaWikiServices::getInstance()->getBlockErrorFormatter()
$services->getPermissionManager(),
$services->getRateLimiter(),
$services->getFormatterFactory()->getBlockErrorFormatter( $uiContext )
);
}

View file

@ -19,6 +19,7 @@ use Wikimedia\Services\SalvageableService;
*/
class MediaWikiServicesTest extends MediaWikiIntegrationTestCase {
private $deprecatedServices = [
'BlockErrorFormatter',
'ConfigRepository',
'ConfiguredReadOnlyMode',
];

View file

@ -1,5 +1,6 @@
<?php
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\Block\CompositeBlock;
use MediaWiki\Block\DatabaseBlock;
use MediaWiki\Block\SystemBlock;
@ -13,27 +14,65 @@ use Wikimedia\Rdbms\LBFactory;
* @covers \MediaWiki\Block\BlockErrorFormatter
*/
class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
/**
* @return DerivativeContext
*/
private function getContext(): DerivativeContext {
$context = new DerivativeContext( RequestContext::getMain() );
$context->setLanguage(
$this->getServiceContainer()
->getLanguageFactory()->getLanguage( 'qqx' )
);
return $context;
}
private function getBlockErrorFormatter( IContextSource $context ): BlockErrorFormatter {
return $this->getServiceContainer()
->getFormatterFactory()->getBlockErrorFormatter( $context );
}
protected function setUp(): void {
parent::setUp();
$db = $this->createNoOpMock( IDatabase::class, [ 'getInfinity' ] );
$db = $this->createMock( IDatabase::class );
$db->method( 'getInfinity' )->willReturn( 'infinity' );
$lbFactory = $this->createMock( LBFactory::class );
$db->method( 'decodeExpiry' )->willReturnArgument( 0 );
$lb = $this->createNoOpMock(
LoadBalancer::class,
[ 'getConnectionRef', 'getConnection' ]
);
$lb->method( 'getConnectionRef' )->willReturn( $db );
$lb->method( 'getConnection' )->willReturn( $db );
$lbFactory = $this->createNoOpMock(
LBFactory::class,
[ 'getReplicaDatabase', 'getPrimaryDatabase', 'getMainLB', ]
);
$lbFactory->method( 'getReplicaDatabase' )->willReturn( $db );
$lbFactory->method( 'getPrimaryDatabase' )->willReturn( $db );
$lbFactory->method( 'getMainLB' )->willReturn( $lb );
$this->setService( 'DBLoadBalancerFactory', $lbFactory );
}
/**
* @dataProvider provideTestGetMessage
*/
public function testGetMessage( $block, $expectedKey, $expectedParams ) {
$context = new DerivativeContext( RequestContext::getMain() );
public function testGetMessage( $blockClass, $blockData, $expectedKey, $expectedParams ) {
$block = $this->makeBlock(
$blockClass,
$blockData
);
$context = $this->getContext();
$formatter = $this->getServiceContainer()->getBlockErrorFormatter();
$formatter = $this->getBlockErrorFormatter( $context );
$message = $formatter->getMessage(
$block,
$context->getUser(),
$this->getServiceContainer()->getLanguageFactory()->getLanguage( 'qqx' ),
$context->getLanguage(),
'1.2.3.4'
);
@ -45,28 +84,29 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
$timestamp = '20000101000000';
$expiry = '20010101000000';
$databaseBlock = new DatabaseBlock( [
$databaseBlock = [
'timestamp' => $timestamp,
'expiry' => $expiry,
'reason' => 'Test reason.',
] );
];
$systemBlock = new SystemBlock( [
$systemBlock = [
'timestamp' => $timestamp,
'systemBlock' => 'test',
'reason' => new Message( 'proxyblockreason' ),
] );
];
$compositeBlock = new CompositeBlock( [
$compositeBlock = [
'timestamp' => $timestamp,
'originalBlocks' => [
$databaseBlock,
$systemBlock
[ DatabaseBlock::class, $databaseBlock ],
[ SystemBlock::class, $systemBlock ]
]
] );
];
return [
'Database block' => [
DatabaseBlock::class,
$databaseBlock,
'blockedtext',
[
@ -81,11 +121,12 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
],
],
'Database block (autoblock)' => [
new DatabaseBlock( [
DatabaseBlock::class,
[
'timestamp' => $timestamp,
'expiry' => $expiry,
'auto' => true,
] ),
],
'autoblockedtext',
[
'',
@ -99,11 +140,12 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
],
],
'Database block (partial block)' => [
new DatabaseBlock( [
DatabaseBlock::class,
[
'timestamp' => $timestamp,
'expiry' => $expiry,
'sitewide' => false,
] ),
],
'blockedtext-partial',
[
'',
@ -117,6 +159,7 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
],
],
'System block (type \'test\')' => [
SystemBlock::class,
$systemBlock,
'systemblockedtext',
[
@ -131,11 +174,12 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
],
],
'System block (type \'test\') with reason parameters' => [
new SystemBlock( [
SystemBlock::class,
[
'timestamp' => $timestamp,
'systemBlock' => 'test',
'reason' => new Message( 'softblockrangesreason', [ '1.2.3.4' ] ),
] ),
],
'systemblockedtext',
[
'',
@ -149,6 +193,7 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
],
],
'Composite block (original blocks not inserted)' => [
CompositeBlock::class,
$compositeBlock,
'blockedtext-composite',
[
@ -177,7 +222,7 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
$context = RequestContext::getMain();
$formatter = $this->getServiceContainer()->getBlockErrorFormatter();
$formatter = $this->getBlockErrorFormatter( $context );
$this->assertContains(
$expected,
$formatter->getMessage(
@ -209,14 +254,18 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
/**
* @dataProvider provideTestGetMessages
*/
public function testGetMessages( $block, $expectedKeys ) {
$context = new DerivativeContext( RequestContext::getMain() );
public function testGetMessages( $blockClass, $blockData, $expectedKeys ) {
$block = $this->makeBlock(
$blockClass,
$blockData
);
$formatter = $this->getServiceContainer()->getBlockErrorFormatter();
$context = $this->getContext();
$formatter = $this->getBlockErrorFormatter( $context );
$messages = $formatter->getMessages(
$block,
$context->getUser(),
$this->getServiceContainer()->getLanguageFactory()->getLanguage( 'qqx' ),
'1.2.3.4'
);
@ -229,40 +278,57 @@ class BlockErrorFormatterTest extends MediaWikiIntegrationTestCase {
$timestamp = '20000101000000';
$expiry = '20010101000000';
$databaseBlock = new DatabaseBlock( [
$databaseBlock = [
'timestamp' => $timestamp,
'expiry' => $expiry,
'reason' => 'Test reason.',
] );
];
$systemBlock = new SystemBlock( [
$systemBlock = [
'timestamp' => $timestamp,
'systemBlock' => 'test',
'reason' => new Message( 'proxyblockreason' ),
] );
];
$compositeBlock = new CompositeBlock( [
$compositeBlock = [
'timestamp' => $timestamp,
'originalBlocks' => [
$databaseBlock,
$systemBlock
[ DatabaseBlock::class, $databaseBlock ],
[ SystemBlock::class, $systemBlock ]
]
] );
];
return [
'Database block' => [
DatabaseBlock::class,
$databaseBlock,
[ 'blockedtext' ],
],
'System block (type \'test\')' => [
SystemBlock::class,
$systemBlock,
[ 'systemblockedtext' ],
],
'Composite block (original blocks not inserted)' => [
CompositeBlock::class,
$compositeBlock,
[ 'blockedtext', 'systemblockedtext' ],
],
];
}
/**
* @param string $blockClass
* @param array $blockData
*
* @return mixed
*/
private function makeBlock( $blockClass, $blockData ) {
foreach ( $blockData['originalBlocks'] ?? [] as $key => $originalBlock ) {
$blockData['originalBlocks'][$key] = $this->makeBlock( ...$originalBlock );
}
return new $blockClass( $blockData );
}
}

View file

@ -2,6 +2,7 @@
use MediaWiki\Block\AbstractBlock;
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\Language\FormatterFactory;
use MediaWiki\Language\RawMessage;
use MediaWiki\User\UserIdentity;
@ -16,13 +17,13 @@ class UserBlockedErrorTest extends MediaWikiIntegrationTestCase {
$mockBlockErrorFormatter = $this->createMock( BlockErrorFormatter::class );
$mockBlockErrorFormatter->expects( $this->once() )
->method( 'getMessages' )
->with( $expectedBlock, $expectedUser, $expectedLanguage, $expectedIp )
->with( $expectedBlock, $expectedUser, $expectedIp )
->willReturn( $returnMessages );
$this->overrideMwServices( null, [
'BlockErrorFormatter' => static function () use ( $mockBlockErrorFormatter ) {
return $mockBlockErrorFormatter;
}
] );
$formatterFactory = $this->createNoOpMock( FormatterFactory::class, [ 'getBlockErrorFormatter' ] );
$formatterFactory->method( 'getBlockErrorFormatter' )->willReturn( $mockBlockErrorFormatter );
$this->setService( 'FormatterFactory', $formatterFactory );
}
public function testConstructionProvidedOnlyBlockParameter() {

View file

@ -23,6 +23,7 @@ namespace MediaWiki\Tests\Integration\Permissions;
use MediaWiki\Block\Block;
use MediaWiki\Block\BlockErrorFormatter;
use MediaWiki\CommentStore\CommentStoreComment;
use MediaWiki\Language\FormatterFactory;
use MediaWiki\Language\RawMessage;
use MediaWiki\Permissions\PermissionStatus;
use MediaWiki\User\UserIdentityValue;
@ -101,7 +102,10 @@ class PermissionStatusIntegrationTest extends MediaWikiIntegrationTestCase {
$blockErrorFormatter = $this->createNoOpMock( BlockErrorFormatter::class, [ 'getMessages' ] );
$blockErrorFormatter->method( 'getMessages' )->willReturn( [ new RawMessage( 'testing' ) ] );
$this->setService( 'BlockErrorFormatter', $blockErrorFormatter );
$formatterFactory = $this->createNoOpMock( FormatterFactory::class, [ 'getBlockErrorFormatter' ] );
$formatterFactory->method( 'getBlockErrorFormatter' )->willReturn( $blockErrorFormatter );
$this->setService( 'FormatterFactory', $formatterFactory );
$status = $this->makeBlockedStatus();
$block = $status->getBlock();

View file

@ -0,0 +1,45 @@
<?php
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\Language\FormatterFactory;
use MediaWiki\Languages\LanguageFactory;
use MediaWiki\Title\TitleFormatter;
use MediaWiki\User\UserIdentityUtils;
/**
* @covers MediaWiki\Language\FormatterFactory
*/
class FormatterFactoryTest extends MediaWikiUnitTestCase {
private function getFactory() {
return new FormatterFactory(
$this->createNoOpMock( MessageCache::class ),
$this->createNoOpMock( TitleFormatter::class ),
$this->createNoOpMock( HookContainer::class ),
$this->createNoOpMock( UserIdentityUtils::class ),
$this->createNoOpMock( LanguageFactory::class )
);
}
public function testGetStatusFormatter() {
$factory = $this->getFactory();
$factory->getStatusFormatter(
$this->createNoOpMock( MessageLocalizer::class )
);
// Just make sure the getter works.
// This protects against constructor signature changes.
$this->addToAssertionCount( 1 );
}
public function testGetBlockErrorFormatter() {
$factory = $this->getFactory();
$factory->getBlockErrorFormatter(
$this->createNoOpMock( IContextSource::class )
);
// Just make sure the getter works.
// This protects against constructor signature changes.
$this->addToAssertionCount( 1 );
}
}