MediaWiki master
CoreMagicVariables.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Parser;
25
26use DateTime;
31use Psr\Log\LoggerInterface;
32use Wikimedia\Timestamp\ConvertibleTimestamp;
33
41 private const CACHE_TTL_BY_ID = [
42 'currenttime' => 3600,
43 'localtime' => 3600,
44 'numberofarticles' => 3600,
45 'numberoffiles' => 3600,
46 'numberofedits' => 3600,
47 'numberofusers' => 3600,
48 'numberofactiveusers' => 3600,
49 'numberofpages' => 3600,
50 'currentversion' => 86400,
51 'currenttimestamp' => 3600,
52 'localtimestamp' => 3600,
53 'pagesinnamespace' => 3600,
54 'numberofadmins' => 3600,
55 'numberingroup' => 3600,
56 ];
57
59 private const DEADLINE_DATE_SPEC_BY_UNIT = [
60 'Y' => 'first day of January next year midnight',
61 'M' => 'first day of next month midnight',
62 'D' => 'next day midnight',
63 // Note that this relative datetime specifier does not zero out
64 // minutes/seconds, but we will do so manually in
65 // ::applyUnitTimestampDeadline() when given the unit 'H'
66 'H' => 'next hour'
67 ];
69 private const DEADLINE_TTL_CLOCK_FUDGE = 1;
71 private const DEADLINE_TTL_STAGGER_MAX = 15;
73 private const MIN_DEADLINE_TTL = 15;
74
87 public static function expand(
88 // Fundamental options
89 Parser $parser,
90 string $id,
91 // Context passed over from the parser
92 ConvertibleTimestamp $ts,
93 ServiceOptions $svcOptions,
94 LoggerInterface $logger
95 ): ?string {
96 $pageLang = $parser->getTargetLanguage();
97
98 $cacheTTL = self::CACHE_TTL_BY_ID[$id] ?? -1;
99 if ( $cacheTTL > -1 ) {
100 $parser->getOutput()->updateCacheExpiry( $cacheTTL );
101 }
102
103 switch ( $id ) {
104 case '!':
105 return '|';
106 case '=':
107 return '=';
108 case 'currentmonth':
109 self::applyUnitTimestampDeadline( $parser, $ts, 'M' );
110
111 return $pageLang->formatNumNoSeparators( $ts->format( 'm' ) );
112 case 'currentmonth1':
113 self::applyUnitTimestampDeadline( $parser, $ts, 'M' );
114
115 return $pageLang->formatNumNoSeparators( $ts->format( 'n' ) );
116 case 'currentmonthname':
117 self::applyUnitTimestampDeadline( $parser, $ts, 'M' );
118
119 return $pageLang->getMonthName( (int)$ts->format( 'n' ) );
120 case 'currentmonthnamegen':
121 self::applyUnitTimestampDeadline( $parser, $ts, 'M' );
122
123 return $pageLang->getMonthNameGen( (int)$ts->format( 'n' ) );
124 case 'currentmonthabbrev':
125 self::applyUnitTimestampDeadline( $parser, $ts, 'M' );
126
127 return $pageLang->getMonthAbbreviation( (int)$ts->format( 'n' ) );
128 case 'currentday':
129 self::applyUnitTimestampDeadline( $parser, $ts, 'D' );
130
131 return $pageLang->formatNumNoSeparators( $ts->format( 'j' ) );
132 case 'currentday2':
133 self::applyUnitTimestampDeadline( $parser, $ts, 'D' );
134
135 return $pageLang->formatNumNoSeparators( $ts->format( 'd' ) );
136 case 'localmonth':
137 $localTs = self::makeTsLocal( $svcOptions, $ts );
138 self::applyUnitTimestampDeadline( $parser, $localTs, 'M' );
139
140 return $pageLang->formatNumNoSeparators( $localTs->format( 'm' ) );
141 case 'localmonth1':
142 $localTs = self::makeTsLocal( $svcOptions, $ts );
143 self::applyUnitTimestampDeadline( $parser, $localTs, 'M' );
144
145 return $pageLang->formatNumNoSeparators( $localTs->format( 'n' ) );
146 case 'localmonthname':
147 $localTs = self::makeTsLocal( $svcOptions, $ts );
148 self::applyUnitTimestampDeadline( $parser, $localTs, 'M' );
149
150 return $pageLang->getMonthName( (int)$localTs->format( 'n' ) );
151 case 'localmonthnamegen':
152 $localTs = self::makeTsLocal( $svcOptions, $ts );
153 self::applyUnitTimestampDeadline( $parser, $localTs, 'M' );
154
155 return $pageLang->getMonthNameGen( (int)$localTs->format( 'n' ) );
156 case 'localmonthabbrev':
157 $localTs = self::makeTsLocal( $svcOptions, $ts );
158 self::applyUnitTimestampDeadline( $parser, $localTs, 'M' );
159
160 return $pageLang->getMonthAbbreviation( (int)$localTs->format( 'n' ) );
161 case 'localday':
162 $localTs = self::makeTsLocal( $svcOptions, $ts );
163 self::applyUnitTimestampDeadline( $parser, $localTs, 'D' );
164
165 return $pageLang->formatNumNoSeparators( $localTs->format( 'j' ) );
166 case 'localday2':
167 $localTs = self::makeTsLocal( $svcOptions, $ts );
168 self::applyUnitTimestampDeadline( $parser, $localTs, 'D' );
169
170 return $pageLang->formatNumNoSeparators( $localTs->format( 'd' ) );
171 case 'pagename':
172 case 'pagenamee':
173 case 'fullpagename':
174 case 'fullpagenamee':
175 case 'subpagename':
176 case 'subpagenamee':
177 case 'rootpagename':
178 case 'rootpagenamee':
179 case 'basepagename':
180 case 'basepagenamee':
181 case 'talkpagename':
182 case 'talkpagenamee':
183 case 'subjectpagename':
184 case 'subjectpagenamee':
185 case 'pageid':
186 case 'revisionid':
187 case 'revisionuser':
188 case 'revisionday':
189 case 'revisionday2':
190 case 'revisionmonth':
191 case 'revisionmonth1':
192 case 'revisionyear':
193 case 'revisiontimestamp':
194 case 'namespace':
195 case 'namespacee':
196 case 'namespacenumber':
197 case 'talkspace':
198 case 'talkspacee':
199 case 'subjectspace':
200 case 'subjectspacee':
201 case 'cascadingsources':
202 # First argument of the corresponding parser function
203 # (second argument of the PHP implementation) is
204 # "title".
205
206 # Note that for many of these {{FOO}} is subtly different
207 # from {{FOO:{{PAGENAME}}}}, so we can't pass $title here
208 # we have to explicitly use the "no arguments" form of the
209 # parser function by passing `null` to indicate a missing
210 # argument (which then defaults to the current page title).
211 return CoreParserFunctions::$id( $parser, null );
212 case 'revisionsize':
213 return (string)$parser->getRevisionSize();
214 case 'currentdayname':
215 self::applyUnitTimestampDeadline( $parser, $ts, 'D' );
216
217 return $pageLang->getWeekdayName( (int)$ts->format( 'w' ) + 1 );
218 case 'currentyear':
219 self::applyUnitTimestampDeadline( $parser, $ts, 'Y' );
220
221 return $pageLang->formatNumNoSeparators( $ts->format( 'Y' ) );
222 case 'currenttime':
223 return $pageLang->time( $ts->getTimestamp( TS_MW ), false, false );
224 case 'currenthour':
225 self::applyUnitTimestampDeadline( $parser, $ts, 'H' );
226
227 return $pageLang->formatNumNoSeparators( $ts->format( 'H' ) );
228 case 'currentweek':
229 self::applyUnitTimestampDeadline( $parser, $ts, 'D' );
230 // @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
231 // int to remove the padding
232 return $pageLang->formatNum( (int)$ts->format( 'W' ) );
233 case 'currentdow':
234 self::applyUnitTimestampDeadline( $parser, $ts, 'D' );
235
236 return $pageLang->formatNum( $ts->format( 'w' ) );
237 case 'localdayname':
238 $localTs = self::makeTsLocal( $svcOptions, $ts );
239 self::applyUnitTimestampDeadline( $parser, $localTs, 'D' );
240
241 return $pageLang->getWeekdayName( (int)$localTs->format( 'w' ) + 1 );
242 case 'localyear':
243 $localTs = self::makeTsLocal( $svcOptions, $ts );
244 self::applyUnitTimestampDeadline( $parser, $localTs, 'Y' );
245
246 return $pageLang->formatNumNoSeparators( $localTs->format( 'Y' ) );
247 case 'localtime':
248 $localTs = self::makeTsLocal( $svcOptions, $ts );
249
250 return $pageLang->time(
251 $localTs->format( 'YmdHis' ),
252 false,
253 false
254 );
255 case 'localhour':
256 $localTs = self::makeTsLocal( $svcOptions, $ts );
257 self::applyUnitTimestampDeadline( $parser, $localTs, 'H' );
258
259 return $pageLang->formatNumNoSeparators( $localTs->format( 'H' ) );
260 case 'localweek':
261 $localTs = self::makeTsLocal( $svcOptions, $ts );
262 self::applyUnitTimestampDeadline( $parser, $localTs, 'D' );
263 // @bug T6594 PHP5 has it zero padded, PHP4 does not, cast to
264 // int to remove the padding
265 return $pageLang->formatNum( (int)$localTs->format( 'W' ) );
266 case 'localdow':
267 $localTs = self::makeTsLocal( $svcOptions, $ts );
268 self::applyUnitTimestampDeadline( $parser, $localTs, 'D' );
269
270 return $pageLang->formatNum( $localTs->format( 'w' ) );
271 case 'numberofarticles':
272 case 'numberoffiles':
273 case 'numberofusers':
274 case 'numberofactiveusers':
275 case 'numberofpages':
276 case 'numberofadmins':
277 case 'numberofedits':
278 # second argument is 'raw'; magic variables are "not raw"
279 return CoreParserFunctions::$id( $parser, null );
280 case 'currenttimestamp':
281 return $ts->getTimestamp( TS_MW );
282 case 'localtimestamp':
283 $localTs = self::makeTsLocal( $svcOptions, $ts );
284
285 return $localTs->format( 'YmdHis' );
286 case 'currentversion':
287 return SpecialVersion::getVersion();
288 case 'articlepath':
289 return (string)$svcOptions->get( MainConfigNames::ArticlePath );
290 case 'sitename':
291 return (string)$svcOptions->get( MainConfigNames::Sitename );
292 case 'server':
293 return (string)$svcOptions->get( MainConfigNames::Server );
294 case 'servername':
295 return (string)$svcOptions->get( MainConfigNames::ServerName );
296 case 'scriptpath':
297 return (string)$svcOptions->get( MainConfigNames::ScriptPath );
298 case 'stylepath':
299 return (string)$svcOptions->get( MainConfigNames::StylePath );
300 case 'directionmark':
301 return $pageLang->getDirMark();
302 case 'contentlanguage':
303 return $parser->getContentLanguage()->getCode();
304 case 'pagelanguage':
305 return $pageLang->getCode();
306 case 'userlanguage':
307 if ( $svcOptions->get( MainConfigNames::ParserEnableUserLanguage ) ) {
308 return $parser->getOptions()->getUserLang();
309 } else {
310 return $pageLang->getCode();
311 }
312 case 'bcp47':
313 case 'dir':
314 case 'language':
315 # magic variables are the same as empty/default first argument
316 return CoreParserFunctions::$id( $parser );
317 default:
318 // This is not one of the core magic variables
319 return null;
320 }
321 }
322
330 private static function makeTsLocal( $svcOptions, $ts ) {
331 $localtimezone = $svcOptions->get( MainConfigNames::Localtimezone );
332 $ts->setTimezone( $localtimezone );
333 return $ts;
334 }
335
343 private static function applyUnitTimestampDeadline(
344 Parser $parser,
345 ConvertibleTimestamp $ts,
346 string $unit
347 ) {
348 $tsUnix = (int)$ts->getTimestamp( TS_UNIX );
349
350 $date = new DateTime( "@$tsUnix" );
351 $date->setTimezone( $ts->getTimezone() );
352 $date->modify( self::DEADLINE_DATE_SPEC_BY_UNIT[$unit] );
353 if ( $unit === 'H' ) {
354 // Zero out the minutes/seconds
355 $date->setTime( intval( $date->format( 'H' ), 10 ), 0, 0 );
356 } else {
357 $date->setTime( 0, 0, 0 );
358 }
359 $deadlineUnix = (int)$date->format( 'U' );
360
361 $ttl = max( $deadlineUnix - $tsUnix, self::MIN_DEADLINE_TTL );
362 $ttl += self::DEADLINE_TTL_CLOCK_FUDGE;
363 $ttl += ( $tsUnix % self::DEADLINE_TTL_STAGGER_MAX );
364
365 $parser->getOutput()->updateCacheExpiry( $ttl );
366 }
367}
368
370class_alias( CoreMagicVariables::class, 'CoreMagicVariables' );
A class for passing options to services.
A class containing constants representing the names of configuration variables.
const ServerName
Name constant for the ServerName setting, for use with Config::get()
const ParserEnableUserLanguage
Name constant for the ParserEnableUserLanguage setting, for use with Config::get()
const StylePath
Name constant for the StylePath setting, for use with Config::get()
const Localtimezone
Name constant for the Localtimezone setting, for use with Config::get()
const Server
Name constant for the Server setting, for use with Config::get()
const Sitename
Name constant for the Sitename setting, for use with Config::get()
const ArticlePath
Name constant for the ArticlePath setting, for use with Config::get()
const ScriptPath
Name constant for the ScriptPath setting, for use with Config::get()
Expansions of core magic variables, used by the parser.
static expand(Parser $parser, string $id, ConvertibleTimestamp $ts, ServiceOptions $svcOptions, LoggerInterface $logger)
Expand the magic variable given by $index.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:147
getContentLanguage()
Get the content language that this Parser is using.
Definition Parser.php:1240
getRevisionSize()
Get the size of the revision.
Definition Parser.php:6209
Version information about MediaWiki (core, extensions, libs), PHP, and the database.
Library for creating and parsing MW-style timestamps.