Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
4.17% covered (danger)
4.17%
4 / 96
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Geocoders
4.17% covered (danger)
4.17%
4 / 96
0.00% covered (danger)
0.00%
0 / 5
1308.92
0.00% covered (danger)
0.00%
0 / 1
 getCoordinates
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
5.26
 performRequest
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCoordinatesUseGoogle
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
90
 getCoordinatesUseYandex
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
72
 getCoordinatesUseMapquestNominatim
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
272
1<?php
2namespace MultiMaps;
3
4use MediaWiki\MediaWikiServices;
5
6/**
7 * @file Geocoders.php
8 * @ingroup MultiMaps
9 * @author Pavel Astakhov <pastakhov@yandex.ru>
10 * @license GPL-2.0-or-later
11 */
12
13class Geocoders {
14
15    public static function getCoordinates( $address, $service, $params = null ) {
16        switch ( $service ) {
17            case 'google':
18                return self::getCoordinatesUseGoogle( $address );
19            case 'yandex':
20                return self::getCoordinatesUseYandex( $address );
21            case 'leaflet':
22                return self::getCoordinatesUseMapquestNominatim( $address, $params );
23        }
24        return false;
25    }
26
27    private static function performRequest( $url, $urlArgs ) {
28        return MediaWikiServices::getInstance()->getHttpRequestFactory()->get( $url . wfArrayToCgi( $urlArgs ) );
29    }
30
31    private static function getCoordinatesUseGoogle( $address ) {
32        $return = false;
33
34        $urlArgs = [
35            'sensor' => 'false',
36            'address' => $address,
37            ];
38        $response = self::performRequest( 'https://maps.googleapis.com/maps/api/geocode/json?', $urlArgs );
39
40        if ( $response !== null ) {
41            $data = \FormatJson::decode( $response );
42            if ( $data !== null ) {
43                if ( $data->status == 'OK' ) {
44                    $geometry = $data->results[0]->geometry;
45                    $location = $geometry->location;
46                    $lat = $location->lat;
47                    $lon = $location->lng;
48                    if ( $lat !== null && $lon !== null ) {
49                        $return = [ 'lat' => $lat, 'lon' => $lon ];
50                        $bounds = $geometry->bounds;
51                        if ( $bounds !== null ) {
52                            $bounds_ne = new Point( $bounds->northeast->lat, $bounds->northeast->lng );
53                            $bounds_sw = new Point( $bounds->southwest->lat, $bounds->southwest->lng );
54                            if ( $bounds_ne->isValid() && $bounds_sw->isValid() ) {
55                                $b = new Bounds( [ $bounds_ne, $bounds_sw ] );
56                                $return['bounds'] = $b;
57                            }
58                        }
59                    }
60                }
61            }
62        }
63        return $return;
64    }
65
66    private static function getCoordinatesUseYandex( $address ) {
67        $return = false;
68
69        $urlArgs = [
70            'format' => 'json',
71            'results' => '1',
72            'geocode' => $address,
73            ];
74        $response = self::performRequest( 'https://geocode-maps.yandex.ru/1.x/?', $urlArgs );
75
76        if ( $response !== null ) {
77            $data = \FormatJson::decode( $response );
78            if ( $data !== null ) {
79                $geoObjectCollection = $data->response->GeoObjectCollection;
80                if ( $geoObjectCollection->metaDataProperty->GeocoderResponseMetaData->found > 0 ) {
81                    $geoObject = $geoObjectCollection->featureMember[0]->GeoObject;
82                    [ $lon, $lat ] = explode( ' ', $geoObject->Point->pos );
83                    $point = new Point( $lat, $lon );
84                    if ( $point->isValid() ) {
85                        $return = $point->pos;
86                        $envelope = $geoObject->boundedBy->Envelope;
87                        if ( $envelope !== null ) {
88                            [ $lon, $lat ] = explode( ' ', $envelope->upperCorner );
89                            $bounds_ne = new Point( $lat, $lon );
90                            [ $lon, $lat ] = explode( ' ', $envelope->lowerCorner );
91                            $bounds_sw = new Point( $lat, $lon );
92                            if ( $bounds_ne->isValid() && $bounds_sw->isValid() ) {
93                                $b = new Bounds( [ $bounds_ne, $bounds_sw ] );
94                                $return['bounds'] = $b;
95                            }
96                        }
97                    }
98                }
99            }
100        }
101        return $return;
102    }
103
104    public static function getCoordinatesUseMapquestNominatim( $address, $params ) {
105        $return = false;
106        $param_polygon = ( isset( $params['polygon'] ) && $params['polygon'] === true ) ? true : false;
107
108        $urlArgs = [
109            'format' => 'json',
110            'addressdetails' => '0',
111            'limit' => 1,
112            'q' => $address,
113        ];
114        if ( $param_polygon ) {
115            $urlArgs['polygon'] = '1';
116        }
117        $response = self::performRequest( 'https://open.mapquestapi.com/nominatim/v1/search.php?', $urlArgs );
118
119        if ( $response !== null ) {
120            $data = \FormatJson::decode( $response );
121            if ( isset( $data[0] ) ) {
122                $data = $data[0];
123                $lat = $data->lat;
124                $lon = $data->lon;
125                if ( $lat !== null && $lon !== null ) {
126                    $return = [ 'lat' => $lat, 'lon' => $lon ];
127                    $bounds = $data->boundingbox;
128                    if ( $bounds !== null ) {
129                        $bounds_ne = new Point( $bounds[1], $bounds[3] );
130                        $bounds_sw = new Point( $bounds[0], $bounds[2] );
131                        if ( $bounds_ne->isValid() && $bounds_sw->isValid() ) {
132                            $b = new Bounds( [ $bounds_ne, $bounds_sw ] );
133                            $return['bounds'] = $b;
134                        }
135                    }
136                    if ( $param_polygon ) {
137                        $polygonpoints = $data->polygonpoints;
138                        if ( count( $polygonpoints ) > 1 ) {
139                            $points = [];
140                            foreach ( $polygonpoints as $value ) {
141                                $p = new Point( $value[1], $value[0] );
142                                if ( $p->isValid() ) {
143                                    $points[] = $p;
144                                }
145                            }
146                            if ( count( $points ) > 1 ) {
147                                $return['polygon'] = $points;
148                            }
149                        }
150                    }
151                }
152            }
153        }
154        return $return;
155    }
156
157}