Completed
Push — master ( 73fc3a...671515 )
by Mark
02:16 queued 02:15
created
action.php 1 patch
Indentation   +412 added lines, -412 removed lines patch added patch discarded remove patch
@@ -25,416 +25,416 @@
 block discarded – undo
25 25
  */
26 26
 class action_plugin_spatialhelper extends DokuWiki_Action_Plugin {
27 27
 
28
-    /**
29
-     * Register for events.
30
-     *
31
-     * @param Doku_Event_Handler $controller
32
-     *          DokuWiki's event controller object. Also available as global $EVENT_HANDLER
33
-     */
34
-    public function register(Doku_Event_Handler $controller): void {
35
-        // listen for page add / delete events
36
-        // http://www.dokuwiki.org/devel:event:indexer_page_add
37
-        $controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, 'handleIndexerPageAdd');
38
-        $controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'removeFromIndex');
39
-
40
-        // http://www.dokuwiki.org/devel:event:sitemap_generate
41
-        $controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSitemapGenerateBefore');
42
-        // using after will only trigger us if a sitemap was actually created
43
-        $controller->register_hook('SITEMAP_GENERATE', 'AFTER', $this, 'handleSitemapGenerateAfter');
44
-
45
-        // handle actions we know of
46
-        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleActionActPreprocess', array());
47
-        // handle HTML eg. /dokuwiki/doku.php?id=start&do=findnearby&geohash=u15vk4
48
-        $controller->register_hook(
49
-            'TPL_ACT_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
50
-                                 'format' => 'HTML'
51
-                             )
52
-        );
53
-        // handles AJAX/json eg: jQuery.post("/dokuwiki/lib/exe/ajax.php?id=start&call=findnearby&geohash=u15vk4");
54
-        $controller->register_hook(
55
-            'AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
56
-                                   'format' => 'JSON'
57
-                               )
58
-        );
59
-
60
-        // listen for media uploads and deletes
61
-        $controller->register_hook('MEDIA_UPLOAD_FINISH', 'BEFORE', $this, 'handleMediaUploaded', array());
62
-        $controller->register_hook('MEDIA_DELETE_FILE', 'BEFORE', $this, 'handleMediaDeleted', array());
63
-
64
-        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleMetaheaderOutput');
65
-        $controller->register_hook('PLUGIN_POPULARITY_DATA_SETUP', 'AFTER', $this, 'popularity');
66
-    }
67
-
68
-    /**
69
-     * Update the spatial index for the page.
70
-     *
71
-     * @param Doku_Event $event
72
-     *          event object
73
-     * @param mixed      $param
74
-     *          the parameters passed to register_hook when this handler was registered
75
-     */
76
-    public function handleIndexerPageAdd(Doku_Event $event, $param): void {
77
-        // $event→data['page'] – the page id
78
-        // $event→data['body'] – empty, can be filled by additional content to index by your plugin
79
-        // $event→data['metadata'] – the metadata that shall be indexed. This is an array where the keys are the
80
-        //    metadata indexes and the value a string or an array of strings with the values.
81
-        //    title and relation_references will already be set.
82
-        $id      = $event->data ['page'];
83
-        $indexer = plugin_load('helper', 'spatialhelper_index');
84
-        $entries = $indexer->updateSpatialIndex($id);
85
-    }
86
-
87
-    /**
88
-     * Update the spatial index, removing the page.
89
-     *
90
-     * @param Doku_Event $event
91
-     *          event object
92
-     * @param mixed      $param
93
-     *          the parameters passed to register_hook when this handler was registered
94
-     */
95
-    public function removeFromIndex(Doku_Event $event, $param): void {
96
-        // event data:
97
-        // $data[0] – The raw arguments for io_saveFile as an array. Do not change file path.
98
-        // $data[0][0] – the file path.
99
-        // $data[0][1] – the content to be saved, and may be modified.
100
-        // $data[1] – ns: The colon separated namespace path minus the trailing page name. (false if root ns)
101
-        // $data[2] – page_name: The wiki page name.
102
-        // $data[3] – rev: The page revision, false for current wiki pages.
103
-
104
-        dbglog($event->data, "Event data in removeFromIndex.");
105
-        if(@file_exists($event->data [0] [0])) {
106
-            // file not new
107
-            if(!$event->data [0] [1]) {
108
-                // file is empty, page is being deleted
109
-                if(empty ($event->data [1])) {
110
-                    // root namespace
111
-                    $id = $event->data [2];
112
-                } else {
113
-                    $id = $event->data [1] . ":" . $event->data [2];
114
-                }
115
-                $indexer = plugin_load('helper', 'spatialhelper_index');
116
-                if($indexer) {
117
-                    $indexer->deleteFromIndex($id);
118
-                }
119
-            }
120
-        }
121
-    }
122
-
123
-    /**
124
-     * Add a new SitemapItem object that points to the KML of public geocoded pages.
125
-     *
126
-     * @param Doku_Event $event
127
-     * @param mixed      $param
128
-     */
129
-    public function handleSitemapGenerateBefore(Doku_Event $event, $param): void {
130
-        $path                     = mediaFN($this->getConf('media_kml'));
131
-        $lastmod                  = @filemtime($path);
132
-        $event->data ['items'] [] = new Item(ml($this->getConf('media_kml'), '', true, '&', true), $lastmod);
133
-        //dbglog($event->data ['items'],
134
-        //  "Added a new SitemapItem object that points to the KML of public geocoded pages.");
135
-    }
136
-
137
-    /**
138
-     * Create a spatial sitemap or attach the geo/kml map to the sitemap.
139
-     *
140
-     * @param Doku_Event $event
141
-     *          event object, not used
142
-     * @param mixed      $param
143
-     *          parameter array, not used
144
-     */
145
-    public function handleSitemapGenerateAfter(Doku_Event $event, $param): bool {
146
-        // $event→data['items']: Array of SitemapItem instances, the array of sitemap items that already
147
-        //      contains all public pages of the wiki
148
-        // $event→data['sitemap']: The path of the file the sitemap will be saved to.
149
-        if($helper = plugin_load('helper', 'spatialhelper_sitemap')) {
150
-            // dbglog($helper, "createSpatialSitemap loaded helper.");
151
-
152
-            $kml = $helper->createKMLSitemap($this->getConf('media_kml'));
153
-            $rss = $helper->createGeoRSSSitemap($this->getConf('media_georss'));
154
-
155
-            if(!empty ($this->getConf('sitemap_namespaces'))) {
156
-                $namespaces = array_map('trim', explode("\n", $this->getConf('sitemap_namespaces')));
157
-                foreach($namespaces as $namespace) {
158
-                    $kmlN = $helper->createKMLSitemap($namespace . $this->getConf('media_kml'));
159
-                    $rssN = $helper->createGeoRSSSitemap($namespace . $this->getConf('media_georss'));
160
-                    dbglog(
161
-                        $kmlN && $rssN,
162
-                        "handleSitemapGenerateAfter, created KML / GeoRSS sitemap in $namespace, succes: "
163
-                    );
164
-                }
165
-            }
166
-            return $kml && $rss;
167
-        } else {
168
-            dbglog($helper, "createSpatialSitemap NOT loaded helper.");
169
-        }
170
-    }
171
-
172
-    /**
173
-     * trap findnearby action.
174
-     * This addional handler is required as described at: https://www.dokuwiki.org/devel:event:tpl_act_unknown
175
-     *
176
-     * @param Doku_Event $event
177
-     *          event object
178
-     * @param mixed      $param
179
-     *          not used
180
-     */
181
-    public function handleActionActPreprocess(Doku_Event $event, $param): void {
182
-        if($event->data !== 'findnearby') {
183
-            return;
184
-        }
185
-        $event->preventDefault();
186
-    }
187
-
188
-    /**
189
-     * handle findnearby action.
190
-     *
191
-     * @param Doku_Event $event
192
-     *          event object
193
-     * @param mixed      $param
194
-     *          associative array with keys
195
-     *          'format'=> HTML | JSON
196
-     */
197
-    public function findnearby(Doku_Event $event, $param): void {
198
-        if($event->data !== 'findnearby') {
199
-            return;
200
-        }
201
-        $event->preventDefault();
202
-        $results = array();
203
-        global $INPUT;
204
-        if($helper = plugin_load('helper', 'spatialhelper_search')) {
205
-            if($INPUT->has('lat') && $INPUT->has('lon')) {
206
-                $results = $helper->findNearbyLatLon($INPUT->param('lat'), $INPUT->param('lon'));
207
-            } elseif($INPUT->has('geohash')) {
208
-                $results = $helper->findNearby($INPUT->str('geohash'));
209
-            } else {
210
-                $results = array(
211
-                    'error' => hsc($this->getLang('invalidinput'))
212
-                );
213
-            }
214
-        }
215
-
216
-        $showMedia = $INPUT->bool('showMedia', true);
217
-
218
-        switch($param['format']) {
219
-            case 'JSON' :
220
-                $this->printJSON($results);
221
-                break;
222
-            case 'HTML' :
223
-                // fall through to default
224
-            default :
225
-                $this->printHTML($results, $showMedia);
226
-                break;
227
-        }
228
-    }
229
-
230
-    /**
231
-     * Print seachresults as HTML lists.
232
-     *
233
-     * @param array $searchresults
234
-     */
235
-    private function printJSON(array $searchresults): void {
236
-        require_once DOKU_INC . 'inc/JSON.php';
237
-        $json = new JSON();
238
-        header('Content-Type: application/json');
239
-        print $json->encode($searchresults);
240
-    }
241
-
242
-    /**
243
-     * Print seachresults as HTML lists.
244
-     *
245
-     * @param array $searchresults
246
-     * @param bool  $showMedia
247
-     */
248
-    private function printHTML(array $searchresults, bool $showMedia = true): void {
249
-        $pages   = (array) ($searchresults ['pages']);
250
-        $media   = (array) $searchresults ['media'];
251
-        $lat     = (float) $searchresults ['lat'];
252
-        $lon     = (float) $searchresults ['lon'];
253
-        $geohash = (string) $searchresults ['geohash'];
254
-
255
-        if(isset ($searchresults ['error'])) {
256
-            print '<div class="level1"><p>' . hsc($searchresults ['error']) . '</p></div>';
257
-            return;
258
-        }
259
-
260
-        // print a HTML list
261
-        print '<h1>' . $this->getLang('results_header') . '</h1>' . DOKU_LF;
262
-        print '<div class="level1">' . DOKU_LF;
263
-        if(!empty ($pages)) {
264
-            $pagelist = '<ol>' . DOKU_LF;
265
-            foreach($pages as $page) {
266
-                $pagelist .= '<li>' . html_wikilink(
267
-                        ':' . $page ['id'], useHeading('navigation') ? null :
268
-                        noNS($page ['id'])
269
-                    ) . ' (' . $this->getLang('results_distance_prefix')
270
-                    . $page ['distance'] . '&nbsp;m) ' . $page ['description'] . '</li>' . DOKU_LF;
271
-            }
272
-            $pagelist .= '</ol>' . DOKU_LF;
273
-
274
-            print '<h2>' . $this->getLang('results_pages') . hsc(
275
-                    ' lat;lon: ' . $lat . ';' . $lon
276
-                    . ' (geohash: ' . $geohash . ')'
277
-                ) . '</h2>';
278
-            print '<div class="level2">' . DOKU_LF;
279
-            print $pagelist;
280
-            print '</div>' . DOKU_LF;
281
-        } else {
282
-            print '<p>' . hsc($this->getLang('nothingfound')) . '</p>';
283
-        }
284
-
285
-        if(!empty ($media) && $showMedia) {
286
-            $pagelist = '<ol>' . DOKU_LF;
287
-            foreach($media as $m) {
288
-                $opts       = array();
289
-                $link       = ml($m ['id'], $opts, false, '&amp;', false);
290
-                $opts ['w'] = '100';
291
-                $src        = ml($m ['id'], $opts);
292
-                $pagelist   .= '<li><a href="' . $link . '"><img src="' . $src . '"></a> ('
293
-                    . $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . hsc($desc)
294
-                    . '</li>' . DOKU_LF;
295
-            }
296
-            $pagelist .= '</ol>' . DOKU_LF;
297
-
298
-            print '<h2>' . $this->getLang('results_media') . hsc(
299
-                    ' lat;lon: ' . $lat . ';' . $lon
300
-                    . ' (geohash: ' . $geohash . ')'
301
-                ) . '</h2>' . DOKU_LF;
302
-            print '<div class="level2">' . DOKU_LF;
303
-            print $pagelist;
304
-            print '</div>' . DOKU_LF;
305
-        }
306
-        print '<p>' . $this->getLang('results_precision') . $searchresults ['precision'] . ' m. ';
307
-        if(strlen($geohash) > 1) {
308
-            $url = wl(
309
-                getID(), array(
310
-                           'do'      => 'findnearby',
311
-                           'geohash' => substr($geohash, 0, -1)
312
-                       )
313
-            );
314
-            print '<a href="' . $url . '" class="findnearby">' . $this->getLang('search_largerarea') . '</a>.</p>'
315
-                . DOKU_LF;
316
-        }
317
-        print '</div>' . DOKU_LF;
318
-    }
319
-
320
-    /**
321
-     * add media to spatial index.
322
-     *
323
-     * @param Doku_Event $event
324
-     * @param mixed      $param
325
-     */
326
-    public function handleMediaUploaded(Doku_Event $event, $param): void {
327
-        // data[0] temporary file name (read from $_FILES)
328
-        // data[1] file name of the file being uploaded
329
-        // data[2] future directory id of the file being uploaded
330
-        // data[3] the mime type of the file being uploaded
331
-        // data[4] true if the uploaded file exists already
332
-        // data[5] (since 2011-02-06) the PHP function used to move the file to the correct location
333
-
334
-        dbglog($event->data, "handleMediaUploaded::event data");
335
-
336
-        // check the list of mimetypes
337
-        // if it's a supported type call appropriate index function
338
-        if(substr_compare($event->data [3], 'image/jpeg', 0)) {
339
-            $indexer = plugin_load('helper', 'spatialhelper_index');
340
-            if($indexer) {
341
-                $indexer->indexImage($event->data [2], $event->data [1]);
342
-            }
343
-        }
344
-        // TODO add image/tiff
345
-        // TODO kml, gpx, geojson...
346
-    }
347
-
348
-    /**
349
-     * removes the media from the index.
350
-     */
351
-    public function handleMediaDeleted(Doku_Event $event, $param): void {
352
-        // data['id'] ID data['unl'] unlink return code
353
-        // data['del'] Namespace directory unlink return code
354
-        // data['name'] file name data['path'] full path to the file
355
-        // data['size'] file size
356
-
357
-        dbglog($event->data, "handleMediaDeleted::event data");
358
-
359
-        // remove the media id from the index
360
-        $indexer = plugin_load('helper', 'spatialhelper_index');
361
-        if($indexer) {
362
-            $indexer->deleteFromIndex('media__' . $event->data ['id']);
363
-        }
364
-    }
365
-
366
-    /**
367
-     * add a link to the spatial sitemap files in the header.
368
-     *
369
-     * @param Doku_Event $event
370
-     *          the DokuWiki event. $event->data is a two-dimensional
371
-     *          array of all meta headers. The keys are meta, link and script.
372
-     * @param mixed      $param
373
-     *
374
-     * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
375
-     */
376
-    public function handleMetaheaderOutput(Doku_Event $event, $param): void {
377
-        // TODO maybe test for exist
378
-        $event->data ["link"] [] = array(
379
-            "type"  => "application/atom+xml",
380
-            "rel"   => "alternate",
381
-            "href"  => ml($this->getConf('media_georss')),
382
-            "title" => "Spatial ATOM Feed"
383
-        );
384
-        $event->data ["link"] [] = array(
385
-            "type"  => "application/vnd.google-earth.kml+xml",
386
-            "rel"   => "alternate",
387
-            "href"  => ml($this->getConf('media_kml')),
388
-            "title" => "KML Sitemap"
389
-        );
390
-    }
391
-
392
-    /**
393
-     * Add spatialhelper popularity data.
394
-     *
395
-     * @param Doku_Event $event
396
-     *          the DokuWiki event
397
-     */
398
-    final public function popularity(Doku_Event $event): void {
399
-        global $updateVersion;
400
-        $plugin_info                                     = $this->getInfo();
401
-        $event->data['spatialhelper']['version']         = $plugin_info['date'];
402
-        $event->data['spatialhelper']['dwversion']       = $updateVersion;
403
-        $event->data['spatialhelper']['combinedversion'] = $updateVersion . '_' . $plugin_info['date'];
404
-    }
405
-
406
-    /**
407
-     * Calculate a new coordinate based on start, distance and bearing
408
-     *
409
-     * @param $start array
410
-     *               - start coordinate as decimal lat/lon pair
411
-     * @param $dist  float
412
-     *               - distance in kilometers
413
-     * @param $brng  float
414
-     *               - bearing in degrees (compass direction)
415
-     */
416
-    private function geoDestination(array $start, float $dist, float $brng): array {
417
-        $lat1 = $this->toRad($start [0]);
418
-        $lon1 = $this->toRad($start [1]);
419
-        // http://en.wikipedia.org/wiki/Earth_radius
420
-        // average earth radius in km
421
-        $dist = $dist / 6371.01;
422
-        $brng = $this->toRad($brng);
423
-
424
-        $lon2 = $lon1 + atan2(sin($brng) * sin($dist) * cos($lat1), cos($dist) - sin($lat1) * sin($lat2));
425
-        $lon2 = fmod(($lon2 + 3 * M_PI), (2 * M_PI)) - M_PI;
426
-
427
-        return array(
428
-            $this->toDeg($lat2),
429
-            $this->toDeg($lon2)
430
-        );
431
-    }
432
-
433
-    private function toRad(float $deg): float {
434
-        return $deg * M_PI / 180;
435
-    }
436
-
437
-    private function toDeg(float $rad): float {
438
-        return $rad * 180 / M_PI;
439
-    }
28
+	/**
29
+	 * Register for events.
30
+	 *
31
+	 * @param Doku_Event_Handler $controller
32
+	 *          DokuWiki's event controller object. Also available as global $EVENT_HANDLER
33
+	 */
34
+	public function register(Doku_Event_Handler $controller): void {
35
+		// listen for page add / delete events
36
+		// http://www.dokuwiki.org/devel:event:indexer_page_add
37
+		$controller->register_hook('INDEXER_PAGE_ADD', 'BEFORE', $this, 'handleIndexerPageAdd');
38
+		$controller->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'removeFromIndex');
39
+
40
+		// http://www.dokuwiki.org/devel:event:sitemap_generate
41
+		$controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSitemapGenerateBefore');
42
+		// using after will only trigger us if a sitemap was actually created
43
+		$controller->register_hook('SITEMAP_GENERATE', 'AFTER', $this, 'handleSitemapGenerateAfter');
44
+
45
+		// handle actions we know of
46
+		$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleActionActPreprocess', array());
47
+		// handle HTML eg. /dokuwiki/doku.php?id=start&do=findnearby&geohash=u15vk4
48
+		$controller->register_hook(
49
+			'TPL_ACT_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
50
+								 'format' => 'HTML'
51
+							 )
52
+		);
53
+		// handles AJAX/json eg: jQuery.post("/dokuwiki/lib/exe/ajax.php?id=start&call=findnearby&geohash=u15vk4");
54
+		$controller->register_hook(
55
+			'AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'findnearby', array(
56
+								   'format' => 'JSON'
57
+							   )
58
+		);
59
+
60
+		// listen for media uploads and deletes
61
+		$controller->register_hook('MEDIA_UPLOAD_FINISH', 'BEFORE', $this, 'handleMediaUploaded', array());
62
+		$controller->register_hook('MEDIA_DELETE_FILE', 'BEFORE', $this, 'handleMediaDeleted', array());
63
+
64
+		$controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleMetaheaderOutput');
65
+		$controller->register_hook('PLUGIN_POPULARITY_DATA_SETUP', 'AFTER', $this, 'popularity');
66
+	}
67
+
68
+	/**
69
+	 * Update the spatial index for the page.
70
+	 *
71
+	 * @param Doku_Event $event
72
+	 *          event object
73
+	 * @param mixed      $param
74
+	 *          the parameters passed to register_hook when this handler was registered
75
+	 */
76
+	public function handleIndexerPageAdd(Doku_Event $event, $param): void {
77
+		// $event→data['page'] – the page id
78
+		// $event→data['body'] – empty, can be filled by additional content to index by your plugin
79
+		// $event→data['metadata'] – the metadata that shall be indexed. This is an array where the keys are the
80
+		//    metadata indexes and the value a string or an array of strings with the values.
81
+		//    title and relation_references will already be set.
82
+		$id      = $event->data ['page'];
83
+		$indexer = plugin_load('helper', 'spatialhelper_index');
84
+		$entries = $indexer->updateSpatialIndex($id);
85
+	}
86
+
87
+	/**
88
+	 * Update the spatial index, removing the page.
89
+	 *
90
+	 * @param Doku_Event $event
91
+	 *          event object
92
+	 * @param mixed      $param
93
+	 *          the parameters passed to register_hook when this handler was registered
94
+	 */
95
+	public function removeFromIndex(Doku_Event $event, $param): void {
96
+		// event data:
97
+		// $data[0] – The raw arguments for io_saveFile as an array. Do not change file path.
98
+		// $data[0][0] – the file path.
99
+		// $data[0][1] – the content to be saved, and may be modified.
100
+		// $data[1] – ns: The colon separated namespace path minus the trailing page name. (false if root ns)
101
+		// $data[2] – page_name: The wiki page name.
102
+		// $data[3] – rev: The page revision, false for current wiki pages.
103
+
104
+		dbglog($event->data, "Event data in removeFromIndex.");
105
+		if(@file_exists($event->data [0] [0])) {
106
+			// file not new
107
+			if(!$event->data [0] [1]) {
108
+				// file is empty, page is being deleted
109
+				if(empty ($event->data [1])) {
110
+					// root namespace
111
+					$id = $event->data [2];
112
+				} else {
113
+					$id = $event->data [1] . ":" . $event->data [2];
114
+				}
115
+				$indexer = plugin_load('helper', 'spatialhelper_index');
116
+				if($indexer) {
117
+					$indexer->deleteFromIndex($id);
118
+				}
119
+			}
120
+		}
121
+	}
122
+
123
+	/**
124
+	 * Add a new SitemapItem object that points to the KML of public geocoded pages.
125
+	 *
126
+	 * @param Doku_Event $event
127
+	 * @param mixed      $param
128
+	 */
129
+	public function handleSitemapGenerateBefore(Doku_Event $event, $param): void {
130
+		$path                     = mediaFN($this->getConf('media_kml'));
131
+		$lastmod                  = @filemtime($path);
132
+		$event->data ['items'] [] = new Item(ml($this->getConf('media_kml'), '', true, '&amp;', true), $lastmod);
133
+		//dbglog($event->data ['items'],
134
+		//  "Added a new SitemapItem object that points to the KML of public geocoded pages.");
135
+	}
136
+
137
+	/**
138
+	 * Create a spatial sitemap or attach the geo/kml map to the sitemap.
139
+	 *
140
+	 * @param Doku_Event $event
141
+	 *          event object, not used
142
+	 * @param mixed      $param
143
+	 *          parameter array, not used
144
+	 */
145
+	public function handleSitemapGenerateAfter(Doku_Event $event, $param): bool {
146
+		// $event→data['items']: Array of SitemapItem instances, the array of sitemap items that already
147
+		//      contains all public pages of the wiki
148
+		// $event→data['sitemap']: The path of the file the sitemap will be saved to.
149
+		if($helper = plugin_load('helper', 'spatialhelper_sitemap')) {
150
+			// dbglog($helper, "createSpatialSitemap loaded helper.");
151
+
152
+			$kml = $helper->createKMLSitemap($this->getConf('media_kml'));
153
+			$rss = $helper->createGeoRSSSitemap($this->getConf('media_georss'));
154
+
155
+			if(!empty ($this->getConf('sitemap_namespaces'))) {
156
+				$namespaces = array_map('trim', explode("\n", $this->getConf('sitemap_namespaces')));
157
+				foreach($namespaces as $namespace) {
158
+					$kmlN = $helper->createKMLSitemap($namespace . $this->getConf('media_kml'));
159
+					$rssN = $helper->createGeoRSSSitemap($namespace . $this->getConf('media_georss'));
160
+					dbglog(
161
+						$kmlN && $rssN,
162
+						"handleSitemapGenerateAfter, created KML / GeoRSS sitemap in $namespace, succes: "
163
+					);
164
+				}
165
+			}
166
+			return $kml && $rss;
167
+		} else {
168
+			dbglog($helper, "createSpatialSitemap NOT loaded helper.");
169
+		}
170
+	}
171
+
172
+	/**
173
+	 * trap findnearby action.
174
+	 * This addional handler is required as described at: https://www.dokuwiki.org/devel:event:tpl_act_unknown
175
+	 *
176
+	 * @param Doku_Event $event
177
+	 *          event object
178
+	 * @param mixed      $param
179
+	 *          not used
180
+	 */
181
+	public function handleActionActPreprocess(Doku_Event $event, $param): void {
182
+		if($event->data !== 'findnearby') {
183
+			return;
184
+		}
185
+		$event->preventDefault();
186
+	}
187
+
188
+	/**
189
+	 * handle findnearby action.
190
+	 *
191
+	 * @param Doku_Event $event
192
+	 *          event object
193
+	 * @param mixed      $param
194
+	 *          associative array with keys
195
+	 *          'format'=> HTML | JSON
196
+	 */
197
+	public function findnearby(Doku_Event $event, $param): void {
198
+		if($event->data !== 'findnearby') {
199
+			return;
200
+		}
201
+		$event->preventDefault();
202
+		$results = array();
203
+		global $INPUT;
204
+		if($helper = plugin_load('helper', 'spatialhelper_search')) {
205
+			if($INPUT->has('lat') && $INPUT->has('lon')) {
206
+				$results = $helper->findNearbyLatLon($INPUT->param('lat'), $INPUT->param('lon'));
207
+			} elseif($INPUT->has('geohash')) {
208
+				$results = $helper->findNearby($INPUT->str('geohash'));
209
+			} else {
210
+				$results = array(
211
+					'error' => hsc($this->getLang('invalidinput'))
212
+				);
213
+			}
214
+		}
215
+
216
+		$showMedia = $INPUT->bool('showMedia', true);
217
+
218
+		switch($param['format']) {
219
+			case 'JSON' :
220
+				$this->printJSON($results);
221
+				break;
222
+			case 'HTML' :
223
+				// fall through to default
224
+			default :
225
+				$this->printHTML($results, $showMedia);
226
+				break;
227
+		}
228
+	}
229
+
230
+	/**
231
+	 * Print seachresults as HTML lists.
232
+	 *
233
+	 * @param array $searchresults
234
+	 */
235
+	private function printJSON(array $searchresults): void {
236
+		require_once DOKU_INC . 'inc/JSON.php';
237
+		$json = new JSON();
238
+		header('Content-Type: application/json');
239
+		print $json->encode($searchresults);
240
+	}
241
+
242
+	/**
243
+	 * Print seachresults as HTML lists.
244
+	 *
245
+	 * @param array $searchresults
246
+	 * @param bool  $showMedia
247
+	 */
248
+	private function printHTML(array $searchresults, bool $showMedia = true): void {
249
+		$pages   = (array) ($searchresults ['pages']);
250
+		$media   = (array) $searchresults ['media'];
251
+		$lat     = (float) $searchresults ['lat'];
252
+		$lon     = (float) $searchresults ['lon'];
253
+		$geohash = (string) $searchresults ['geohash'];
254
+
255
+		if(isset ($searchresults ['error'])) {
256
+			print '<div class="level1"><p>' . hsc($searchresults ['error']) . '</p></div>';
257
+			return;
258
+		}
259
+
260
+		// print a HTML list
261
+		print '<h1>' . $this->getLang('results_header') . '</h1>' . DOKU_LF;
262
+		print '<div class="level1">' . DOKU_LF;
263
+		if(!empty ($pages)) {
264
+			$pagelist = '<ol>' . DOKU_LF;
265
+			foreach($pages as $page) {
266
+				$pagelist .= '<li>' . html_wikilink(
267
+						':' . $page ['id'], useHeading('navigation') ? null :
268
+						noNS($page ['id'])
269
+					) . ' (' . $this->getLang('results_distance_prefix')
270
+					. $page ['distance'] . '&nbsp;m) ' . $page ['description'] . '</li>' . DOKU_LF;
271
+			}
272
+			$pagelist .= '</ol>' . DOKU_LF;
273
+
274
+			print '<h2>' . $this->getLang('results_pages') . hsc(
275
+					' lat;lon: ' . $lat . ';' . $lon
276
+					. ' (geohash: ' . $geohash . ')'
277
+				) . '</h2>';
278
+			print '<div class="level2">' . DOKU_LF;
279
+			print $pagelist;
280
+			print '</div>' . DOKU_LF;
281
+		} else {
282
+			print '<p>' . hsc($this->getLang('nothingfound')) . '</p>';
283
+		}
284
+
285
+		if(!empty ($media) && $showMedia) {
286
+			$pagelist = '<ol>' . DOKU_LF;
287
+			foreach($media as $m) {
288
+				$opts       = array();
289
+				$link       = ml($m ['id'], $opts, false, '&amp;', false);
290
+				$opts ['w'] = '100';
291
+				$src        = ml($m ['id'], $opts);
292
+				$pagelist   .= '<li><a href="' . $link . '"><img src="' . $src . '"></a> ('
293
+					. $this->getLang('results_distance_prefix') . $page ['distance'] . '&nbsp;m) ' . hsc($desc)
294
+					. '</li>' . DOKU_LF;
295
+			}
296
+			$pagelist .= '</ol>' . DOKU_LF;
297
+
298
+			print '<h2>' . $this->getLang('results_media') . hsc(
299
+					' lat;lon: ' . $lat . ';' . $lon
300
+					. ' (geohash: ' . $geohash . ')'
301
+				) . '</h2>' . DOKU_LF;
302
+			print '<div class="level2">' . DOKU_LF;
303
+			print $pagelist;
304
+			print '</div>' . DOKU_LF;
305
+		}
306
+		print '<p>' . $this->getLang('results_precision') . $searchresults ['precision'] . ' m. ';
307
+		if(strlen($geohash) > 1) {
308
+			$url = wl(
309
+				getID(), array(
310
+						   'do'      => 'findnearby',
311
+						   'geohash' => substr($geohash, 0, -1)
312
+					   )
313
+			);
314
+			print '<a href="' . $url . '" class="findnearby">' . $this->getLang('search_largerarea') . '</a>.</p>'
315
+				. DOKU_LF;
316
+		}
317
+		print '</div>' . DOKU_LF;
318
+	}
319
+
320
+	/**
321
+	 * add media to spatial index.
322
+	 *
323
+	 * @param Doku_Event $event
324
+	 * @param mixed      $param
325
+	 */
326
+	public function handleMediaUploaded(Doku_Event $event, $param): void {
327
+		// data[0] temporary file name (read from $_FILES)
328
+		// data[1] file name of the file being uploaded
329
+		// data[2] future directory id of the file being uploaded
330
+		// data[3] the mime type of the file being uploaded
331
+		// data[4] true if the uploaded file exists already
332
+		// data[5] (since 2011-02-06) the PHP function used to move the file to the correct location
333
+
334
+		dbglog($event->data, "handleMediaUploaded::event data");
335
+
336
+		// check the list of mimetypes
337
+		// if it's a supported type call appropriate index function
338
+		if(substr_compare($event->data [3], 'image/jpeg', 0)) {
339
+			$indexer = plugin_load('helper', 'spatialhelper_index');
340
+			if($indexer) {
341
+				$indexer->indexImage($event->data [2], $event->data [1]);
342
+			}
343
+		}
344
+		// TODO add image/tiff
345
+		// TODO kml, gpx, geojson...
346
+	}
347
+
348
+	/**
349
+	 * removes the media from the index.
350
+	 */
351
+	public function handleMediaDeleted(Doku_Event $event, $param): void {
352
+		// data['id'] ID data['unl'] unlink return code
353
+		// data['del'] Namespace directory unlink return code
354
+		// data['name'] file name data['path'] full path to the file
355
+		// data['size'] file size
356
+
357
+		dbglog($event->data, "handleMediaDeleted::event data");
358
+
359
+		// remove the media id from the index
360
+		$indexer = plugin_load('helper', 'spatialhelper_index');
361
+		if($indexer) {
362
+			$indexer->deleteFromIndex('media__' . $event->data ['id']);
363
+		}
364
+	}
365
+
366
+	/**
367
+	 * add a link to the spatial sitemap files in the header.
368
+	 *
369
+	 * @param Doku_Event $event
370
+	 *          the DokuWiki event. $event->data is a two-dimensional
371
+	 *          array of all meta headers. The keys are meta, link and script.
372
+	 * @param mixed      $param
373
+	 *
374
+	 * @see http://www.dokuwiki.org/devel:event:tpl_metaheader_output
375
+	 */
376
+	public function handleMetaheaderOutput(Doku_Event $event, $param): void {
377
+		// TODO maybe test for exist
378
+		$event->data ["link"] [] = array(
379
+			"type"  => "application/atom+xml",
380
+			"rel"   => "alternate",
381
+			"href"  => ml($this->getConf('media_georss')),
382
+			"title" => "Spatial ATOM Feed"
383
+		);
384
+		$event->data ["link"] [] = array(
385
+			"type"  => "application/vnd.google-earth.kml+xml",
386
+			"rel"   => "alternate",
387
+			"href"  => ml($this->getConf('media_kml')),
388
+			"title" => "KML Sitemap"
389
+		);
390
+	}
391
+
392
+	/**
393
+	 * Add spatialhelper popularity data.
394
+	 *
395
+	 * @param Doku_Event $event
396
+	 *          the DokuWiki event
397
+	 */
398
+	final public function popularity(Doku_Event $event): void {
399
+		global $updateVersion;
400
+		$plugin_info                                     = $this->getInfo();
401
+		$event->data['spatialhelper']['version']         = $plugin_info['date'];
402
+		$event->data['spatialhelper']['dwversion']       = $updateVersion;
403
+		$event->data['spatialhelper']['combinedversion'] = $updateVersion . '_' . $plugin_info['date'];
404
+	}
405
+
406
+	/**
407
+	 * Calculate a new coordinate based on start, distance and bearing
408
+	 *
409
+	 * @param $start array
410
+	 *               - start coordinate as decimal lat/lon pair
411
+	 * @param $dist  float
412
+	 *               - distance in kilometers
413
+	 * @param $brng  float
414
+	 *               - bearing in degrees (compass direction)
415
+	 */
416
+	private function geoDestination(array $start, float $dist, float $brng): array {
417
+		$lat1 = $this->toRad($start [0]);
418
+		$lon1 = $this->toRad($start [1]);
419
+		// http://en.wikipedia.org/wiki/Earth_radius
420
+		// average earth radius in km
421
+		$dist = $dist / 6371.01;
422
+		$brng = $this->toRad($brng);
423
+
424
+		$lon2 = $lon1 + atan2(sin($brng) * sin($dist) * cos($lat1), cos($dist) - sin($lat1) * sin($lat2));
425
+		$lon2 = fmod(($lon2 + 3 * M_PI), (2 * M_PI)) - M_PI;
426
+
427
+		return array(
428
+			$this->toDeg($lat2),
429
+			$this->toDeg($lon2)
430
+		);
431
+	}
432
+
433
+	private function toRad(float $deg): float {
434
+		return $deg * M_PI / 180;
435
+	}
436
+
437
+	private function toDeg(float $rad): float {
438
+		return $rad * 180 / M_PI;
439
+	}
440 440
 }
Please login to merge, or discard this patch.