mediawiki-skins-Vector/includes/HTMLForm/Fields/HTMLLegacySkinVersionField.php
Sam Smith 4449235516 [Special:Preferences] [PHP] Add HTMLSkinVersionField form field
I177dad88 introduced the skin version user preference field and
associated configuration values. Per T242381, the field is to presented
as a checkbox with the implied storage type of a boolean where a string
is needed. A PreferencesFormPreSave hook handler was added to adapt
values of either data type to the other.  While this was a neat solution
to a minor nit, the adapter's implementation is incompatible with the
GlobalPreferences extension as the PreferencesFormPreSave hook isn't run
whilst saving global preferences.

Rather than adding an equivalent hook to the GlobalPreferences
extension, create a custom field based on a checkbox with the adapter
included. This allows us to:

- Separate the business logic concerned with preserving the user's
  VectorSkinVersion preference if they've simply disabled Vector from
  the adapter

- Simplify the adapter's implementation

- Forego adding hooks to the GlobalPreferences codebase

Additional changes:

- Replace repeated string literals with equivalent constants in
  tests/phpunit/integration/VectorHooksTest.php

Bug: T258493
Change-Id: I628435a4ad676f55534191b8c10147be28be5d73
2020-08-31 12:04:12 -07:00

93 lines
2.7 KiB
PHP

<?php
namespace Vector\HTMLForm\Fields;
use Vector\Constants;
use Wikimedia\Assert\Assert;
/**
* The field on Special:Preferences (and Special:GlobalPreferences) that allows the user to
* enable/disable the legacy version of the Vector skin. Per
* https://phabricator.wikimedia.org/T242381, the field is a checkbox, that, when checked, enables
* the legacy version of the Vector skin.
*
* `HTMLLegacySkinVersionField` adapts the boolean storage type of a checkbox field to the string
* storage type of the Vector skin version preference (e.g. see `Constants::SKIN_VERSION_LEGACY`).
*
* However, we cannot extend `HTMLCheckField` to inherit the behavior of a checkbox field.
* `HTMLCheckField::loadDataFromRequest` returns boolean values. Returning non-boolean values in
* `HTMLLegacySkinVersionField::loadDataFromRequest` would violate Liskov's Substitution Principle.
* Like `HTMLExpiryField`, `HTMLLegacySkinVersionField` proxies to a private instance of
* `HTMLCheckField`, adapting parameter and return values where necessary.
*
* @package Vector\HTMLForm\Fields
* @internal
*/
final class HTMLLegacySkinVersionField extends \HTMLFormField {
/**
* @var \HTMLCheckField $checkField
*/
private $checkField;
/**
* @inheritDoc
*/
public function __construct( $params ) {
Assert::precondition(
is_bool( $params['default'] ),
'The "default" param must be a boolean.'
);
parent::__construct( $params );
$this->checkField = new \HTMLCheckField( $params );
}
// BEGIN ADAPTER
/** @inheritDoc */
public function getInputHTML( $value ) {
return $this->checkField->getInputHTML( $value === Constants::SKIN_VERSION_LEGACY );
}
/** @inheritDoc */
public function getInputOOUI( $value ) {
return $this->checkField->getInputOOUI( (string)( $value === Constants::SKIN_VERSION_LEGACY ) );
}
/**
* @inheritDoc
*
* @return string If the checkbox is checked, then `Constants::SKIN_VERSION_LEGACY`;
* `Constants::SKIN_VERSION_LATEST` otherwise
*/
public function loadDataFromRequest( $request ) {
return $this->checkField->loadDataFromRequest( $request )
? Constants::SKIN_VERSION_LEGACY
: Constants::SKIN_VERSION_LATEST;
}
// END ADAPTER
/** @inheritDoc */
public function getLabel() {
return $this->checkField->getLabel();
}
// Note well that we can't invoke the following methods of `HTMLCheckField` directly because
// they're protected and `HTMLSkinVectorField` doesn't extend `HTMLCheckField`.
/** @inheritDoc */
protected function getLabelAlignOOUI() {
// See \HTMLCheckField::getLabelAlignOOUI
return 'inline';
}
/** @inheritDoc */
protected function needsLabel() {
// See \HTMLCheckField::needsLabel
return false;
}
}