MediaWiki  master
HTMLTimezoneField.php
Go to the documentation of this file.
1 <?php
2 
9 
16  private const FIELD_CLASS = 'mw-htmlform-timezone-field';
17 
19  private $msgFormatter;
20 
26  public function __construct( $params ) {
27  if ( isset( $params['options'] ) ) {
28  throw new InvalidArgumentException( "Options should not be provided to " . __CLASS__ );
29  }
30  $params['placeholder-message'] ??= 'timezone-useoffset-placeholder';
31  $params['options'] = [];
32  parent::__construct( $params );
33  $lang = $this->mParent ? $this->mParent->getLanguage() : RequestContext::getMain()->getLanguage();
34  $langCode = $lang->getCode();
35  $this->msgFormatter = MediaWikiServices::getInstance()->getMessageFormatterFactory()
36  ->getTextFormatter( $langCode );
37  $this->mOptions = $this->getTimezoneOptions();
38  }
39 
43  private function getTimezoneOptions(): array {
44  $opt = [];
45 
46  $localTZoffset = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::LocalTZoffset );
47  $timeZoneList = $this->getTimeZoneList();
48 
49  $timestamp = MWTimestamp::getLocalInstance();
50  // Check that the LocalTZoffset is the same as the local time zone offset
51  if ( $localTZoffset === (int)$timestamp->format( 'Z' ) / 60 ) {
52  $timezoneName = $timestamp->getTimezone()->getName();
53  // Localize timezone
54  if ( isset( $timeZoneList[$timezoneName] ) ) {
55  $timezoneName = $timeZoneList[$timezoneName]['name'];
56  }
57  $server_tz_msg = $this->msgFormatter->format(
58  MessageValue::new( 'timezoneuseserverdefault', [ $timezoneName ] )
59  );
60  } else {
61  $tzstring = UserTimeCorrection::formatTimezoneOffset( $localTZoffset );
62  $server_tz_msg = $this->msgFormatter->format(
63  MessageValue::new( 'timezoneuseserverdefault', [ $tzstring ] )
64  );
65  }
66  $opt[$server_tz_msg] = "System|$localTZoffset";
67  $opt[$this->msgFormatter->format( MessageValue::new( 'timezoneuseoffset' ) )] = 'other';
68  $opt[$this->msgFormatter->format( MessageValue::new( 'guesstimezone' ) )] = 'guess';
69 
70  foreach ( $timeZoneList as $timeZoneInfo ) {
71  $region = $timeZoneInfo['region'];
72  if ( !isset( $opt[$region] ) ) {
73  $opt[$region] = [];
74  }
75  $opt[$region][$timeZoneInfo['name']] = $timeZoneInfo['timecorrection'];
76  }
77  return $opt;
78  }
79 
86  private function getTimeZoneList(): array {
87  $identifiers = DateTimeZone::listIdentifiers();
88  '@phan-var array|false $identifiers'; // See phan issue #3162
89  if ( $identifiers === false ) {
90  return [];
91  }
92  sort( $identifiers );
93 
94  $tzRegions = [
95  'Africa' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-africa' ) ),
96  'America' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-america' ) ),
97  'Antarctica' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-antarctica' ) ),
98  'Arctic' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-arctic' ) ),
99  'Asia' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-asia' ) ),
100  'Atlantic' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-atlantic' ) ),
101  'Australia' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-australia' ) ),
102  'Europe' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-europe' ) ),
103  'Indian' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-indian' ) ),
104  'Pacific' => $this->msgFormatter->format( MessageValue::new( 'timezoneregion-pacific' ) ),
105  ];
106  asort( $tzRegions );
107 
108  $timeZoneList = [];
109 
110  $now = new DateTime();
111 
112  foreach ( $identifiers as $identifier ) {
113  $parts = explode( '/', $identifier, 2 );
114 
115  // DateTimeZone::listIdentifiers() returns a number of
116  // backwards-compatibility entries. This filters them out of the
117  // list presented to the user.
118  if ( count( $parts ) !== 2 || !array_key_exists( $parts[0], $tzRegions ) ) {
119  continue;
120  }
121 
122  // Localize region
123  $parts[0] = $tzRegions[$parts[0]];
124 
125  $dateTimeZone = new DateTimeZone( $identifier );
126  $minDiff = floor( $dateTimeZone->getOffset( $now ) / 60 );
127 
128  $display = str_replace( '_', ' ', $parts[0] . '/' . $parts[1] );
129  $value = "ZoneInfo|$minDiff|$identifier";
130 
131  $timeZoneList[$identifier] = [
132  'name' => $display,
133  'timecorrection' => $value,
134  'region' => $parts[0],
135  ];
136  }
137 
138  return $timeZoneList;
139  }
140 
144  public function validate( $value, $alldata ) {
145  $p = parent::validate( $value, $alldata );
146  if ( $p !== true ) {
147  return $p;
148  }
149 
150  if ( !( new UserTimeCorrection( $value ) )->isValid() ) {
151  return $this->mParent->msg( 'timezone-invalid' )->escaped();
152  }
153 
154  return true;
155  }
156 
160  protected function getFieldClasses(): array {
161  $classes = parent::getFieldClasses();
162  $classes[] = self::FIELD_CLASS;
163  return $classes;
164  }
165 }
Select dropdown field, with an additional "other" textbox.
Dropdown widget that allows the user to select a timezone, either by choosing a geographic zone,...
getFieldClasses()
Returns a list of classes that should be applied to the widget itself.Unfortunately,...
validate( $value, $alldata)
Override this function to add specific validation checks on the field input.Don't forget to call pare...
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
Utility class to parse the TimeCorrection string value.
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:48
static getMain()
Get the RequestContext object associated with the main request.
Value object representing a message for i18n.