Completed
Push — master ( c6c53b...6ca4bd )
by mw
06:55
created

SRFiCalendar   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 290
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 80.48%

Importance

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