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