diff options
author | TChin <tchin@wikimedia.org> | 2021-10-15 13:39:56 -0400 |
---|---|---|
committer | TChin <tchin@wikimedia.org> | 2021-11-16 11:24:35 -0500 |
commit | 349819dc5aaccafcc9d1daae7b16d48ee951942c (patch) | |
tree | b1a8a9c74a6ba79a210d4fcc4013982cb920af0a | |
parent | 80d3ece54a8b4085910716246977885db87c5188 (diff) | |
download | mediawikicore-349819dc5aaccafcc9d1daae7b16d48ee951942c.tar.gz mediawikicore-349819dc5aaccafcc9d1daae7b16d48ee951942c.zip |
Add Message/MessageValue user group member parameter type
* Added ParamType::OBJECT, which allows Stringable objects to be passed into MessageValue
Bug: T278482
Change-Id: Ib4990f87d4ad70b7525d7aa05c8b97e90c121674
-rw-r--r-- | includes/Message/UserGroupMembershipParam.php | 52 | ||||
-rw-r--r-- | includes/language/Language.php | 21 | ||||
-rw-r--r-- | includes/language/Message.php | 42 | ||||
-rw-r--r-- | includes/libs/Message/MessageValue.php | 15 | ||||
-rw-r--r-- | includes/libs/Message/ParamType.php | 9 | ||||
-rw-r--r-- | includes/libs/Message/ScalarParam.php | 9 | ||||
-rw-r--r-- | includes/user/UserGroupMembership.php | 8 | ||||
-rw-r--r-- | tests/phpunit/includes/Message/TextFormatterTest.php | 9 | ||||
-rw-r--r-- | tests/phpunit/includes/MessageTest.php | 19 | ||||
-rw-r--r-- | tests/phpunit/languages/LanguageIntegrationTest.php | 24 | ||||
-rw-r--r-- | tests/phpunit/unit/includes/libs/Message/MessageValueTest.php | 14 |
11 files changed, 211 insertions, 11 deletions
diff --git a/includes/Message/UserGroupMembershipParam.php b/includes/Message/UserGroupMembershipParam.php new file mode 100644 index 000000000000..c6e2e55baef8 --- /dev/null +++ b/includes/Message/UserGroupMembershipParam.php @@ -0,0 +1,52 @@ +<?php + +/** + * Represents a Message/MessageValue parameter user group membership to be used with ParamType::OBJECT. + * + * 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\Message; + +use MediaWiki\User\UserIdentity; +use Stringable; + +class UserGroupMembershipParam implements Stringable { + /** @var string */ + private $group; + + /** @var UserIdentity */ + private $member; + + public function __construct( string $group, UserIdentity $member ) { + $this->group = $group; + $this->member = $member; + } + + public function getGroup(): string { + return $this->group; + } + + public function getMember(): UserIdentity { + return $this->member; + } + + public function __toString() { + return $this->group . ':' . $this->member->getName(); + } +} diff --git a/includes/language/Language.php b/includes/language/Language.php index 804b3e2afe5b..f27585cdb594 100644 --- a/includes/language/Language.php +++ b/includes/language/Language.php @@ -899,10 +899,11 @@ class Language { * Get message object in this language. Only for use inside this class. * * @param string $msg Message name + * @param mixed ...$params Message parameters * @return Message */ - protected function msg( $msg ) { - return wfMessage( $msg )->inLanguage( $this ); + protected function msg( $msg, ...$params ) { + return wfMessage( $msg, ...$params )->inLanguage( $this ); } /** @@ -2616,6 +2617,22 @@ class Language { } /** + * Gets the localized name for a member of a group, if it exists. For example, + * "administrator" or "bureaucrat" + * + * @param string $group Internal group name + * @param string|UserIdentity $member + * @return string Localized name for group member + */ + public function getGroupMemberName( string $group, $member ) { + if ( $member instanceof UserIdentity ) { + $member = $member->getName(); + } + $msg = $this->msg( "group-$group-member", $member ); + return $msg->isBlank() ? $group : $msg->text(); + } + + /** * @param string $key * @return string|null */ diff --git a/includes/language/Message.php b/includes/language/Message.php index f4af7636aab5..2b266d6923a9 100644 --- a/includes/language/Message.php +++ b/includes/language/Message.php @@ -21,6 +21,7 @@ use MediaWiki\Logger\LoggerFactory; use MediaWiki\MediaWikiServices; +use MediaWiki\Message\UserGroupMembershipParam; use MediaWiki\Page\PageReference; use MediaWiki\Page\PageReferenceValue; @@ -650,6 +651,26 @@ class Message implements MessageSpecifier, Serializable { } /** + * Add parameters that represent stringable objects + * + * @since 1.38 + * + * @param Stringable|Stringable[] ...$params stringable parameters, + * or a single argument that is an array of stringable parameters. + * + * @return Message $this + */ + public function objectParams( ...$params ) { + if ( isset( $params[0] ) && is_array( $params[0] ) ) { + $params = $params[0]; + } + foreach ( $params as $param ) { + $this->parameters[] = self::objectParam( $param ); + } + return $this; + } + + /** * Add parameters that are times and will be passed through * Language::time before substitution * @@ -1174,6 +1195,17 @@ class Message implements MessageSpecifier, Serializable { } /** + * @since 1.38 + * + * @param Stringable $object + * + * @return Stringable[] Array with a single "object" key. + */ + public static function objectParam( Stringable $object ) { + return [ 'object' => $object ]; + } + + /** * @since 1.22 * * @param int $period @@ -1311,6 +1343,16 @@ class Message implements MessageSpecifier, Serializable { return [ 'after', $this->formatPlaintext( $param['plaintext'], $format ) ]; } elseif ( isset( $param['list'] ) ) { return $this->formatListParam( $param['list'], $param['type'], $format ); + } elseif ( isset( $param['object'] ) ) { + $obj = $param['object']; + if ( $obj instanceof UserGroupMembershipParam ) { + return [ + 'before', + $this->getLanguage()->getGroupMemberName( $obj->getGroup(), $obj->getMember() ) + ]; + } else { + return [ 'before', $obj->__toString() ]; + } } else { LoggerFactory::getInstance( 'Bug58676' )->warning( 'Invalid parameter for message "{msgkey}": {param}', diff --git a/includes/libs/Message/MessageValue.php b/includes/libs/Message/MessageValue.php index 4abfe6919f4c..3af73e460223 100644 --- a/includes/libs/Message/MessageValue.php +++ b/includes/libs/Message/MessageValue.php @@ -2,6 +2,8 @@ namespace Wikimedia\Message; +use Stringable; + /** * Value object representing a message for i18n. * @@ -93,6 +95,19 @@ class MessageValue { } /** + * Chainable mutator which adds object parameters + * + * @param Stringable ...$values stringable object values + * @return $this + */ + public function objectParams( ...$values ) { + foreach ( $values as $value ) { + $this->params[] = new ScalarParam( ParamType::OBJECT, $value ); + } + return $this; + } + + /** * Chainable mutator which adds list parameters with a common type * * @param string $listType One of the ListType constants diff --git a/includes/libs/Message/ParamType.php b/includes/libs/Message/ParamType.php index 8287a7079315..100adb70d9f8 100644 --- a/includes/libs/Message/ParamType.php +++ b/includes/libs/Message/ParamType.php @@ -60,12 +60,17 @@ class ParamType { public const TIME = 'time'; /** - * @since 1.38 - * * User Group + * @since 1.38 */ public const GROUP = 'group'; + /** + * For arbitrary stringable objects + * @since 1.38 + */ + public const OBJECT = 'object'; + /** A number of bytes. The output will be rounded to an appropriate magnitude. */ public const SIZE = 'size'; diff --git a/includes/libs/Message/ScalarParam.php b/includes/libs/Message/ScalarParam.php index e28166757676..9e9c68fbcf13 100644 --- a/includes/libs/Message/ScalarParam.php +++ b/includes/libs/Message/ScalarParam.php @@ -2,6 +2,8 @@ namespace Wikimedia\Message; +use Stringable; + /** * Value object representing a message parameter holding a single value. * @@ -16,7 +18,7 @@ class ScalarParam extends MessageParam { * @stable to call. * * @param string $type One of the ParamType constants. - * @param string|int|float|MessageValue $value + * @param string|int|float|MessageValue|Stringable $value */ public function __construct( $type, $value ) { if ( $type === ParamType::LIST ) { @@ -24,7 +26,8 @@ class ScalarParam extends MessageParam { 'ParamType::LIST cannot be used with ScalarParam; use ListParam instead' ); } - if ( !is_string( $value ) && !is_numeric( $value ) && !$value instanceof MessageValue ) { + if ( !is_string( $value ) && !is_numeric( $value ) && + !$value instanceof MessageValue && !$value instanceof Stringable ) { $type = is_object( $value ) ? get_class( $value ) : gettype( $value ); throw new \InvalidArgumentException( "Scalar parameter must be a string, number, or MessageValue; got $type" @@ -39,7 +42,7 @@ class ScalarParam extends MessageParam { if ( $this->value instanceof MessageValue ) { $contents = $this->value->dump(); } else { - $contents = htmlspecialchars( $this->value ); + $contents = htmlspecialchars( (string)$this->value ); } return "<{$this->type}>" . $contents . "</{$this->type}>"; } diff --git a/includes/user/UserGroupMembership.php b/includes/user/UserGroupMembership.php index 51adae89070a..57e25f9dbb2d 100644 --- a/includes/user/UserGroupMembership.php +++ b/includes/user/UserGroupMembership.php @@ -21,6 +21,7 @@ */ use MediaWiki\MediaWikiServices; +use MediaWiki\User\UserIdentity; /** * Represents a "user group membership" -- a specific instance of a user belonging @@ -175,12 +176,11 @@ class UserGroupMembership { * "administrator" or "bureaucrat" * * @param string $group Internal group name - * @param string $username Username for gender + * @param string|UserIdentity $member Username or UserIdentity of member for gender * @return string Localized name for group member */ - public static function getGroupMemberName( $group, $username ) { - $msg = wfMessage( "group-$group-member", $username ); - return $msg->isBlank() ? $group : $msg->text(); + public static function getGroupMemberName( $group, $member ) { + return RequestContext::getMain()->getLanguage()->getGroupMemberName( $group, $member ); } /** diff --git a/tests/phpunit/includes/Message/TextFormatterTest.php b/tests/phpunit/includes/Message/TextFormatterTest.php index 3f439e5e65d4..ccc27cffc4af 100644 --- a/tests/phpunit/includes/Message/TextFormatterTest.php +++ b/tests/phpunit/includes/Message/TextFormatterTest.php @@ -4,6 +4,8 @@ namespace MediaWiki\Tests\Message; use MediaWiki\Message\Converter; use MediaWiki\Message\TextFormatter; +use MediaWiki\Message\UserGroupMembershipParam; +use MediaWiki\User\UserIdentityValue; use MediaWikiIntegrationTestCase; use Message; use Wikimedia\Message\MessageValue; @@ -92,6 +94,13 @@ class TextFormatterTest extends MediaWikiIntegrationTestCase { ->userGroupParams( 'bot' ), 'test (group-bot) $2' ]; + + yield [ ( new MessageValue( 'test' ) ) + ->objectParams( + new UserGroupMembershipParam( 'bot', new UserIdentityValue( 1, 'user' ) ) + ), + 'test (group-bot-member: user) $2' + ]; } /** diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php index 13150cc0ece8..9f758b0d764b 100644 --- a/tests/phpunit/includes/MessageTest.php +++ b/tests/phpunit/includes/MessageTest.php @@ -1,8 +1,10 @@ <?php use MediaWiki\MediaWikiServices; +use MediaWiki\Message\UserGroupMembershipParam; use MediaWiki\Page\PageReference; use MediaWiki\Page\PageReferenceValue; +use MediaWiki\User\UserIdentityValue; use Wikimedia\TestingAccessWrapper; /** @@ -552,6 +554,23 @@ class MessageTest extends MediaWikiLangTestCase { } /** + * @covers Message::objectParam + * @covers Message::objectParams + */ + public function testUserGroupMemberParams() { + $lang = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( 'qqx' ); + $msg = new RawMessage( '$1' ); + $this->setUserLang( $lang ); + $this->assertSame( + '(group-bot-member: user)', + $msg->objectParams( + new UserGroupMembershipParam( 'bot', new UserIdentityValue( 1, 'user' ) ) + )->plain(), + 'user group member is handled correctly' + ); + } + + /** * @covers Message::timeperiodParam * @covers Message::timeperiodParams */ diff --git a/tests/phpunit/languages/LanguageIntegrationTest.php b/tests/phpunit/languages/LanguageIntegrationTest.php index 540537352f71..8c0eefbb2230 100644 --- a/tests/phpunit/languages/LanguageIntegrationTest.php +++ b/tests/phpunit/languages/LanguageIntegrationTest.php @@ -6,6 +6,8 @@ use MediaWiki\Languages\LanguageConverterFactory; use MediaWiki\Languages\LanguageFallback; use MediaWiki\Languages\LanguageNameUtils; use MediaWiki\MediaWikiServices; +use MediaWiki\User\UserIdentityValue; +use Wikimedia\TestingAccessWrapper; /** * @group Language @@ -2200,4 +2202,26 @@ class LanguageIntegrationTest extends LanguageClassesTestCase { $this->assertSame( 'Bots', $groupName ); } + /** + * @covers Language::getGroupMemberName + */ + public function testGetGroupMemberName() { + $lang = $this->getLang(); + $user = new UserIdentityValue( 1, 'user' ); + $groupMemberName = $lang->getGroupMemberName( 'bot', $user ); + $this->assertSame( 'bot', $groupMemberName ); + + $lang = $this->getServiceContainer()->getLanguageFactory()->getLanguage( 'qqx' ); + $groupMemberName = $lang->getGroupMemberName( 'bot', $user ); + $this->assertSame( '(group-bot-member: user)', $groupMemberName ); + } + + /** + * @covers Language::msg + */ + public function testMsg() { + $lang = TestingAccessWrapper::newFromObject( $this->getLang() ); + $this->assertSame( 'December 1', $lang->msg( 'december-date', '1' )->text() ); + } + } diff --git a/tests/phpunit/unit/includes/libs/Message/MessageValueTest.php b/tests/phpunit/unit/includes/libs/Message/MessageValueTest.php index 9b553a593d44..363fae2e49ba 100644 --- a/tests/phpunit/unit/includes/libs/Message/MessageValueTest.php +++ b/tests/phpunit/unit/includes/libs/Message/MessageValueTest.php @@ -2,6 +2,8 @@ namespace Wikimedia\Tests\Message; +use MediaWiki\Message\UserGroupMembershipParam; +use MediaWiki\User\UserIdentityValue; use Wikimedia\Message\ListType; use Wikimedia\Message\MessageValue; use Wikimedia\Message\ParamType; @@ -183,6 +185,18 @@ class MessageValueTest extends \PHPUnit\Framework\TestCase { $this->assertSame( $mv, $mv2 ); } + public function testUserGroupMemberParams() { + $mv = new MessageValue( 'key' ); + $mv2 = $mv->objectParams( + new UserGroupMembershipParam( 'bot', new UserIdentityValue( 1, 'user' ) ) + ); + $this->assertSame( '<message key="key">' . + '<object>bot:user</object>' . + '</message>', + $mv->dump() ); + $this->assertSame( $mv, $mv2 ); + } + public function testSizeParams() { $mv = new MessageValue( 'key' ); $mv2 = $mv->sizeParams( 1, 2 ); |