Completed
Push — master ( 67f027...f57688 )
by Mike
19s queued 10s
created

ProviderAndDumperAggregator::getReader()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 5
cts 5
cp 1
rs 9.9
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2
1
<?php namespace Geocoder\Laravel;
2
3
/**
4
 * This file is part of the Geocoder Laravel package.
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author Mike Bronner <[email protected]>
9
 * @license    MIT License
10
 */
11
12
use Geocoder\Dumper\GeoJson;
13
use Geocoder\Dumper\Gpx;
14
use Geocoder\Dumper\Kml;
15
use Geocoder\Dumper\Wkb;
16
use Geocoder\Dumper\Wkt;
17
use Geocoder\Laravel\Exceptions\InvalidDumperException;
18
use Geocoder\ProviderAggregator;
19
use Geocoder\Query\GeocodeQuery;
20
use Geocoder\Query\ReverseQuery;
21
use Illuminate\Log\Logger;
22
use Illuminate\Support\Collection;
23
use Illuminate\Support\Str;
24
use Psr\Log\LoggerAwareTrait;
25
use ReflectionClass;
26
27
/**
28
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
29
 */
30
class ProviderAndDumperAggregator
31
{
32
    protected $aggregator;
33
    protected $limit;
34 24
    protected $results;
35
36 24
    public function __construct()
37 24
    {
38 24
        $this->aggregator = new ProviderAggregator();
39
        $this->results = collect();
40
    }
41
42
    /**
43 1
     * @deprecated Use `get()` instead.
44
     */
45 1
    public function all() : array
46
    {
47
        return $this->results->all();
48 17
    }
49
50 17
    public function get() : Collection
51
    {
52
        return $this->results;
53 2
    }
54
55 2
    public function toJson() : string
56 2
    {
57
        return $this
58
            ->dump("geojson")
59
            ->first();
60
    }
61
62
    public function dump(string $dumper) : Collection
63 2
    {
64 1
        $dumperClasses = collect([
65 1
            'geojson' => GeoJson::class,
66 1
            'gpx' => Gpx::class,
67
            'kml' => Kml::class,
68 1
            'wkb' => Wkb::class,
69
            'wkt' => Wkt::class,
70
        ]);
71 1
72 1
        if (!$dumperClasses->has($dumper)) {
73 1
            $errorMessage = implode('', [
74
                "The dumper specified ('{$dumper}') is invalid. Valid dumpers ",
75 1
                "are: geojson, gpx, kml, wkb, wkt.",
76 1
            ]);
77 1
78
            throw new InvalidDumperException($errorMessage);
79
        }
80 1
81
        $dumperClass = $dumperClasses->get($dumper);
82 1
        $dumper = new $dumperClass;
83 1
        $results = collect($this->results->all());
84 1
85 1
        return $results->map(function ($result) use ($dumper) {
86 1
            return $dumper->dump($result);
87 1
        });
88 1
    }
89
90 View Code Duplication
    public function geocode(string $value) : self
91 1
    {
92
        $cacheKey = (new Str)->slug(strtolower(urlencode($value)));
93 1
        $this->results = $this->cacheRequest($cacheKey, [$value], "geocode");
94
95
        return $this;
96 1
    }
97
98 1
    public function geocodeQuery(GeocodeQuery $query) : self
99 1
    {
100 1
        $cacheKey = serialize($query);
101 1
        $this->results = $this->cacheRequest($cacheKey, [$query], "geocodeQuery");
102 1
103 1
        return $this;
104 1
    }
105
106
    public function getLimit() : int
107 1
    {
108
        return $this->limit;
109 1
    }
110
111
    public function getName() : string
112 1
    {
113
        return $this->aggregator->getName();
114 1
    }
115
116
    public function limit(int $limit) : self
117 16
    {
118
        $this->aggregator = new ProviderAggregator(null, $limit);
119 16
        $this->registerProvidersFromConfig(collect(config('geocoder.providers')));
120 16
        $this->limit = $limit;
121 16
122 16
        return $this;
123 16
    }
124 16
125 16
    /**
126
     * @deprecated Use `getProviders()` instead.
127
     */
128 16
    public function getProvider()
129
    {
130 16
        return $this->getProviders()->first();
131
    }
132
133 1
    public function getProviders() : Collection
134
    {
135 1
        return collect($this->aggregator->getProviders());
136 1
    }
137 1
138 1
    public function registerProvider($provider) : self
139 1
    {
140 1
        $this->aggregator->registerProvider($provider);
141 1
142
        return $this;
143
    }
144 1
145
    public function registerProviders(array $providers = []) : self
146 1
    {
147
        $this->aggregator->registerProviders($providers);
148
149 1
        return $this;
150
    }
151 1
152 1
    public function registerProvidersFromConfig(Collection $providers) : self
153 1
    {
154
        $this->registerProviders($this->getProvidersFromConfiguration($providers));
155 1
156
        return $this;
157
    }
158 1
159 View Code Duplication
    public function reverse(float $latitude, float $longitude) : self
160 1
    {
161
        $cacheKey = (new Str)->slug(strtolower(urlencode("{$latitude}-{$longitude}")));
162
        $this->results = $this->cacheRequest($cacheKey, [$latitude, $longitude], "reverse");
163 1
164
        return $this;
165 1
    }
166
167 1
    public function reverseQuery(ReverseQuery $query) : self
168
    {
169
        $cacheKey = serialize($query);
170 24
        $this->results = $this->cacheRequest($cacheKey, [$query], "reverseQuery");
171
172 24
        return $this;
173
    }
174 24
175
    public function using(string $name) : self
176
    {
177 5
        $this->aggregator = $this->aggregator->using($name);
178
179 5
        return $this;
180
    }
181 5
182
    protected function cacheRequest(string $cacheKey, array $queryElements, string $queryType)
183
    {
184 2
        $hashedCacheKey = sha1($cacheKey);
185
        $duration = config("geocoder.cache.duration", 0);
186 2
        $store = config('geocoder.cache.store');
187
188
        $result = app("cache")
189
            ->store($store)
190
            ->remember($hashedCacheKey, $duration, function () use ($cacheKey, $queryElements, $queryType) {
191
                return [
192 1
                    "key" => $cacheKey,
193
                    "value" => collect($this->aggregator->{$queryType}(...$queryElements)),
194 1
                ];
195
            });
196
197 24
        $result = $this->preventCacheKeyHashCollision(
198
            $result,
199 24
            $hashedCacheKey,
200
            $cacheKey,
201 24
            $queryElements,
202
            $queryType
203
        );
204
205
        $this->removeEmptyCacheEntry($result, $hashedCacheKey);
206 24
207 24
        return $result;
208 24
    }
209
210 24
    protected function getAdapterClass(string $provider) : string
211 24
    {
212
        $specificAdapters = collect([
213
            'Geocoder\Provider\GeoIP2\GeoIP2' => 'Geocoder\Provider\GeoIP2\GeoIP2Adapter',
214 24
            'Geocoder\Provider\MaxMindBinary\MaxMindBinary' => '',
215 24
        ]);
216
217 24
        if ($specificAdapters->has($provider)) {
218
            return $specificAdapters->get($provider);
219
        }
220 24
221
        return config('geocoder.adapter');
222 24
    }
223 24
224 24
    protected function getReader()
225
    {
226
        if (is_array(config('geocoder.reader'))) {
227
            $reflection = new ReflectionClass(config('geocoder.reader.class'));
228 24
            $reader = $reflection->newInstanceArgs(config('geocoder.reader.arguments'));
229
        } else {
230 24
            $reader = config('geocoder.reader');
231 24
        }
232
233
        return $reader;
234 24
    }
235
236
    protected function getArguments(array $arguments, string $provider) : array
237 24
    {
238
        if ($provider === 'Geocoder\Provider\Chain\Chain') {
239 24
            return $this->getProvidersFromConfiguration(
240 24
                collect(config('geocoder.providers.Geocoder\Provider\Chain\Chain'))
241
            );
242
        }
243
244 24
        $adapter = $this->getAdapterClass($provider);
245
246
        if ($adapter) {
247
            if ($this->requiresReader($provider)) {
248 24
                $adapter = new $adapter($this->getReader());
249
            } else {
250
                $adapter = new $adapter;
251 19
            }
252
253 19
            array_unshift($arguments, $adapter);
254
        }
255 19
256 1
        return $arguments;
257
    }
258 19
259
    protected function getProvidersFromConfiguration(Collection $providers) : array
260
    {
261
        $providers = $providers->map(function ($arguments, $provider) {
262
            $arguments = $this->getArguments($arguments, $provider);
263
            $reflection = new ReflectionClass($provider);
264
265
            if ($provider === "Geocoder\Provider\Chain\Chain") {
266
                $chainProvider = $reflection->newInstance($arguments);
267
268
                if (class_exists(Logger::class)
269
                    && in_array(LoggerAwareTrait::class, class_uses($chainProvider))
270
                    && app(Logger::class) !== null
271
                ) {
272
                    $chainProvider->setLogger(app(Logger::class));
273
                }
274
275
                return $chainProvider;
276
            }
277
278
            return $reflection->newInstanceArgs($arguments);
279
        });
280
281
        return $providers->toArray();
282
    }
283
284
    protected function preventCacheKeyHashCollision(
285
        array $result,
286
        string $hashedCacheKey,
287
        string $cacheKey,
288
        array $queryElements,
289
        string $queryType
290
    ) {
291
        if ($result["key"] === $cacheKey) {
292
            return $result["value"];
293
        }
294
295
        app("cache")
296
            ->store(config('geocoder.cache.store'))
297
            ->forget($hashedCacheKey);
298
299
        return $this->cacheRequest($cacheKey, $queryElements, $queryType);
300
    }
301
302
    protected function removeEmptyCacheEntry(Collection $result, string $cacheKey)
303
    {
304
        if ($result && $result->isEmpty()) {
305
            app('cache')->forget($cacheKey);
306
        }
307
    }
308
309
    protected function requiresReader(string $class) : bool
310
    {
311
        $specificAdapters = collect([
312
            'Geocoder\Provider\GeoIP2\GeoIP2',
313
        ]);
314
315
        return $specificAdapters->contains($class);
316
    }
317
}
318