Addok::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 5
rs 10
ccs 3
cts 3
cp 1
crap 1
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