Passed
Pull Request — master (#4)
by Mark
01:50
created

GoogleGeocode::read()   D

Complexity

Conditions 18
Paths 176

Size

Total Lines 58
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 40
nc 176
nop 5
dl 0
loc 58
rs 4.2333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace geoPHP\Adapter;
4
5
use geoPHP\Geometry\Geometry;
6
use geoPHP\Geometry\GeometryCollection;
7
use geoPHP\Geometry\Point;
0 ignored issues
show
Bug introduced by
The type geoPHP\Geometry\Point was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use geoPHP\Geometry\MultiPoint;
9
use geoPHP\Geometry\LineString;
10
use geoPHP\Geometry\Polygon;
11
use geoPHP\Geometry\MultiPolygon;
12
13
/*
14
 * (c) Camptocamp <[email protected]>
15
 * (c) Patrick Hayes
16
 *
17
 * This code is open-source and licenced under the Modified BSD License.
18
 * For the full copyright and license information, please view the LICENSE
19
 * file that was distributed with this source code.
20
 */
21
22
/**
23
 * PHP Google Geocoder Adapter
24
 *
25
 *
26
 * @package    geoPHP
27
 * @author     Patrick Hayes <[email protected]>
28
 */
29
class GoogleGeocode implements GeoAdapter
30
{
31
32
    /** @var \stdClass $result */
33
    protected $result;
34
35
    /**
36
     * Makes a geocoding (lat/lon lookup) with an address string or array geometry objects
37
     *
38
     * @param string|string[]     $address        Address to geocode
39
     * @param string              $apiKey         Your application's Google Maps Geocoding API key
40
     * @param string              $returnType     Type of Geometry to return. Can either be 'points' or 'bounds' (polygon)
41
     * @param array|bool|Geometry $bounds         Limit the search area to within this region.
42
     *        For example by default geocoding "Cairo" will return the location of Cairo Egypt.
43
     *        If you pass a polygon of Illinois, it will return Cairo IL.
44
     * @param boolean             $returnMultiple - Return all results in a multipoint or multipolygon
45
     *
46
     * @return Geometry|GeometryCollection
47
     * @throws \Exception If geocoding fails
48
     */
49
    public function read($address, $apiKey = null, $returnType = 'point', $bounds = false, $returnMultiple = false)
50
    {
51
        if (is_array($address)) {
52
            $address = join(',', $address);
53
        }
54
55
        if (gettype($bounds) == 'object') {
56
            $bounds = $bounds->getBBox();
57
        }
58
        if (gettype($bounds) == 'array') {
59
            $boundsString = '&bounds=' . $bounds['miny'] . ',' . $bounds['minx'] . '|' . $bounds['maxy'] . ',' . $bounds['maxx'];
60
        } else {
61
            $boundsString = '';
62
        }
63
64
        $url = "http://maps.googleapis.com/maps/api/geocode/json";
65
        $url .= '?address=' . urlencode($address);
66
        $url .= $boundsString . ($apiKey ? '&key=' . $apiKey : '');
67
        $this->result = json_decode(@file_get_contents($url));
0 ignored issues
show
Bug introduced by
It seems like @file_get_contents($url) can also be of type false; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

67
        $this->result = json_decode(/** @scrutinizer ignore-type */ @file_get_contents($url));
Loading history...
68
69
        if ($this->result->status == 'OK') {
70
            if (!$returnMultiple) {
71
                if ($returnType == 'point') {
72
                    return $this->getPoint();
73
                }
74
                if ($returnType == 'bounds' || $returnType == 'polygon') {
75
                    return $this->getPolygon();
76
                }
77
            } else {
78
                if ($returnType == 'point') {
79
                    $points = [];
80
                    foreach ($this->result->results as $delta => $item) {
81
                        $points[] = $this->getPoint($delta);
82
                    }
83
                    return new MultiPoint($points);
84
                }
85
                if ($returnType == 'bounds' || $returnType == 'polygon') {
86
                    $polygons = [];
87
                    foreach ($this->result->results as $delta => $item) {
88
                        $polygons[] = $this->getPolygon($delta);
89
                    }
90
                    return new MultiPolygon($polygons);
91
                }
92
            }
93
        } elseif ($this->result->status == 'ZERO_RESULTS') {
94
            return null;
95
        } else {
96
            if ($this->result->status) {
97
                throw new \Exception(
98
                    'Error in Google Reverse Geocoder: '
99
                        . $this->result->status
100
                    . (isset($this->result->error_message) ? '. ' . $this->result->error_message : '')
101
                );
102
            } else {
103
                throw new \Exception('Unknown error in Google Reverse Geocoder');
104
            }
105
        }
106
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type geoPHP\Geometry\Geometry...etry\GeometryCollection.
Loading history...
107
    }
108
109
    /**
110
     * Makes a Reverse Geocoding (address lookup) with the (center) point of Geometry
111
     * Detailed documentation of response values can be found in:
112
     *
113
     * @see https://developers.google.com/maps/documentation/geocoding/intro#ReverseGeocoding
114
     *
115
     * @param Geometry $geometry
116
     * @param string   $apiKey     Your application's Google Maps Geocoding API key
117
     * @param string   $returnType Should be either 'string' or 'array' or 'both'
118
     * @param string   $language   The language in which to return results. If not set, geocoder tries to use the native language of the domain.
119
     *
120
     * @return string|Object[]|null A formatted address or array of address components
121
     * @throws \Exception If geocoding fails
122
     */
123
    public function write(Geometry $geometry, $apiKey = null, $returnType = 'string', $language = null)
124
    {
125
        $centroid = $geometry->centroid();
126
        $lat = $centroid->y();
127
        $lon = $centroid->x();
128
129
        $url = "http://maps.googleapis.com/maps/api/geocode/json";
130
        /** @noinspection SpellCheckingInspection */
131
        $url .= '?latlng=' . $lat . ',' . $lon;
132
        $url .= ($language ? '&language=' . $language : '') . ($apiKey ? '&key=' . $apiKey : '');
133
134
        $this->result = json_decode(@file_get_contents($url));
0 ignored issues
show
Bug introduced by
It seems like @file_get_contents($url) can also be of type false; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
        $this->result = json_decode(/** @scrutinizer ignore-type */ @file_get_contents($url));
Loading history...
135
136
        if ($this->result->status == 'OK') {
137
            if ($returnType == 'string') {
138
                return $this->result->results[0]->formatted_address;
139
            } elseif ($returnType == 'array') {
140
                return $this->result->results[0]->address_components;
141
            } elseif ($returnType == 'full') {
142
                return $this->result->results[0];
143
            }
144
        } elseif ($this->result->status == 'ZERO_RESULTS') {
145
            if ($returnType == 'string') {
146
                return '';
147
            }
148
            if ($returnType == 'array') {
149
                return $this->result->results;
150
            }
151
        } else {
152
            if ($this->result->status) {
153
                throw new \Exception(
154
                    'Error in Google Reverse Geocoder: '
155
                        . $this->result->status
156
                    . (isset($this->result->error_message) ? '. ' . $this->result->error_message : '')
157
                );
158
            } else {
159
                throw new \Exception('Unknown error in Google Reverse Geocoder');
160
            }
161
        }
162
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array<mixed,object>|null|string.
Loading history...
163
    }
164
165
    private function getPoint($delta = 0)
166
    {
167
        $lat = $this->result->results[$delta]->geometry->location->lat;
168
        $lon = $this->result->results[$delta]->geometry->location->lng;
169
        return new Point($lon, $lat);
170
    }
171
172
    private function getPolygon($delta = 0)
173
    {
174
        $points = [
175
                $this->getTopLeft($delta),
176
                $this->getTopRight($delta),
177
                $this->getBottomRight($delta),
178
                $this->getBottomLeft($delta),
179
                $this->getTopLeft($delta),
180
        ];
181
        $outerRing = new LineString($points);
182
        return new Polygon([$outerRing]);
183
    }
184
185
    private function getTopLeft($delta = 0)
186
    {
187
        $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
188
        $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
189
        return new Point($lon, $lat);
190
    }
191
192
    private function getTopRight($delta = 0)
193
    {
194
        $lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
195
        $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
196
        return new Point($lon, $lat);
197
    }
198
199
    private function getBottomLeft($delta = 0)
200
    {
201
        $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
202
        $lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
203
        return new Point($lon, $lat);
204
    }
205
206
    private function getBottomRight($delta = 0)
207
    {
208
        $lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
209
        $lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
210
        return new Point($lon, $lat);
211
    }
212
}
213