wiki.techinc.nl/includes/htmlform/fields/HTMLUsersMultiselectField.php
Umherirrender 782828c106 htmlform: Improve validation of multiselect fields
- Run the 'max' check always, even 'exists' option is set to false, let
  the parent class decide if exists validation is needed (for namespace
  type this is just moved, parent does not support that setting)
- Validate given namespace to be numeric and cast the value,
  on new php the meaning of the condition ´'text' < 0´ changed
  (https://wiki.php.net/rfc/string_to_number_comparison)
- Pass the max value as formatted number to the message
- Return message as object, allows the html builder to choose the
  correct format to display
- Make 'required' to work on namespace type and title multiselect type
- Combine multiple errors from each validation step and show as bullet
  point list, if multiple errors exists
  (not for namespace type, there are no nice messages to show)

Change-Id: I1f6df50277e6911b2f0ac36fdbd071407437fc78
2023-01-29 20:01:48 +00:00

159 lines
4.6 KiB
PHP

<?php
use MediaWiki\Language\RawMessage;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\UserRigorOptions;
use MediaWiki\Widget\UsersMultiselectWidget;
use Wikimedia\IPUtils;
/**
* Implements a tag multiselect input field for user names.
*
* Besides the parameters recognized by HTMLUserTextField, additional recognized
* parameters are:
* default - (optional) Array of usernames to use as preset data
* placeholder - (optional) Custom placeholder message for input
*
* The result is the array of usernames
*
* @stable to extend
* @note This widget is not likely to remain functional in non-OOUI forms.
*/
class HTMLUsersMultiselectField extends HTMLUserTextField {
public function loadDataFromRequest( $request ) {
$value = $request->getText( $this->mName, $this->getDefault() );
$usersArray = explode( "\n", $value );
// Remove empty lines
$usersArray = array_values( array_filter( $usersArray, static function ( $username ) {
return trim( $username ) !== '';
} ) );
// Normalize usernames
$normalizedUsers = [];
$userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
$listOfIps = [];
foreach ( $usersArray as $user ) {
$canonicalUser = false;
if ( IPUtils::isIPAddress( $user ) ) {
$parsedIPRange = IPUtils::parseRange( $user );
if ( !in_array( $parsedIPRange, $listOfIps ) ) {
$canonicalUser = IPUtils::sanitizeRange( $user );
$listOfIps[] = $parsedIPRange;
}
} else {
$canonicalUser = $userNameUtils->getCanonical(
$user, UserRigorOptions::RIGOR_NONE );
}
if ( $canonicalUser !== false ) {
$normalizedUsers[] = $canonicalUser;
}
}
// Remove any duplicate usernames
$uniqueUsers = array_unique( $normalizedUsers );
// This function is expected to return a string
return implode( "\n", $uniqueUsers );
}
public function validate( $value, $alldata ) {
if ( $value === null ) {
return false;
}
// $value is a string, because HTMLForm fields store their values as strings
$usersArray = explode( "\n", $value );
if ( isset( $this->mParams['max'] ) && count( $usersArray ) > $this->mParams['max'] ) {
return $this->msg( 'htmlform-multiselect-toomany' )->numParams( $this->mParams['max'] );
}
$resultArray = [];
foreach ( $usersArray as $username ) {
$result = parent::validate( $username, $alldata );
if ( $result !== true ) {
if ( $result === false ) {
// Nothing to display, no further validation needed
return $result;
}
$resultArray[] = $result;
}
}
if ( $resultArray !== [] ) {
if ( count( $resultArray ) === 1 ) {
return reset( $resultArray );
}
// Show error as bullet point list
$key = '* $' . implode( "\n* $", range( 1, count( $resultArray ) ) );
return ( new RawMessage( $key ) )->params( $resultArray );
}
return true;
}
public function getInputHTML( $value ) {
$this->mParent->getOutput()->enableOOUI();
return $this->getInputOOUI( $value );
}
public function getInputOOUI( $value ) {
$params = [ 'name' => $this->mName ];
if ( isset( $this->mParams['id'] ) ) {
$params['id'] = $this->mParams['id'];
}
if ( isset( $this->mParams['disabled'] ) ) {
$params['disabled'] = $this->mParams['disabled'];
}
if ( isset( $this->mParams['default'] ) ) {
$params['default'] = $this->mParams['default'];
}
$params['placeholder'] = $this->mParams['placeholder'] ??
$this->msg( 'mw-widgets-usersmultiselect-placeholder' )->plain();
if ( isset( $this->mParams['max'] ) ) {
$params['tagLimit'] = $this->mParams['max'];
}
if ( isset( $this->mParams['ipallowed'] ) ) {
$params['ipAllowed'] = $this->mParams['ipallowed'];
}
if ( isset( $this->mParams['iprange'] ) ) {
$params['ipRangeAllowed'] = $this->mParams['iprange'];
}
if ( isset( $this->mParams['iprangelimits'] ) ) {
$params['ipRangeLimits'] = $this->mParams['iprangelimits'];
}
if ( isset( $this->mParams['input'] ) ) {
$params['input'] = $this->mParams['input'];
}
if ( $value !== null ) {
// $value is a string, but the widget expects an array
$params['default'] = $value === '' ? [] : explode( "\n", $value );
}
// Make the field auto-infusable when it's used inside a legacy HTMLForm rather than OOUIHTMLForm
$params['infusable'] = true;
$params['classes'] = [ 'mw-htmlform-autoinfuse' ];
$widget = new UsersMultiselectWidget( $params );
$widget->setAttributes( [ 'data-mw-modules' => implode( ',', $this->getOOUIModules() ) ] );
return $widget;
}
protected function shouldInfuseOOUI() {
return true;
}
protected function getOOUIModules() {
return [ 'mediawiki.widgets.UsersMultiselectWidget' ];
}
}