Completed
Pull Request — master (#49)
by no
08:44 queued 05:36
created

TimeFormatter::getFormattedTimestamp()   B

Complexity

Conditions 9
Paths 14

Size

Total Lines 56
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 56
rs 7.1584
cc 9
eloc 35
nc 14
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace ValueFormatters;
4
5
use DataValues\TimeValue;
6
use InvalidArgumentException;
7
8
/**
9
 * Basic plain text formatter for TimeValue objects that either delegates formatting to an other
10
 * formatter given via self::OPT_TIME_ISO_FORMATTER or outputs the timestamp in simple YMD-ordered
11
 * fallback formats, resembling ISO 8601.
12
 *
13
 * @since 0.1
14
 *
15
 * @license GPL-2.0+
16
 * @author H. Snater < [email protected] >
17
 * @author Thiemo Mättig
18
 */
19
class TimeFormatter extends ValueFormatterBase {
20
21
	/**
22
	 * @deprecated since 0.7.1, use TimeValue::CALENDAR_GREGORIAN instead
23
	 */
24
	const CALENDAR_GREGORIAN = TimeValue::CALENDAR_GREGORIAN;
25
26
	/**
27
	 * @deprecated since 0.7.1, use TimeValue::CALENDAR_JULIAN instead
28
	 */
29
	const CALENDAR_JULIAN = TimeValue::CALENDAR_JULIAN;
30
31
	/**
32
	 * Option to localize calendar models. Must contain an array mapping known calendar model URIs
33
	 * to localized calendar model names.
34
	 */
35
	const OPT_CALENDARNAMES = 'calendars';
36
37
	/**
38
	 * Option for a custom timestamp formatter. Must contain an instance of a ValueFormatter
39
	 * subclass, capable of formatting TimeValue objects. The output of the custom formatter is
40
	 * threaded as plain text and passed through.
41
	 */
42
	const OPT_TIME_ISO_FORMATTER = 'time iso formatter';
43
44
	/**
45
	 * @see ValueFormatterBase::__construct
46
	 *
47
	 * @param FormatterOptions|null $options
48
	 */
49
	public function __construct( FormatterOptions $options = null ) {
50
		parent::__construct( $options );
51
52
		// A non-localized default is still better than showing full concept URIs.
53
		$this->defaultOption( self::OPT_CALENDARNAMES, array(
54
			TimeValue::CALENDAR_GREGORIAN => 'Gregorian',
55
			TimeValue::CALENDAR_JULIAN => 'Julian',
56
		) );
57
		$this->defaultOption( self::OPT_TIME_ISO_FORMATTER, null );
58
	}
59
60
	/**
61
	 * @see ValueFormatter::format
62
	 *
63
	 * @param TimeValue $value
64
	 *
65
	 * @throws InvalidArgumentException
66
	 * @return string Plain text
67
	 */
68
	public function format( $value ) {
69
		if ( !( $value instanceof TimeValue ) ) {
70
			throw new InvalidArgumentException( 'Data value type mismatch. Expected a TimeValue.' );
71
		}
72
73
		$formatted = $this->getFormattedTimestamp( $value );
74
		// FIXME: Temporarily disabled.
75
		//$formatted .= ' (' . $this->getFormattedCalendarModel( $value->getCalendarModel() ) . ')';
76
		return $formatted;
77
	}
78
79
	/**
80
	 * @param TimeValue $value
81
	 *
82
	 * @return string Plain text
83
	 */
84
	private function getFormattedTimestamp( TimeValue $value ) {
85
		$formatter = $this->getOption( self::OPT_TIME_ISO_FORMATTER );
86
87
		if ( $formatter instanceof ValueFormatter ) {
88
			return $formatter->format( $value );
89
		}
90
91
		if ( !preg_match(
92
			// Loose check for ISO-like strings, as used in Gregorian and Julian time values.
93
			'/^([-+]?)(\d+)-(\d+)-(\d+)(?:T(\d+):(\d+)(?::(\d+))?)?Z?$/i',
94
			$value->getTime(),
95
			$matches
96
		) ) {
97
			return $value->getTime();
98
		}
99
100
		list( , $sign, $year, $month, $day, $hour, $minute, $second ) = $matches;
101
102
		// Actual MINUS SIGN (U+2212) instead of HYPHEN-MINUS (U+002D)
103
		$sign = $sign === '-' ? "\xE2\x88\x92" : '';
104
105
		// Warning, never cast the year to integer to not run into 32-bit integer overflows!
106
		$year = ltrim( $year, '0' );
107
108
		if ( $value->getPrecision() <= TimeValue::PRECISION_YEAR ) {
109
			return sprintf( '%s%04s', $sign, $year );
110
		}
111
112
		switch ( $value->getPrecision() ) {
113
			case TimeValue::PRECISION_MONTH:
114
				return sprintf(
115
					'%s%04s-%02s',
116
					$sign, $year, $month
117
				);
118
			case TimeValue::PRECISION_DAY:
119
				return sprintf(
120
					'%s%04s-%02s-%02s',
121
					$sign, $year, $month, $day
122
				);
123
			case TimeValue::PRECISION_HOUR:
124
				return sprintf(
125
					'%s%04s-%02s-%02sT%02s',
126
					$sign, $year, $month, $day, $hour
127
				);
128
			case TimeValue::PRECISION_MINUTE:
129
				return sprintf(
130
					'%s%04s-%02s-%02sT%02s:%02s',
131
					$sign, $year, $month, $day, $hour, $minute
132
				);
133
			default:
134
				return sprintf(
135
					'%s%04s-%02s-%02sT%02s:%02s:%02s',
136
					$sign, $year, $month, $day, $hour, $minute, $second
137
				);
138
		}
139
	}
140
141
	/**
142
	 * @param string $calendarModel
143
	 *
144
	 * @return string Plain text
145
	 */
146
	private function getFormattedCalendarModel( $calendarModel ) {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
147
		$calendarNames = $this->getOption( self::OPT_CALENDARNAMES );
148
149
		if ( array_key_exists( $calendarModel, $calendarNames ) ) {
150
			return $calendarNames[$calendarModel];
151
		}
152
153
		return $calendarModel;
154
	}
155
156
}
157