Addok::geocodeQuery()   C
last analyzed

Complexity

Conditions 13
Paths 62

Size

Total Lines 58
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 13.0033

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 13
eloc 37
c 2
b 0
f 0
nc 62
nop 1
dl 0
loc 58
rs 6.6166
ccs 36
cts 37
cp 0.973
crap 13.0033

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
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Geocoder package.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT License
11
 */
12
13
namespace Geocoder\Provider\Addok;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\InvalidArgument;
17
use Geocoder\Exception\InvalidServerResponse;
18
use Geocoder\Exception\UnsupportedOperation;
19
use Geocoder\Http\Provider\AbstractHttpProvider;
20
use Geocoder\Model\Address;
21
use Geocoder\Model\AddressCollection;
22
use Geocoder\Provider\Provider;
23
use Geocoder\Query\GeocodeQuery;
24
use Geocoder\Query\ReverseQuery;
25
use Http\Client\HttpClient;
26
27
/**
28
 * @author Jonathan Beliën <[email protected]>
29
 */
30
final class Addok extends AbstractHttpProvider implements Provider
31
{
32
    const TYPE_HOUSENUMBER = 'housenumber';
33
    const TYPE_STREET = 'street';
34
    const TYPE_LOCALITY = 'locality';
35
    const TYPE_MUNICIPALITY = 'municipality';
36
37
    /**
38
     * @var string
39
     */
40
    private $rootUrl;
41
42
    /**
43
     * @param HttpClient  $client
44
     * @param string|null $locale
45
     *
46
     * @return Addok
47
     */
48 20
    public static function withBANServer(HttpClient $client)
49
    {
50 20
        return new self($client, 'https://api-adresse.data.gouv.fr');
51
    }
52
53
    /**
54
     * @param HttpClient $client  an HTTP adapter
55
     * @param string     $rootUrl Root URL of the addok server
56
     */
57 20
    public function __construct(HttpClient $client, $rootUrl)
58
    {
59 20
        parent::__construct($client);
60
61 20
        $this->rootUrl = rtrim($rootUrl, '/');
62 20
    }
63
64 11
    private function getGeocodeEndpointUrl(): string
65
    {
66 11
        return $this->rootUrl.'/search/?q=%s&limit=%d&autocomplete=0';
67
    }
68
69 6
    private function getReverseEndpointUrl(): string
70
    {
71 6
        return $this->rootUrl.'/reverse/?lat=%F&lon=%F';
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 14
    public function geocodeQuery(GeocodeQuery $query): Collection
78
    {
79 14
        $address = $query->getText();
80
        // This API does not support IP
81 14
        if (filter_var($address, FILTER_VALIDATE_IP)) {
82 3
            throw new UnsupportedOperation('The Addok provider does not support IP addresses, only street addresses.');
83
        }
84
85
        // Save a request if no valid address entered
86 11
        if (empty($address)) {
87
            throw new InvalidArgument('Address cannot be empty.');
88
        }
89
90 11
        $url = sprintf($this->getGeocodeEndpointUrl(), urlencode($address), $query->getLimit());
91
92 11
        if ($type = $query->getData('type', null)) {
93 3
            $url .= sprintf('&type=%s', $type);
94
        }
95
96 11
        $json = $this->executeQuery($url);
97
98
        // no result
99 6
        if (empty($json->features)) {
100 1
            return new AddressCollection([]);
101
        }
102
103 5
        $results = [];
104 5
        foreach ($json->features as $feature) {
105 5
            $coordinates = $feature->geometry->coordinates;
106
107 5
            switch ($feature->properties->type) {
108 5
                case self::TYPE_HOUSENUMBER:
109 2
                    $streetName = !empty($feature->properties->street) ? $feature->properties->street : null;
110 2
                    $number = !empty($feature->properties->housenumber) ? $feature->properties->housenumber : null;
111 2
                    break;
112 3
                case self::TYPE_STREET:
113 2
                    $streetName = !empty($feature->properties->name) ? $feature->properties->name : null;
114 2
                    $number = null;
115 2
                    break;
116
                default:
117 2
                    $streetName = null;
118 2
                    $number = null;
119
            }
120 5
            $locality = !empty($feature->properties->city) ? $feature->properties->city : null;
121 5
            $postalCode = !empty($feature->properties->postcode) ? $feature->properties->postcode : null;
122
123 5
            $results[] = Address::createFromArray([
124 5
                'providedBy'   => $this->getName(),
125 5
                'latitude'     => $coordinates[1],
126 5
                'longitude'    => $coordinates[0],
127 5
                'streetNumber' => $number,
128 5
                'streetName'   => $streetName,
129 5
                'locality'     => $locality,
130 5
                'postalCode'   => $postalCode,
131
            ]);
132
        }
133
134 5
        return new AddressCollection($results);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 6
    public function reverseQuery(ReverseQuery $query): Collection
141
    {
142 6
        $coordinates = $query->getCoordinates();
143
144 6
        $url = sprintf($this->getReverseEndpointUrl(), $coordinates->getLatitude(), $coordinates->getLongitude());
145 6
        $json = $this->executeQuery($url);
146
147
        // no result
148 1
        if (empty($json->features)) {
149
            return new AddressCollection([]);
150
        }
151
152 1
        $results = [];
153 1
        foreach ($json->features as $feature) {
154 1
            $coordinates = $feature->geometry->coordinates;
155 1
            $streetName = !empty($feature->properties->street) ? $feature->properties->street : null;
156 1
            $number = !empty($feature->properties->housenumber) ? $feature->properties->housenumber : null;
157 1
            $municipality = !empty($feature->properties->city) ? $feature->properties->city : null;
158 1
            $postalCode = !empty($feature->properties->postcode) ? $feature->properties->postcode : null;
159
160 1
            $results[] = Address::createFromArray([
161 1
                'providedBy'   => $this->getName(),
162 1
                'latitude'     => $coordinates[1],
163 1
                'longitude'    => $coordinates[0],
164 1
                'streetNumber' => $number,
165 1
                'streetName'   => $streetName,
166 1
                'locality'     => $municipality,
167 1
                'postalCode'   => $postalCode,
168
            ]);
169
        }
170
171 1
        return new AddressCollection($results);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 6
    public function getName(): string
178
    {
179 6
        return 'addok';
180
    }
181
182
    /**
183
     * @param string $url
184
     *
185
     * @return \stdClass
186
     */
187 17
    private function executeQuery(string $url): \stdClass
188
    {
189 17
        $content = $this->getUrlContents($url);
190 7
        $json = json_decode($content);
191
        // API error
192 7
        if (!isset($json)) {
193
            throw InvalidServerResponse::create($url);
194
        }
195
196 7
        return $json;
197
    }
198
}
199