Completed
Push — master ( d63616...511dbe )
by Tobias
02:09
created

Batch::reverse()   C

Complexity

Conditions 10
Paths 4

Size

Total Lines 64
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 64
ccs 42
cts 42
cp 1
rs 6.309
c 0
b 0
f 0
cc 10
eloc 45
nc 4
nop 1
crap 10

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
/*
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\Cache\CacheInterface;
17
use League\Geotools\Coordinate\CoordinateInterface;
18
use League\Geotools\Exception\InvalidArgumentException;
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 CacheInterface
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 61
    public function __construct(ProviderAggregator $geocoder)
56
    {
57 61
        $this->geocoder = $geocoder;
58 61
    }
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
        return isset($this->cache) ? $this->cache->isCached($providerName, $query) : false;
71
    }
72
73
    /**
74
     * Cache the BatchGeocoded object.
75
     *
76
     * @param BatchGeocoded $geocoded The BatchGeocoded object to cache.
77
     *
78
     * @return BatchGeocoded The BatchGeocoded object.
79
     */
80 9
    public function cache(BatchGeocoded $geocoded)
81
    {
82 9
        if (isset($this->cache)) {
83 1
            $this->cache->cache($geocoded);
84
        }
85
86 9
        return $geocoded;
87
    }
88
89
    /**
90
     * {@inheritDoc}
91
     */
92 28
    public function geocode($values)
93
    {
94 28
        $geocoder = $this->geocoder;
95 28
        $cache    = $this;
96
97 28
        foreach ($geocoder->getProviders() as $provider) {
98 28
            if (is_array($values) && count($values) > 0) {
99 9
                foreach ($values as $value) {
100 9
                    $this->tasks[] = function () use ($geocoder, $provider, $value, $cache) {
101 8
                        $deferred = new Deferred;
102
103
                        try {
104 8
                            if ($cached = $cache->isCached($provider->getName(), $value)) {
105 4
                                $deferred->resolve($cached);
106
                            } else {
107 4
                                $batchResult = new BatchResult($provider->getName(), $value);
108 4
                                $address = $geocoder->using($provider->getName())->geocode($value)->first();
109 6
                                $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
110
                            }
111 2
                        } catch (\Exception $e) {
112 2
                            $batchGeocoded = new BatchResult($provider->getName(), $value, $e->getMessage());
113 2
                            $deferred->reject($batchGeocoded->newInstance());
114
                        }
115
116 8
                        return $deferred->promise();
117 9
                    };
118
                }
119 19
            } elseif (is_string($values) && '' !== trim($values)) {
120 12
                $this->tasks[] = function () use ($geocoder, $provider, $values, $cache) {
121 8
                    $deferred = new Deferred;
122
123
                    try {
124 8
                        if ($cached = $cache->isCached($provider->getName(), $values)) {
125 4
                            $deferred->resolve($cached);
126
                        } else {
127 4
                            $batchResult = new BatchResult($provider->getName(), $values);
128 4
                            $address = $geocoder->using($provider->getName())->geocode($values)->first();
129 6
                            $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
130
                        }
131 2
                    } catch (\Exception $e) {
132 2
                        $batchGeocoded = new BatchResult($provider->getName(), $values, $e->getMessage());
133 2
                        $deferred->reject($batchGeocoded->newInstance());
134
                    }
135
136 8
                    return $deferred->promise();
137 12
                };
138
            } else {
139 7
                throw new InvalidArgumentException(
140 28
                    'The argument should be a string or an array of strings to geocode.'
141
                );
142
            }
143
        }
144
145 21
        return $this;
146
    }
147
148
    /**
149
     * {@inheritDoc}
150
     */
151 26
    public function reverse($coordinates)
152
    {
153 26
        $geocoder = $this->geocoder;
154 26
        $cache    = $this;
155
156 26
        foreach ($geocoder->getProviders() as $provider) {
157 26
            if (is_array($coordinates) && count($coordinates) > 0) {
158 9
                foreach ($coordinates as $coordinate) {
159 9
                    $this->tasks[] = function () use ($geocoder, $provider, $coordinate, $cache) {
160 8
                        $deferred = new Deferred();
161
162 8
                        $valueCoordinates = sprintf('%s, %s', $coordinate->getLatitude(), $coordinate->getLongitude());
163
                        try {
164 8
                            if ($cached = $cache->isCached($provider->getName(), $valueCoordinates)) {
165 4
                                $deferred->resolve($cached);
166
                            } else {
167 4
                                $batchResult = new BatchResult($provider->getName(), $valueCoordinates);
168 4
                                $address = $geocoder->using($provider->getName())->reverse(
169 4
                                        $coordinate->getLatitude(),
170 4
                                        $coordinate->getLongitude()
171 2
                                    )->first();
172
173 6
                                $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
174
                            }
175 2
                        } catch (\Exception $e) {
176 2
                            $batchGeocoded = new BatchResult($provider->getName(), $valueCoordinates, $e->getMessage());
177 2
                            $deferred->reject($batchGeocoded->newInstance());
178
                        }
179
180 8
                        return $deferred->promise();
181 9
                    };
182
                }
183 17
            } elseif ($coordinates instanceOf CoordinateInterface) {
184 10
                $this->tasks[] = function () use ($geocoder, $provider, $coordinates, $cache) {
185 8
                    $deferred = new Deferred();
186
187 8
                    $valueCoordinates = sprintf('%s, %s', $coordinates->getLatitude(), $coordinates->getLongitude());
188
                    try {
189 8
                        if ($cached = $cache->isCached($provider->getName(), $valueCoordinates)) {
190 4
                            $deferred->resolve($cached);
191
                        } else {
192 4
                            $batchResult = new BatchResult($provider->getName(), $valueCoordinates);
193 4
                            $address = $geocoder->using($provider->getName())->reverse(
194 4
                                    $coordinates->getLatitude(),
195 4
                                    $coordinates->getLongitude()
196 2
                                )->first();
197 6
                            $deferred->resolve($cache->cache($batchResult->createFromAddress($address)));
198
                        }
199 2
                    } catch (\Exception $e) {
200 2
                        $batchGeocoded = new BatchResult($provider->getName(), $valueCoordinates, $e->getMessage());
201 2
                        $deferred->reject($batchGeocoded->newInstance());
202
                    }
203
204 8
                    return $deferred->promise();
205 10
                };
206
            } else {
207 7
                throw new InvalidArgumentException(
208 26
                    'The argument should be a Coordinate instance or an array of Coordinate instances to reverse.'
209
                );
210
            }
211
        }
212
213 19
        return $this;
214
    }
215
216
    /**
217
     * {@inheritDoc}
218
     *
219
     * $this cannot be used in anonymous function in PHP 5.3.x
220
     * @see http://php.net/manual/en/functions.anonymous.php
221
     */
222 17
    public function serie()
223
    {
224 17
        $computedInSerie = array();
225
226 17
        foreach ($this->tasks as $task) {
227 13
            $task()->then(function($result) use (&$computedInSerie) {
228 13
                $computedInSerie[] = $result;
229
            }, function ($emptyResult) use (&$computedInSerie) {
230 4
                $computedInSerie[] = $emptyResult;
231 17
            });
232
        }
233
234 16
        return $computedInSerie;
235
    }
236
237
    /**
238
     * {@inheritDoc}
239
     *
240
     * $this cannot be used in anonymous function in PHP 5.3.x
241
     * @see http://php.net/manual/en/functions.anonymous.php
242
     */
243 17
    public function parallel()
244
    {
245 17
        $loop = EventLoopFactory::create();
246 17
        $computedInParallel = array();
247
248 17
        foreach ($this->tasks as $task) {
249
            $loop->nextTick(function () use ($task, &$computedInParallel) {
250 12
                $task()->then(function($result) use (&$computedInParallel) {
251 12
                    $computedInParallel[] = $result;
252
                }, function ($emptyResult) use (&$computedInParallel) {
253 4
                    $computedInParallel[] = $emptyResult;
254 16
                });
255 17
            });
256
        }
257
258 17
        $loop->run();
259
260 16
        return $computedInParallel;
261
    }
262
263
    /**
264
     * {@inheritDoc}
265
     */
266 19
    public function setCache(CacheInterface $cache)
267
    {
268 19
        $this->cache = $cache;
269
270 19
        return $this;
271
    }
272
}
273