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