wiki.techinc.nl/includes/htmlform/fields/HTMLTitleTextField.php
Gergő Tisza 16f3b8c4c0 Make HTMLTitleTextField interwiki option tri-state
Make the 'interwiki' option temporarily accept null as well as true/false
(and default to null instead of false) so form fields which disallow
interwiki titles can avoid deprecation warnings. This also includes
implementing the new error message.

The idea is that for the duration of the deprecation process, form fields
can be set explicitly to interwiki => false (which will eventually become
the default). It would be super annoying to have to do this for all
title fields, but this way it's only needed for fields where users actually
submit interwiki titles with some frequency.

Also improve the logic for legacy fields (which do not set the option
either way): since these (while emitting a warning) allow an interwiki
title, it does not make sense to apply namespace etc. checks to that
title.

Bug: T288155
Change-Id: Ic00f4a0f27747b5ff0893b4c01f42f68a99771ab
2021-08-04 21:24:16 -07:00

143 lines
5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use MediaWiki\Widget\TitleInputWidget;
/**
* Implements a text input field for page titles.
* Automatically does validation that the title is valid,
* as well as autocompletion if using the OOUI display format.
*
* Optional parameters:
* 'namespace' - Namespace the page must be in (use namespace constant; one of the NS_* constants may be used)
* 'relative' - If true and 'namespace' given, strip/add the namespace from/to the title as needed
* 'creatable' - Whether to validate the title is creatable (not a special page)
* 'exists' - Whether to validate that the title already exists
* 'interwiki' Tolerate interwiki links (other conditions such as 'namespace' or 'exists' will be
* ignored if the title is an interwiki title). Cannot be used together with 'relative'.
*
* @stable to extend
* @since 1.26
*/
class HTMLTitleTextField extends HTMLTextField {
/**
* @stable to call
* @inheritDoc
*/
public function __construct( $params ) {
$params += [
'namespace' => false,
'relative' => false,
'creatable' => false,
'exists' => false,
// Default to null during the deprecation process so we can differentiate between
// callers who intentionally want to disallow interwiki titles and legacy callers
// who aren't aware of the setting.
'interwiki' => null,
// This overrides the default from HTMLFormField
'required' => true,
];
parent::__construct( $params );
}
public function validate( $value, $alldata ) {
if ( $this->mParams['interwiki'] && $this->mParams['relative'] ) {
// relative and interwiki cannot be used together, because we don't have a way to know about
// namespaces used by the other wiki (and it might actually be a non-wiki link, too).
throw new InvalidArgumentException( 'relative and interwiki may not be used together' );
}
// Default value (from getDefault()) is null, which breaks Title::newFromTextThrow() below
if ( $value === null ) {
$value = '';
}
if ( !$this->mParams['required'] && $value === '' ) {
// If this field is not required and the value is empty, that's okay, skip validation
return parent::validate( $value, $alldata );
}
try {
if ( !$this->mParams['relative'] ) {
$title = Title::newFromTextThrow( $value );
} else {
// Can't use Title::makeTitleSafe(), because it doesn't throw useful exceptions
$title = Title::newFromTextThrow( Title::makeName( $this->mParams['namespace'], $value ) );
}
} catch ( MalformedTitleException $e ) {
return $this->msg( $e->getErrorMessage(), $e->getErrorMessageParameters() );
}
if ( $title->isExternal() ) {
if ( $this->mParams['interwiki'] ) {
// We cannot validate external titles, skip the rest of the validation
return parent::validate( $value, $alldata );
} elseif ( $this->mParams['interwiki'] === null ) {
// Legacy caller, they probably don't need/want interwiki titles as those don't
// make sense in most use cases. To avoid a B/C break without deprecation, though,
// we let the title through and raise a warning. That way, code that needs to allow
// interwiki titles will get deprecation warnings as long as users actually submit
// interwiki titles to the form. That's not ideal but a less conditional warning
// would be impractical - having to update every title field in the world to avoid
// warnings would be too much of a burden.
wfDeprecated(
__METHOD__ . ' will reject external titles in 1.38 when interwiki is false '
. "(field: $this->mName)",
'1.37'
);
return parent::validate( $value, $alldata );
} else {
return $this->msg( 'htmlform-title-interwiki', $title->getPrefixedText() );
}
}
$text = $title->getPrefixedText();
if ( $this->mParams['namespace'] !== false &&
!$title->inNamespace( $this->mParams['namespace'] )
) {
return $this->msg( 'htmlform-title-badnamespace', $text, $this->mParams['namespace'] );
}
if ( $this->mParams['creatable'] && !$title->canExist() ) {
return $this->msg( 'htmlform-title-not-creatable', $text );
}
if ( $this->mParams['exists'] && !$title->exists() ) {
return $this->msg( 'htmlform-title-not-exists', $text );
}
return parent::validate( $value, $alldata );
}
protected function getInputWidget( $params ) {
if ( $this->mParams['namespace'] !== false ) {
$params['namespace'] = $this->mParams['namespace'];
}
$params['relative'] = $this->mParams['relative'];
return new TitleInputWidget( $params );
}
protected function shouldInfuseOOUI() {
return true;
}
protected function getOOUIModules() {
// FIXME: TitleInputWidget should be in its own module
return [ 'mediawiki.widgets' ];
}
public function getInputHtml( $value ) {
// add mw-searchInput class to enable search suggestions for non-OOUI, too
$this->mClass .= 'mw-searchInput';
// return the HTMLTextField html
return parent::getInputHTML( $value );
}
protected function getDataAttribs() {
return [
'data-mw-searchsuggest' => FormatJson::encode( [
'wrapAsLink' => false,
] ),
];
}
}