Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
62.07% |
18 / 29 |
|
62.50% |
5 / 8 |
CRAP | |
0.00% |
0 / 1 |
EventTimeFormatter | |
62.07% |
18 / 29 |
|
62.50% |
5 / 8 |
17.60 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
formatStart | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
formatEnd | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
formatTimeInternal | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
formatTimezone | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
getTimeCorrection | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
wrapRangeForConversion | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
wrapTimeZoneForConversion | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | declare( strict_types=1 ); |
4 | |
5 | namespace MediaWiki\Extension\CampaignEvents\Time; |
6 | |
7 | use MediaWiki\Extension\CampaignEvents\Event\EventRegistration; |
8 | use MediaWiki\Extension\CampaignEvents\Utils; |
9 | use MediaWiki\Language\Language; |
10 | use MediaWiki\User\Options\UserOptionsLookup; |
11 | use MediaWiki\User\UserIdentity; |
12 | use MediaWiki\User\UserTimeCorrection; |
13 | use OOUI\HtmlSnippet; |
14 | use OOUI\Tag; |
15 | use Wikimedia\Timestamp\ConvertibleTimestamp; |
16 | |
17 | /** |
18 | * This service formats the time of an event according to the event type, in a given language and for a given user. |
19 | * The timezone used for the return value can be obtained separately. |
20 | */ |
21 | class EventTimeFormatter { |
22 | public const SERVICE_NAME = 'CampaignEventsEventTimeFormatter'; |
23 | |
24 | private UserOptionsLookup $userOptionsLookup; |
25 | |
26 | private const FORMAT_START = 'start'; |
27 | private const FORMAT_END = 'end'; |
28 | |
29 | /** |
30 | * @param UserOptionsLookup $userOptionsLookup |
31 | */ |
32 | public function __construct( UserOptionsLookup $userOptionsLookup ) { |
33 | $this->userOptionsLookup = $userOptionsLookup; |
34 | } |
35 | |
36 | /** |
37 | * @param EventRegistration $event |
38 | * @param Language $language |
39 | * @param UserIdentity $user |
40 | * @return FormattedTime |
41 | */ |
42 | public function formatStart( |
43 | EventRegistration $event, |
44 | Language $language, |
45 | UserIdentity $user |
46 | ): FormattedTime { |
47 | return $this->formatTimeInternal( self::FORMAT_START, $event, $language, $user ); |
48 | } |
49 | |
50 | /** |
51 | * @param EventRegistration $event |
52 | * @param Language $language |
53 | * @param UserIdentity $user |
54 | * @return FormattedTime |
55 | */ |
56 | public function formatEnd( |
57 | EventRegistration $event, |
58 | Language $language, |
59 | UserIdentity $user |
60 | ): FormattedTime { |
61 | return $this->formatTimeInternal( self::FORMAT_END, $event, $language, $user ); |
62 | } |
63 | |
64 | /** |
65 | * @param string $type self::FORMAT_START or self::FORMAT_END |
66 | * @param EventRegistration $event |
67 | * @param Language $language |
68 | * @param UserIdentity $user |
69 | * @return FormattedTime |
70 | */ |
71 | private function formatTimeInternal( |
72 | string $type, |
73 | EventRegistration $event, |
74 | Language $language, |
75 | UserIdentity $user |
76 | ): FormattedTime { |
77 | $formatOptions = [ 'timecorrection' => $this->getTimeCorrection( $event, $user )->toString() ]; |
78 | $utcTimestamp = $type === self::FORMAT_START ? $event->getStartUTCTimestamp() : $event->getEndUTCTimestamp(); |
79 | return new FormattedTime( |
80 | $language->userTime( $utcTimestamp, $user, $formatOptions ), |
81 | $language->userDate( $utcTimestamp, $user, $formatOptions ), |
82 | $language->userTimeAndDate( $utcTimestamp, $user, $formatOptions ) |
83 | ); |
84 | } |
85 | |
86 | /** |
87 | * @param EventRegistration $eventRegistration |
88 | * @param UserIdentity $user |
89 | * @return string |
90 | */ |
91 | public function formatTimezone( EventRegistration $eventRegistration, UserIdentity $user ): string { |
92 | $userTimeCorrection = $this->getTimeCorrection( $eventRegistration, $user ); |
93 | $tzObj = $userTimeCorrection->getTimeZone(); |
94 | if ( $tzObj ) { |
95 | return $tzObj->getName(); |
96 | } |
97 | return UserTimeCorrection::formatTimezoneOffset( $userTimeCorrection->getTimeOffset() ); |
98 | } |
99 | |
100 | /** |
101 | * Returns the time correction that should be used when formatting time, date, and timezone. |
102 | * This uses the event timezone for in-person events, and the user preference for online and hybrid events, |
103 | * see T316688. |
104 | * |
105 | * @param EventRegistration $event |
106 | * @param UserIdentity $user |
107 | * @return UserTimeCorrection |
108 | */ |
109 | private function getTimeCorrection( EventRegistration $event, UserIdentity $user ): UserTimeCorrection { |
110 | if ( $event->getMeetingType() === EventRegistration::MEETING_TYPE_IN_PERSON ) { |
111 | return Utils::timezoneToUserTimeCorrection( $event->getTimezone() ); |
112 | } |
113 | $timeCorrectionPref = $this->userOptionsLookup->getOption( $user, 'timecorrection' ) ?? ''; |
114 | return new UserTimeCorrection( $timeCorrectionPref ); |
115 | } |
116 | |
117 | /** |
118 | * Wrap a time range in an HTML structure that can be read by the TimeZoneConverter JavaScript utility. |
119 | * The timezone must also be wrapped, using {@see self::wrapTimeZoneForConversion}. |
120 | */ |
121 | public static function wrapRangeForConversion( EventRegistration $event, string $range ): Tag { |
122 | return ( new Tag( 'span' ) ) |
123 | ->addClasses( [ 'ext-campaignevents-time-range' ] ) |
124 | ->setAttributes( [ |
125 | 'data-mw-start' => ConvertibleTimestamp::convert( TS_ISO_8601, $event->getStartUTCTimestamp() ), |
126 | 'data-mw-end' => ConvertibleTimestamp::convert( TS_ISO_8601, $event->getEndUTCTimestamp() ), |
127 | ] ) |
128 | ->appendContent( $range ); |
129 | } |
130 | |
131 | /** |
132 | * Wrap a timezone name in an HTML structure that can be read by the TimeZoneConverter JavaScript utility. |
133 | * The time range must also be wrapped, using {@see self::wrapRangeForConversion}. |
134 | */ |
135 | public static function wrapTimeZoneForConversion( string $timezone ): Tag { |
136 | return ( new Tag( 'span' ) ) |
137 | ->addClasses( [ 'ext-campaignevents-timezone' ] ) |
138 | ->appendContent( new HtmlSnippet( $timezone ) ); |
139 | } |
140 | } |