Completed
Push — master ( 6ca4bd...61c879 )
by mw
06:26
created

SRFiCalendar   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 80.65%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 4
dl 0
loc 298
ccs 100
cts 124
cp 0.8065
rs 8.439
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A handleParameters() 0 6 1
A getMimeType() 0 3 1
A getFileName() 0 7 2
A getQueryMode() 0 3 2
A getName() 0 3 1
A getResultText() 0 3 2
B getIcal() 0 39 5
B getIcalLink() 0 28 5
D getIcalForItem() 0 74 18
C parsedate() 0 23 8
A escapeICalendarText() 0 4 1
A getParamDefinitions() 0 20 1

How to fix   Complexity   

Complex Class

Complex classes like SRFiCalendar often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SRFiCalendar, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
use SRF\iCalendar\IcalTimezoneFormatter;
4
5
/**
6
 * Create iCalendar exports
7
 * @file
8
 * @ingroup SemanticResultFormats
9
 */
10
11
/**
12
 * Printer class for creating iCalendar exports
13
 *
14
 * @author Markus Krötzsch
15
 * @author Denny Vrandecic
16
 * @author Jeroen De Dauw
17
 *
18
 * @ingroup SemanticResultFormats
19
 */
20
class SRFiCalendar extends SMWExportPrinter {
21
22
	protected $m_title;
23
	protected $m_description;
24
25
	/**
26
	 * @var IcalTimezoneFormatter
27
	 */
28
	private $icalTimezoneFormatter;
29
30 3
	protected function handleParameters( array $params, $outputmode ) {
31 3
		parent::handleParameters( $params, $outputmode );
32
33 3
		$this->m_title = trim( $params['title'] );
34 3
		$this->m_description = trim( $params['description'] );
35 3
	}
36
37
	/**
38
	 * @see SMWIExportPrinter::getMimeType
39
	 *
40
	 * @since 1.8
41
	 *
42
	 * @param SMWQueryResult $queryResult
43
	 *
44
	 * @return string
45
	 */
46
	public function getMimeType( SMWQueryResult $queryResult ) {
47
		return 'text/calendar';
48
	}
49
50
	/**
51
	 * @see SMWIExportPrinter::getFileName
52
	 *
53
	 * @since 1.8
54
	 *
55
	 * @param SMWQueryResult $queryResult
56
	 *
57
	 * @return string|boolean
58
	 */
59
	public function getFileName( SMWQueryResult $queryResult ) {
60
		if ( $this->m_title != '' ) {
61
			return str_replace( ' ', '_', $this->m_title ) . '.ics';
62
		} else {
63
			return 'iCalendar.ics';
64
		}
65
	}
66
67 3
	public function getQueryMode( $context ) {
68 3
		return ( $context == SMWQueryProcessor::SPECIAL_PAGE ) ? SMWQuery::MODE_INSTANCES : SMWQuery::MODE_NONE;
69
	}
70
71
	public function getName() {
72
		return wfMessage( 'srf_printername_icalendar' )->text();
73
	}
74
75 3
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
76 3
		return $outputmode == SMW_OUTPUT_FILE ? $this->getIcal( $res ) : $this->getIcalLink( $res, $outputmode );
77
	}
78
79
	/**
80
	 * Returns the query result in iCal.
81
	 *
82
	 * @since 1.5.2
83
	 *
84
	 * @param SMWQueryResult $res
85
	 *
86
	 * @return string
87
	 */
88 3
	protected function getIcal( SMWQueryResult $res ) {
89
90 3
		$this->icalTimezoneFormatter = new IcalTimezoneFormatter();
91
92 3
		$this->icalTimezoneFormatter->setLocalTimezones(
93 3
			isset( $this->params['timezone'] ) ? $this->params['timezone'] : []
94
		);
95
96 3
		$result = '';
97
98 3
		if ( $this->m_title == '' ) {
99 3
			global $wgSitename;
100 3
			$this->m_title = $wgSitename;
101
		}
102
103 3
		$result .= "BEGIN:VCALENDAR\r\n";
104 3
		$result .= "PRODID:-//SMW Project//Semantic Result Formats\r\n";
105 3
		$result .= "VERSION:2.0\r\n";
106 3
		$result .= "METHOD:PUBLISH\r\n";
107 3
		$result .= "X-WR-CALNAME:" . $this->m_title . "\r\n";
108
109 3
		if ( $this->m_description !== '' ) {
110 3
			$result .= "X-WR-CALDESC:" . $this->m_description . "\r\n";
111
		}
112
113 3
		$events = '';
114 3
		$row = $res->getNext();
115 3
		while ( $row !== false ) {
116 3
			$events .= $this->getIcalForItem( $row );
117
118 3
			$row = $res->getNext();
119
		}
120
121 3
		$result .= $this->icalTimezoneFormatter->getTransitions();
122 3
		$result .= $events;
123 3
		$result .= "END:VCALENDAR\r\n";
124
125 3
		return $result;
126
	}
127
128
	/**
129
	 * Returns html for a link to a query that returns the iCal.
130
	 *
131
	 * @since 1.5.2
132
	 *
133
	 * @param SMWQueryResult $res
134
	 * @param $outputmode
135
	 *
136
	 * @return string
137
	 */
138
	protected function getIcalLink( SMWQueryResult $res, $outputmode ) {
139
		if ( $this->getSearchLabel( $outputmode ) ) {
140
			$label = $this->getSearchLabel( $outputmode );
141
		} else {
142
			$label = wfMessage( 'srf_icalendar_link' )->inContentLanguage()->text();
143
		}
144
145
		$link = $res->getQueryLink( $label );
146
		$link->setParameter( 'icalendar', 'format' );
147
148
		if ( $this->m_title !== '' ) {
149
			$link->setParameter( $this->m_title, 'title' );
150
		}
151
152
		if ( $this->m_description !== '' ) {
153
			$link->setParameter( $this->m_description, 'description' );
154
		}
155
156
		if ( array_key_exists( 'limit', $this->params ) ) {
157
			$link->setParameter( $this->params['limit'], 'limit' );
158
		} else { // use a reasonable default limit
159
			$link->setParameter( 20, 'limit' );
160
		}
161
162
		// yes, our code can be viewed as HTML if requested, no more parsing needed
163
		$this->isHTML = ( $outputmode == SMW_OUTPUT_HTML );
164
		return $link->getText( $outputmode, $this->mLinker );
165
	}
166
167
	/**
168
	 * Returns the iCal for a single item.
169
	 *
170
	 * @since 1.5.2
171
	 *
172
	 * @param array $row
173
	 *
174
	 * @return string
175
	 */
176 3
	protected function getIcalForItem( array $row ) {
177 3
		$result = '';
178
179 3
		$wikipage = $row[0]->getResultSubject(); // get the object
180 3
		$wikipage = SMWDataValueFactory::newDataItemValue( $wikipage, null );
181
182
		$params = [
183 3
			'summary' => $wikipage->getShortWikiText()
184
		];
185
186 3
		$from = null;
187 3
		$to = null;
188 3
		foreach ( $row as /* SMWResultArray */ $field ) {
189
			// later we may add more things like a generic
190
			// mechanism to add whatever you want :)
191
			// could include funny things like geo, description etc. though
192 3
			$req = $field->getPrintRequest();
193 3
			$label = strtolower( $req->getLabel() );
194
195
			switch ( $label ) {
196 3
				case 'start': case 'end':
197 2
					if ( $req->getTypeID() == '_dat' ) {
198 2
						$dataValue = $field->getNextDataValue();
199
200 2
						if ( $dataValue === false ) {
201 2
							unset( $params[$label] );
202
						}
203
						else {
204 2
							$params[$label] = $this->parsedate( $dataValue, $label == 'end' );
205
206 2
							$timestamp = strtotime( $params[$label] );
207 2
							if ( $from === null || $timestamp < $from )
208 2
								$from = $timestamp;
209 2
							if ( $to === null || $timestamp > $to )
210 2
								$to = $timestamp;
211
						}
212
					}
213 2
					break;
214 3
				case 'location': case 'description': case 'summary':
215 2
					$value = $field->getNextDataValue();
216 2
					if ( $value !== false ) {
217 2
						$params[$label] = $value->getShortWikiText();
218
					}
219 3
					break;
220
			}
221
		}
222
223 3
		$this->icalTimezoneFormatter->calcTransitions( $from, $to );
224
225 3
		$title = $wikipage->getTitle();
226 3
		$article = new Article( $title );
227 3
		$url = $title->getFullURL();
228
229 3
		$result .= "BEGIN:VEVENT\r\n";
230 3
		$result .= "SUMMARY:" . $this->escapeICalendarText( $params['summary'] ) . "\r\n";
231 3
		$result .= "URL:$url\r\n";
232 3
		$result .= "UID:$url\r\n";
233
234 3
		if ( array_key_exists( 'start', $params ) ) $result .= "DTSTART:" . $params['start'] . "\r\n";
235 3
		if ( array_key_exists( 'end', $params ) )   $result .= "DTEND:" . $params['end'] . "\r\n";
236 3
		if ( array_key_exists( 'location', $params ) ) {
237 2
			$result .= "LOCATION:" . $this->escapeICalendarText( $params['location'] ) . "\r\n";
238
		}
239 3
		if ( array_key_exists( 'description', $params ) ) {
240 2
			$result .= "DESCRIPTION:" . $this->escapeICalendarText( $params['description'] ) . "\r\n";
241
		}
242
243 3
		$t = strtotime( str_replace( 'T', ' ', $article->getTimestamp() ) );
244 3
		$result .= "DTSTAMP:" . date( "Ymd", $t ) . "T" . date( "His", $t ) . "\r\n";
245 3
		$result .= "SEQUENCE:" . $title->getLatestRevID() . "\r\n";
246 3
		$result .= "END:VEVENT\r\n";
247
248 3
		return $result;
249
	}
250
251
	/**
252
	 * Extract a date string formatted for iCalendar from a SMWTimeValue object.
253
	 */
254 2
	static private function parsedate( SMWTimeValue $dv, $isend = false ) {
255 2
		$year = $dv->getYear();
256 2
		if ( ( $year > 9999 ) || ( $year < -9998 ) ) return ''; // ISO range is limited to four digits
257
258 2
		$year = number_format( $year, 0, '.', '' );
259 2
		$time = str_replace( ':', '', $dv->getTimeString( false ) );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
260
261 2
		if ( ( $time == false ) && ( $isend ) ) { // increment by one day, compute date to cover leap years etc.
262
			$dv = SMWDataValueFactory::newTypeIDValue( '_dat', $dv->getWikiValue() . 'T00:00:00-24:00' );
263
		}
264
265 2
		$month = $dv->getMonth();
266 2
		if ( strlen( $month ) == 1 ) $month = '0' . $month;
267
268 2
		$day = $dv->getDay();
269 2
		if ( strlen( $day ) == 1 ) $day = '0' . $day;
270
271 2
		$result = $year . $month . $day;
272
273 2
		if ( $time != false ) $result .= "T$time";
274
275 2
		return $result;
276
	}
277
278
	/**
279
	 * Implements esaping of special characters for iCalendar properties of type TEXT. This is defined
280
	 * in RFC2445 Section 4.3.11.
281
	 */
282 3
	static private function escapeICalendarText( $text ) {
283
		// Note that \\ is a PHP escaped single \ here
284 3
		return str_replace( [ "\\", "\n", ";", "," ], [ "\\\\", "\\n", "\\;", "\\," ], $text );
285
	}
286
287
	/**
288
	 * @see SMWResultPrinter::getParamDefinitions
289
	 *
290
	 * @since 1.8
291
	 *
292
	 * @param $definitions array of IParamDefinition
293
	 *
294
	 * @return array of IParamDefinition|array
295
	 */
296 3
	public function getParamDefinitions( array $definitions ) {
297 3
		$params = parent::getParamDefinitions( $definitions );
298
299 3
		$params['title'] = [
300
			'default' => '',
301
			'message' => 'srf_paramdesc_icalendartitle',
302
		];
303
304 3
		$params['description'] = [
305
			'default' => '',
306
			'message' => 'srf_paramdesc_icalendardescription',
307
		];
308
309 3
		$params['timezone'] = [
310
			'default' => '',
311
			'message' => 'srf-paramdesc-icalendar-timezone',
312
		];
313
314 3
		return $params;
315
	}
316
317
}
318