IcalTimezoneFormatter::calcTransitions()   B
last analyzed

Complexity

Conditions 10
Paths 9

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 11.5625

Importance

Changes 0
Metric Value
dl 0
loc 45
ccs 18
cts 24
cp 0.75
rs 7.3333
c 0
b 0
f 0
cc 10
nc 9
nop 2
crap 11.5625

How to fix   Complexity   

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 SRF\iCalendar;
4
5
use DateTimeZone;
6
use Exception;
7
8
/**
9
 * Create the iCalendar's vTimezone component
10
 *
11
 * @license GNU GPL v2+
12
 * @since 3.0
13
 *
14
 * @author HgO
15
 */
16
class IcalTimezoneFormatter {
17
18
	/**
19
	 * @var array
20
	 */
21
	private $localTimezones = [];
22
23
	/**
24
	 * @var array
25
	 */
26
	private $transitions = [];
27
28
	/**
29
	 * @var array
30
	 */
31
	private $offsets = [];
32
33
	/**
34
	 * @since 3.0
35
	 */
36 8
	public function __construct() {
37 8
		$this->localTimezones = [ $GLOBALS['wgLocaltimezone'] ];
38 8
	}
39
40
	/**
41
	 * Set a list of local timezones.
42
	 *
43
	 * @since 3.0
44
	 *
45
	 * @param array|string $localTimezones
46
	 */
47 7
	public function setLocalTimezones( $localTimezones ) {
48
49 7
		if ( is_array( $localTimezones ) ) {
50
			$localTimezones = $localTimezones;
0 ignored issues
show
Bug introduced by mwjames
Why assign $localTimezones to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
51 7
		} elseif ( strpos( $localTimezones, ',' ) !== false ) {
52 1
			$localTimezones = explode( ',', $localTimezones );
53 7
		} elseif ( $localTimezones !== '' ) {
54 5
			$localTimezones = [ $localTimezones ];
55
		} else {
56 2
			$localTimezones = [];
57
		}
58
59 7
		$this->localTimezones = $localTimezones;
60 7
	}
61
62
	/**
63
	 * Calculate transitions for each timezone.
64
	 *
65
	 * @since 3.0
66
	 *
67
	 * @param integer $from Timestamp from which transitions are generated.
68
	 * @param integer $to Timestamp until which transitions are generated.
69
	 *
70
	 * @return boolean
71
	 */
72 7
	public function calcTransitions( $from = null, $to = null ) {
73
74 7
		if ( $this->localTimezones === [] ) {
75 2
			return false;
76
		}
77
78 5
		if ( $from === null || $to === null ) {
79
			return false;
80
		}
81
82 5
		foreach ( $this->localTimezones as $timezone ) {
83
			try {
84 5
				$dateTimezone = new DateTimeZone( $timezone );
85
			}
86 1
			catch ( Exception $e ) {
87 1
				continue;
88
			}
89
90 5
			$transitions = $dateTimezone->getTransitions( $from, $to );
91
92 5
			if ( $transitions === false ) {
93
				continue;
94
			}
95
96 5
			$min = 0;
97 5
			$max = 1;
98
99 5
			foreach ( $transitions as $i => $transition ) {
100 5
				if ( $transition['ts'] < $from ) {
101
					$min = $i;
102
					continue;
103
				}
104
105 5
				if ( $transition['ts'] > $to ) {
106
					$max = $i;
107
					break;
108
				}
109
			}
110
111 5
			$this->offsets[$timezone] = $transitions[max( $min - 1, 0 )]['offset'];
112 5
			$this->transitions[$timezone] = array_slice( $transitions, $min, $max - $min );
113
		}
114
115 5
		return true;
116
	}
117
118
	/**
119
	 * Generate the transitions for a given range, for each timezones, in the
120
	 * iCalendar format.
121
	 *
122
	 * @since 3.0
123
	 *
124
	 * @return string
125
	 */
126 7
	public function getTransitions() {
127
128 7
		$result = '';
129
130 7
		if ( $this->transitions === null || $this->transitions === [] ) {
131 2
			return $result;
132
		}
133
134 5
		foreach ( $this->transitions as $timezone => $transitions ) {
135
			// cf. http://www.kanzaki.com/docs/ical/vtimezone.html
136 5
			$result .= "BEGIN:VTIMEZONE\r\n";
137 5
			$result .= "TZID:$timezone\r\n";
138
139 5
			$tzfrom = $this->offsets[$timezone] / 3600;
140 5
			foreach ( $transitions as $transition ) {
141 5
				$dst = ( $transition['isdst'] ) ? "DAYLIGHT" : "STANDARD";
142 5
				$result .= "BEGIN:$dst\r\n";
143
144 5
				$start_date = date( 'Ymd\THis', $transition['ts'] );
145 5
				$result .= "DTSTART:$start_date\r\n";
146
147 5
				$offset = $transition['offset'] / 3600;
148
149 5
				$offset_from = $this->formatTimezoneOffset( $tzfrom );
150 5
				$result .= "TZOFFSETFROM:$offset_from\r\n";
151
152 5
				$offset_to = $this->formatTimezoneOffset( $offset );
153 5
				$result .= "TZOFFSETTO:$offset_to\r\n";
154
155 5
				if ( !empty( $transition['abbr'] ) ) {
156 5
					$result .= "TZNAME:{$transition['abbr']}\r\n";
157
				}
158
159 5
				$result .= "END:$dst\r\n";
160
161 5
				$tzfrom = $offset;
162
			}
163
164 5
			$result .= "END:VTIMEZONE\r\n";
165
		}
166
167
		// Clear the calculation
168 5
		$this->transitions = [];
169
170 5
		return $result;
171
	}
172
173
	/**
174
	 * Format an integer offset to '+hhii', where hh are the hours, and ii the
175
	 * minutes
176
	 *
177
	 * @param int $offset
178
	 */
179 5
	private function formatTimezoneOffset( $offset ) {
180 5
		return sprintf( '%s%02d%02d', $offset >= 0 ? '+' : '-', abs( floor( $offset ) ), ( $offset - floor( $offset ) ) * 60 );
181
	}
182
183
}
184