aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTChin <tchin@wikimedia.org>2021-10-15 13:39:56 -0400
committerTChin <tchin@wikimedia.org>2021-11-16 11:24:35 -0500
commit349819dc5aaccafcc9d1daae7b16d48ee951942c (patch)
treeb1a8a9c74a6ba79a210d4fcc4013982cb920af0a
parent80d3ece54a8b4085910716246977885db87c5188 (diff)
downloadmediawikicore-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.php52
-rw-r--r--includes/language/Language.php21
-rw-r--r--includes/language/Message.php42
-rw-r--r--includes/libs/Message/MessageValue.php15
-rw-r--r--includes/libs/Message/ParamType.php9
-rw-r--r--includes/libs/Message/ScalarParam.php9
-rw-r--r--includes/user/UserGroupMembership.php8
-rw-r--r--tests/phpunit/includes/Message/TextFormatterTest.php9
-rw-r--r--tests/phpunit/includes/MessageTest.php19
-rw-r--r--tests/phpunit/languages/LanguageIntegrationTest.php24
-rw-r--r--tests/phpunit/unit/includes/libs/Message/MessageValueTest.php14
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 );