UserNameUtils: use ITextFormatter instead of MessageLocalizer

Bug: T249045
Change-Id: Ica1e1e4788d4b9f9dfcf9f8c8b4136147d92b32e
This commit is contained in:
Petr Pchelko 2020-03-31 16:29:51 -07:00
parent f00d265611
commit 7f643f2ab6
7 changed files with 109 additions and 40 deletions

View file

@ -2,6 +2,7 @@
namespace MediaWiki\Message;
use Message;
use Wikimedia\Message\IMessageFormatterFactory;
use Wikimedia\Message\ITextFormatter;
@ -9,20 +10,31 @@ use Wikimedia\Message\ITextFormatter;
* The MediaWiki-specific implementation of IMessageFormatterFactory
*/
class MessageFormatterFactory implements IMessageFormatterFactory {
/** @var string */
private $format;
/** @var array */
private $textFormatters = [];
/**
* Required parameters may be added to this function without deprecation.
* External callers should use MediaWikiServices::getMessageFormatterFactory().
*
* @param string $format which if the Message::FORMAT_* to use in the formatters.
* @internal
*/
public function __construct() {
public function __construct( string $format = Message::FORMAT_TEXT ) {
$this->format = $format;
}
/**
* @inheritDoc
*/
public function getTextFormatter( $langCode ): ITextFormatter {
if ( !isset( $this->textFormatters[$langCode] ) ) {
$this->textFormatters[$langCode] = new TextFormatter( $langCode, new Converter() );
$this->textFormatters[$langCode] = new TextFormatter(
$langCode, new Converter(), $this->format );
}
return $this->textFormatters[$langCode];
}

View file

@ -2,6 +2,7 @@
namespace MediaWiki\Message;
use Message;
use Wikimedia\Message\ITextFormatter;
use Wikimedia\Message\MessageValue;
@ -15,6 +16,9 @@ class TextFormatter implements ITextFormatter {
/** @var string */
private $langCode;
/** @var string */
private $format;
/**
* Construct a TextFormatter.
*
@ -25,10 +29,16 @@ class TextFormatter implements ITextFormatter {
* @internal
* @param string $langCode
* @param Converter $converter
* @param string $format
*/
public function __construct( $langCode, Converter $converter ) {
public function __construct(
string $langCode,
Converter $converter,
string $format = Message::FORMAT_TEXT
) {
$this->langCode = $langCode;
$this->converter = $converter;
$this->format = $format;
}
public function getLangCode() {
@ -38,6 +48,6 @@ class TextFormatter implements ITextFormatter {
public function format( MessageValue $mv ) {
$message = $this->converter->convertMessageValue( $mv );
$message->inLanguage( $this->langCode );
return $message->text();
return $message->toString( $this->format );
}
}

View file

@ -1068,7 +1068,7 @@ return [
},
'UserNameUtils' => function ( MediaWikiServices $services ) : UserNameUtils {
// TODO there should be a proper injectable MessageLocalizer service (T247127)
$messageFormatterFactory = new MessageFormatterFactory( Message::FORMAT_PLAIN );
return new UserNameUtils(
new ServiceOptions(
UserNameUtils::CONSTRUCTOR_OPTIONS, $services->getMainConfig()
@ -1076,7 +1076,9 @@ return [
$services->getContentLanguage(),
LoggerFactory::getInstance( 'UserNameUtils' ),
$services->getService( 'TitleFactory' ),
RequestContext::getMain()
$messageFormatterFactory->getTextFormatter(
$services->getContentLanguage()->getCode()
)
);
},

View file

@ -26,10 +26,11 @@ use Hooks;
use InvalidArgumentException;
use Language;
use MediaWiki\Config\ServiceOptions;
use MessageLocalizer;
use Psr\Log\LoggerInterface;
use TitleFactory;
use Wikimedia\IPUtils;
use Wikimedia\Message\ITextFormatter;
use Wikimedia\Message\MessageValue;
/**
* UserNameUtils service
@ -70,9 +71,9 @@ class UserNameUtils {
private $titleFactory;
/**
* @var MessageLocalizer
* @var ITextFormatter
*/
private $msgLocalizer;
private $textFormatter;
/**
* @var string[]|false Cache for isUsable()
@ -84,21 +85,21 @@ class UserNameUtils {
* @param Language $contentLang
* @param LoggerInterface $logger
* @param TitleFactory $titleFactory
* @param MessageLocalizer $msgLocalizer
* @param ITextFormatter $textFormatter the text formatter for the current content language
*/
public function __construct(
ServiceOptions $options,
Language $contentLang,
LoggerInterface $logger,
TitleFactory $titleFactory,
MessageLocalizer $msgLocalizer
ITextFormatter $textFormatter
) {
$options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
$this->options = $options;
$this->contentLang = $contentLang;
$this->logger = $logger;
$this->titleFactory = $titleFactory;
$this->msgLocalizer = $msgLocalizer;
$this->textFormatter = $textFormatter;
}
/**
@ -175,10 +176,9 @@ class UserNameUtils {
// Certain names may be reserved for batch processes.
foreach ( $this->reservedUsernames as $reserved ) {
if ( substr( $reserved, 0, 4 ) === 'msg:' ) {
// FIXME fix $this->msgLocalizer to be able to use it
$reserved = wfMessage( substr( $reserved, 4 ) )
->inContentLanguage()
->plain();
$reserved = $this->textFormatter->format(
MessageValue::new( substr( $reserved, 4 ) )
);
}
if ( $reserved === $name ) {
return false;

View file

@ -18,27 +18,34 @@ use Wikimedia\Message\ScalarParam;
* @covers \Wikimedia\Message\MessageParam
*/
class TextFormatterTest extends MediaWikiTestCase {
private function createTextFormatter( $langCode ) {
private function createTextFormatter( $langCode,
$includeWikitext = false,
$format = Message::FORMAT_TEXT
) {
$converter = $this->getMockBuilder( Converter::class )
->setMethods( [ 'createMessage' ] )
->getMock();
$converter->method( 'createMessage' )
->willReturnCallback( function ( $key ) {
->willReturnCallback( function ( $key ) use ( $includeWikitext ) {
$message = $this->getMockBuilder( Message::class )
->setConstructorArgs( [ $key ] )
->setMethods( [ 'fetchMessage' ] )
->getMock();
$message->method( 'fetchMessage' )
->willReturnCallback( function () use ( $message ) {
->willReturnCallback( function () use ( $message, $includeWikitext ) {
/** @var Message $message */
return "{$message->getKey()} $1 $2";
$result = "{$message->getKey()} $1 $2";
if ( $includeWikitext ) {
$result .= " {{SITENAME}}";
}
return $result;
} );
return $message;
} );
return new TextFormatter( $langCode, $converter );
return new TextFormatter( $langCode, $converter, $format );
}
public function testGetLangCode() {
@ -82,4 +89,19 @@ class TextFormatterTest extends MediaWikiTestCase {
$result = $formatter->format( $mv );
$this->assertSame( 'test test2 a b x, 100 bps, test3 c test4 d e', $result );
}
public function testFormatMessageFormatsWikitext() {
global $wgSitename;
$formatter = $this->createTextFormatter( 'en', true );
$mv = MessageValue::new( 'test' )
->plaintextParams( '1', '2' );
$this->assertSame( "test 1 2 $wgSitename", $formatter->format( $mv ) );
}
public function testFormatMessageNotWikitext() {
$formatter = $this->createTextFormatter( 'en', true, Message::FORMAT_PLAIN );
$mv = MessageValue::new( 'test' )
->plaintextParams( '1', '2' );
$this->assertSame( "test 1 2 {{SITENAME}}", $formatter->format( $mv ) );
}
}

View file

@ -5,6 +5,8 @@ use MediaWiki\User\UserNameUtils;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
use Wikimedia\Message\ITextFormatter;
use Wikimedia\Message\MessageValue;
/**
* @covers MediaWiki\User\UserNameUtils
@ -28,7 +30,7 @@ class UserNameUtilsTest extends MediaWikiTestCase {
array $options = [],
Language $contentLang = null,
LoggerInterface $logger = null,
MessageLocalizer $msgLocalizer = null
ITextFormatter $textFormatter = null
) {
$baseOptions = [
'MaxNameChars' => 255,
@ -52,8 +54,8 @@ class UserNameUtilsTest extends MediaWikiTestCase {
// one. Once its possible to mock, this should be converted to a unit test.
$titleFactory = new TitleFactory();
if ( $msgLocalizer === null ) {
$msgLocalizer = $this->createMock( MessageLocalizer::class );
if ( $textFormatter === null ) {
$textFormatter = $this->getMockForAbstractClass( ITextFormatter::class );
}
$utils = new UserNameUtils(
@ -61,7 +63,7 @@ class UserNameUtilsTest extends MediaWikiTestCase {
$contentLang,
$logger,
$titleFactory,
$msgLocalizer
$textFormatter
);
return $utils;
}
@ -110,22 +112,11 @@ class UserNameUtilsTest extends MediaWikiTestCase {
* @covers MediaWiki\User\UserNameUtils::isUsable
*/
public function testIsUsable( string $name, bool $result ) {
$msg = $this->getMockBuilder( Message::class )
->setMethods( [ 'inContentLanguage', 'plain' ] )
->disableOriginalConstructor()
->getMock();
$msg->method( 'inContentLanguage' )
->will( $this->returnSelf() );
$msg->method( 'plain' )
$textFormatter = $this->getMockForAbstractClass( ITextFormatter::class );
$textFormatter->method( 'format' )
->with( $this->equalTo( MessageValue::new( 'reserved-user' ) ) )
->willReturn( 'reserved-user' );
$msgLocalizer = $this->getMockBuilder( MessageLocalizer::class )
->setMethods( [ 'msg' ] )
->getMock();
$msgLocalizer->method( 'msg' )
->with( $this->equalTo( 'reserved-user' ) )
->willReturn( $msg );
$utils = $this->getUtils(
[
'ReservedUsernames' => [
@ -135,7 +126,7 @@ class UserNameUtilsTest extends MediaWikiTestCase {
],
$this->getUCFirstLanguageMock(),
null,
$msgLocalizer
$textFormatter
);
$this->assertSame(
$result,

View file

@ -0,0 +1,32 @@
<?php
use MediaWiki\Message\MessageFormatterFactory;
/**
* @covers \MediaWiki\Message\MessageFormatterFactory
*/
class MessageFormatterFactoryTest extends MediaWikiUnitTestCase {
use MediaWikiCoversValidator;
public function provideGetTextFormatter() {
yield [ 'en', null ];
yield [ 'en', Message::FORMAT_TEXT ];
yield [ 'ru', Message::FORMAT_PLAIN ];
}
/**
* @covers \MediaWiki\Message\MessageFormatterFactory::getTextFormatter
* @dataProvider provideGetTextFormatter
* @param string $lang
* @param string|null $format
*/
public function testGetTextFormatter( string $lang, string $format = null ) {
if ( $format ) {
$factory = new MessageFormatterFactory( $format );
} else {
$factory = new MessageFormatterFactory();
}
$formatter = $factory->getTextFormatter( $lang );
$this->assertSame( $lang, $formatter->getLangCode() );
}
}