Batch   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 99.15%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 12
dl 0
loc 265
ccs 116
cts 117
cp 0.9915
rs 9.76
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A isCached() 0 14 3
A cache() 0 11 2
C reverse() 0 64 10
A serie() 0 14 2
A parallel() 0 19 2
A setCache() 0 6 1
A getCacheKey() 0 4 1
C geocode() 0 55 11
1
<?php
2
3
/*
4
 * This file is part of the Geotools library.
5
 *
6
 * (c) Antoine Corcy <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace League\Geotools\Batch;
13
14
use Geocoder\Geocoder;
15
use Geocoder\ProviderAggregator;
16
use League\Geotools\Coordinate\CoordinateInterface;
17
use League\Geotools\Exception\InvalidArgumentException;
18
use Psr\Cache\CacheItemPoolInterface;
19
use React\EventLoop\Factory as EventLoopFactory;
20
use React\Promise\Deferred;
21
22
/**
23
 * Batch class
24
 *
25
 * @author Antoine Corcy <[email protected]>
26
 */
27
class Batch implements BatchInterface
28
{
29
    /**
30
     * The Geocoder instance to use.
31
     *
32
     * @var ProviderAggregator
33
     */
34
    protected $geocoder;
35
36
    /**
37
     * An array of closures.
38
     *
39
     * @var array
40
     */
41
    protected $tasks;
42
43
    /**
44
     * The cache instance to use.
45
     *
46
     * @var CacheItemPoolInterface
47
     */
48
    protected $cache;
49
50
    /**
51
     * Set the Geocoder instance to use.
52
     *
53
     * @param ProviderAggregator $geocoder The Geocoder instance to use.
54
     */
55 60
    public function __construct(ProviderAggregator $geocoder)
56
    {
57 60
        $this->geocoder = $geocoder;
58 60
    }
59
60
    /**
61
     * Check against the cache instance if any.
62
     *
63
     * @param string $providerName The name of the provider.
64
     * @param string $query        The query string.
65
     *
66
     * @return boolean|BatchGeocoded The BatchGeocoded object from the query or the cache instance.
67
     */
68 34
    public function isCached($providerName, $query)
69
    {
70 34
        if (null === $this->cache) {
71 17
            return false;
72
        }
73
74 17
        $item = $this->cache->getItem($this->getCacheKey($providerName, $query));
75
76 17
        if ($item->isHit()) {
77 17
            return $item->get();
78
        }
79
80
        return false;
81
    }
82
83
84
    /**
85
     * Cache the BatchGeocoded object.
86
     *
87
     * @param BatchGeocoded $geocoded The BatchGeocoded object to cache.
88
     *
89
     * @return BatchGeocoded The BatchGeocoded object.
90
     */
91 9
    public function cache(BatchGeocoded $geocoded)
92
    {
93 9
        if (isset($this->cache)) {
94 1
            $key = $this->getCacheKey($geocoded->getProviderName(), $geocoded->getQuery());
95 1
            $item = $this->cache->getItem($key);
96 1
            $item->set($geocoded);
97 1
            $this->cache->save($item);
98
        }
99
100 9
        return $geocoded;
101
    }
102
103
    /**
104
     * {@inheritDoc}
105
     */
106 28
    public function geocode($values)
107
    {
108 28
        $geocoder = $this->geocoder;
109 28
        $cache    = $this;
110
111 28
        foreach ($geocoder->getProviders() as $provider) {
112 28
            if (is_array($values) && count($values) > 0) {
113 9
                foreach ($values as $value) {
114 9
                    $this->tasks[] = function () use ($geocoder, $provider, $value, $cache) {
115 8
                        $deferred = new Deferred;
116
117
                        try {
118 8
                            if ($cached = $cache->isCached($provider->getName(), $value)) {
119 4
                                $deferred->resolve($cached);
120
                            } else {
121 4
                                $batchResult = new BatchResult($provider->getName(), $value);
122 4
                                $address = $geocoder->using($provider->getName())->geocode($value)->first();
123 6
                                $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
124
                            }
125 2
                        } catch (\Exception $e) {
126 2
                            $batchGeocoded = new BatchResult($provider->getName(), $value, $e->getMessage());
127 2
                            $deferred->reject($batchGeocoded->newInstance());
128
                        }
129
130 8
                        return $deferred->promise();
131 9
                    };
132
                }
133 19
            } elseif (is_string($values) && '' !== trim($values)) {
134 12
                $this->tasks[] = function () use ($geocoder, $provider, $values, $cache) {
135 8
                    $deferred = new Deferred;
136
137
                    try {
138 8
                        if ($cached = $cache->isCached($provider->getName(), $values)) {
139 4
                            $deferred->resolve($cached);
140
                        } else {
141 4
                            $batchResult = new BatchResult($provider->getName(), $values);
142 4
                            $address = $geocoder->using($provider->getName())->geocode($values)->first();
143 6
                            $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
144
                        }
145 2
                    } catch (\Exception $e) {
146 2
                        $batchGeocoded = new BatchResult($provider->getName(), $values, $e->getMessage());
147 2
                        $deferred->reject($batchGeocoded->newInstance());
148
                    }
149
150 8
                    return $deferred->promise();
151 12
                };
152
            } else {
153 7
                throw new InvalidArgumentException(
154 28
                    'The argument should be a string or an array of strings to geocode.'
155
                );
156
            }
157
        }
158
159 21
        return $this;
160
    }
161
162
    /**
163
     * {@inheritDoc}
164
     */
165 26
    public function reverse($coordinates)
166
    {
167 26
        $geocoder = $this->geocoder;
168 26
        $cache    = $this;
169
170 26
        foreach ($geocoder->getProviders() as $provider) {
171 26
            if (is_array($coordinates) && count($coordinates) > 0) {
172 9
                foreach ($coordinates as $coordinate) {
173 9
                    $this->tasks[] = function () use ($geocoder, $provider, $coordinate, $cache) {
174 8
                        $deferred = new Deferred();
175
176 8
                        $valueCoordinates = sprintf('%s, %s', $coordinate->getLatitude(), $coordinate->getLongitude());
177
                        try {
178 8
                            if ($cached = $cache->isCached($provider->getName(), $valueCoordinates)) {
179 4
                                $deferred->resolve($cached);
180
                            } else {
181 4
                                $batchResult = new BatchResult($provider->getName(), $valueCoordinates);
182 4
                                $address = $geocoder->using($provider->getName())->reverse(
183 4
                                        $coordinate->getLatitude(),
184 4
                                        $coordinate->getLongitude()
185 2
                                    )->first();
186
187 6
                                $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
188
                            }
189 2
                        } catch (\Exception $e) {
190 2
                            $batchGeocoded = new BatchResult($provider->getName(), $valueCoordinates, $e->getMessage());
191 2
                            $deferred->reject($batchGeocoded->newInstance());
192
                        }
193
194 8
                        return $deferred->promise();
195 9
                    };
196
                }
197 17
            } elseif ($coordinates instanceOf CoordinateInterface) {
198 10
                $this->tasks[] = function () use ($geocoder, $provider, $coordinates, $cache) {
199 8
                    $deferred = new Deferred();
200
201 8
                    $valueCoordinates = sprintf('%s, %s', $coordinates->getLatitude(), $coordinates->getLongitude());
202
                    try {
203 8
                        if ($cached = $cache->isCached($provider->getName(), $valueCoordinates)) {
204 4
                            $deferred->resolve($cached);
205
                        } else {
206 4
                            $batchResult = new BatchResult($provider->getName(), $valueCoordinates);
207 4
                            $address = $geocoder->using($provider->getName())->reverse(
208 4
                                    $coordinates->getLatitude(),
209 4
                                    $coordinates->getLongitude()
210 2
                                )->first();
211 6
                            $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
212
                        }
213 2
                    } catch (\Exception $e) {
214 2
                        $batchGeocoded = new BatchResult($provider->getName(), $valueCoordinates, $e->getMessage());
215 2
                        $deferred->reject($batchGeocoded->newInstance());
216
                    }
217
218 8
                    return $deferred->promise();
219 10
                };
220
            } else {
221 7
                throw new InvalidArgumentException(
222 26
                    'The argument should be a Coordinate instance or an array of Coordinate instances to reverse.'
223
                );
224
            }
225
        }
226
227 19
        return $this;
228
    }
229
230
    /**
231
     * {@inheritDoc}
232
     *
233
     * $this cannot be used in anonymous function in PHP 5.3.x
234
     * @see http://php.net/manual/en/functions.anonymous.php
235
     */
236 17
    public function serie()
237
    {
238 17
        $computedInSerie = array();
239
240 17
        foreach ($this->tasks as $task) {
241 13
            $task()->then(function($result) use (&$computedInSerie) {
242 13
                $computedInSerie[] = $result;
243
            }, function ($emptyResult) use (&$computedInSerie) {
244 4
                $computedInSerie[] = $emptyResult;
245 17
            });
246
        }
247
248 16
        return $computedInSerie;
249
    }
250
251
    /**
252
     * {@inheritDoc}
253
     *
254
     * $this cannot be used in anonymous function in PHP 5.3.x
255
     * @see http://php.net/manual/en/functions.anonymous.php
256
     */
257 17
    public function parallel()
258
    {
259 17
        $loop = EventLoopFactory::create();
260 17
        $computedInParallel = array();
261
262 17
        foreach ($this->tasks as $task) {
263
            $loop->futureTick(function () use ($task, &$computedInParallel) {
264 12
                $task()->then(function($result) use (&$computedInParallel) {
265 12
                    $computedInParallel[] = $result;
266
                }, function ($emptyResult) use (&$computedInParallel) {
267 4
                    $computedInParallel[] = $emptyResult;
268 16
                });
269 17
            });
270
        }
271
272 17
        $loop->run();
273
274 16
        return $computedInParallel;
275
    }
276
277
    /**
278
     * {@inheritDoc}
279
     */
280 19
    public function setCache(CacheItemPoolInterface $cache)
281
    {
282 19
        $this->cache = $cache;
283
284 19
        return $this;
285
    }
286
287 18
    private function getCacheKey(string $providerName, string $query): string
288
    {
289 18
        return sha1($providerName.'-'.$query);
290
    }
291
}
292

 

OSZAR »