Passed
Push — master ( 84fe4e...38ed25 )
by du
01:45
created

IpClient   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 441
Duplicated Lines 0 %

Test Coverage

Coverage 95.19%

Importance

Changes 0
Metric Value
wmc 42
eloc 91
dl 0
loc 441
ccs 99
cts 104
cp 0.9519
rs 9.0399
c 0
b 0
f 0

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getErrors() 0 3 1
A getDefaultCacheDriver() 0 3 1
A getIp() 0 7 2
A getProviders() 0 11 3
A checkIp() 0 6 2
A try() 0 5 1
A setProviderConfig() 0 5 1
A setRequestHandler() 0 5 1
A setDataMapper() 0 5 1
A __call() 0 3 1
A getOriginalInfo() 0 16 3
A setCacheStore() 0 5 1
A getDataMapper() 0 15 3
A getInstanceByName() 0 3 2
A bound() 0 5 1
A use() 0 3 1
A resolveProviders() 0 13 3
A getRequestHandler() 0 7 2
A getProviderConfig() 0 7 2
A getCacheStore() 0 7 2
A useProvider() 0 6 1
A createProvider() 0 13 2
A clearUse() 0 5 1
A getDefaultProviders() 0 6 1
A responseWithError() 0 5 1
A __get() 0 3 1
A setIp() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like IpClient often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IpClient, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace DucCnzj\Ip;
4
5
use DucCnzj\Ip\Imp\IpImp;
6
use DucCnzj\Ip\Imp\DataMapImp;
7
use DucCnzj\Ip\Imp\CacheStoreImp;
8
use DucCnzj\Ip\Imp\RequestHandlerImp;
9
use DucCnzj\Ip\Exceptions\InvalidIpAddress;
10
use DucCnzj\Ip\Exceptions\ServerErrorException;
11
use DucCnzj\Ip\Exceptions\IpProviderClassNotExistException;
12
13
/**
14
 * @method string getCity()
15
 * @method string getCountry()
16
 * @method string getAddress()
17
 * @method string getRegion()
18
 *
19
 * Class IpClient
20
 *
21
 * @package DucCnzj\Ip
22
 */
23
class IpClient
24
{
25
    /**
26
     * @var string
27
     */
28
    protected $ip;
29
30
    /**
31
     * @var array
32
     */
33
    protected $providerConfig = [];
34
35
    /**
36
     * @var array|null ['baidu', 'taobao']
37
     */
38
    protected $providers = [];
39
40
    /**
41
     * @var array
42
     */
43
    protected $instances = [];
44
45
    /**
46
     * @var DataMapImp
47
     */
48
    protected $dataMapper;
49
50
    /**
51
     * @var null|CacheStoreImp
52
     */
53
    protected $cacheStore;
54
55
    /**
56
     * @var RequestHandlerImp|null
57
     */
58
    protected $requestHandler;
59
60
    /**
61
     * @param int $times
62
     *
63
     * @return $this
64
     *
65
     * @author duc <[email protected]>
66
     */
67 4
    public function try(int $times)
68
    {
69 4
        $this->requestHandler = $this->getRequestHandler()->setTryTimes($times);
70
71 4
        return $this;
72
    }
73
74
    /**
75
     * @param string $ip
76
     *
77
     * @throws InvalidIpAddress
78
     *
79
     * @author duc <[email protected]>
80
     */
81 13
    public function checkIp(string $ip)
82
    {
83 13
        $b = preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip);
84
85 13
        if (! $b) {
86 1
            throw new InvalidIpAddress;
87
        }
88 12
    }
89
90
    /**
91
     * @return array
92
     *
93
     * @author duc <[email protected]>
94
     */
95 10
    public function resolveProviders()
96
    {
97 10
        $providerInstance = [];
98
99 10
        foreach ($this->getProviders() as $provider) {
100 10
            if (! isset($this->instances[$provider])) {
101 5
                $this->instances[$provider] = $this->createProvider($provider);
102
            }
103
104 9
            $providerInstance[$provider] = $this->instances[$provider];
105
        }
106
107 9
        return $providerInstance;
108
    }
109
110
    /**
111
     * @param string $provider
112
     *
113
     * @return IpImp
114
     * @throws IpProviderClassNotExistException
115
     *
116
     * @author duc <[email protected]>
117
     */
118 5
    public function createProvider(string $provider)
119
    {
120 5
        $config = $this->getProviderConfig($provider);
121
122 5
        $shortName = ucfirst(strtolower($provider)) . 'Ip';
123
124 5
        $class = __NAMESPACE__ . "\Strategies\\{$shortName}";
125
126 5
        if (! class_exists($class)) {
127 1
            throw new IpProviderClassNotExistException("{$class} 不存在");
128
        }
129
130 4
        return new $class($config);
131
    }
132
133
    /**
134
     * @param string $msg
135
     *
136
     * @return array
137
     *
138
     * @author duc <[email protected]>
139
     */
140 5
    public function responseWithError(string $msg)
141
    {
142
        return [
143 5
            'success' => 0,
144 5
            'message' => $msg,
145
        ];
146
    }
147
148
    /**
149
     * @return DataMapper|DataMapImp|NullDataMapper
150
     *
151
     * @author duc <[email protected]>
152
     */
153 6
    public function getDataMapper()
154
    {
155 6
        $response = $this->getOriginalInfo();
156
157 6
        if (! $response['success']) {
158 4
            return (new NullDataMapper())->setInfo(['ip' => $this->getIp()]);
159
        }
160
161 2
        if (! $this->dataMapper) {
162 2
            $this->dataMapper = new DataMapper();
163
164 2
            return $this->dataMapper->setInfo($response);
165
        }
166
167 1
        return $this->dataMapper->setInfo($response);
168
    }
169
170
    /**
171
     * @return RequestHandlerImp|RequestHandler|null
172
     *
173
     * @author duc <[email protected]>
174
     */
175 3
    public function getRequestHandler()
176
    {
177 3
        if (! $this->requestHandler) {
178 2
            return $this->requestHandler = new RequestHandler();
179
        }
180
181 3
        return $this->requestHandler;
182
    }
183
184
    /**
185
     * @return array|mixed
186
     *
187
     * @author duc <[email protected]>
188
     */
189 7
    public function getOriginalInfo()
190
    {
191 7
        if ($info = $this->getCacheStore()->get($this->getIp())) {
192
            return $info;
193
        }
194
195
        try {
196 7
            $result = $this->getRequestHandler()
197 7
                ->send($this->resolveProviders(), $this->getIp());
198 5
        } catch (ServerErrorException $e) {
199 5
            return $this->responseWithError($e->getMessage());
200
        }
201
202 3
        $this->getCacheStore()->put($this->getIp(), $result);
203
204 3
        return $result;
205
    }
206
207
    /**
208
     * @return array
209
     *
210
     * @author duc <[email protected]>
211
     */
212 2
    public function getErrors(): array
213
    {
214 2
        return $this->getRequestHandler()->getErrors();
215
    }
216
217
    /**
218
     * @return array
219
     *
220
     * @author duc <[email protected]>
221
     */
222 13
    public function getProviders()
223
    {
224 13
        if (is_null($this->providers)) {
225 1
            return [];
226
        }
227
228 13
        if (count($this->providers) === 0) {
229 6
            return $this->providers = $this->getDefaultProviders();
230
        }
231
232 8
        return $this->providers;
233
    }
234
235
    /**
236
     * @return CacheStore
237
     *
238
     * @author duc <[email protected]>
239
     */
240 11
    public function getDefaultCacheDriver()
241
    {
242 11
        return new CacheStore();
243
    }
244
245
    /**
246
     * @return string
247
     * @throws \Exception
248
     *
249
     * @author duc <[email protected]>
250
     */
251 13
    public function getIp()
252
    {
253 13
        if (! $this->ip) {
254 1
            throw new \Exception('请先设置 ip');
255
        }
256
257 12
        return $this->ip;
258
    }
259
260
    /**
261
     * @return array
262
     *
263
     * @author duc <[email protected]>
264
     */
265 6
    public function getDefaultProviders()
266
    {
267
        return [
268 6
            'baidu',
269
            'ali',
270
            'taobao',
271
        ];
272
    }
273
274
    /**
275
     * @param string $provider
276
     *
277
     * @return array
278
     */
279 6
    public function getProviderConfig(string $provider): array
280
    {
281 6
        if (! isset($this->providerConfig[$provider])) {
282 6
            return [];
283
        }
284
285 1
        return $this->providerConfig[$provider];
286
    }
287
288
    /**
289
     * @return CacheStore|CacheStoreImp
290
     *
291
     * @author duc <[email protected]>
292
     */
293 12
    public function getCacheStore()
294
    {
295 12
        if ($this->cacheStore instanceof CacheStoreImp) {
296 4
            return $this->cacheStore;
297
        }
298
299 11
        return $this->cacheStore = $this->getDefaultCacheDriver();
300
    }
301
302
    /**
303
     * @param string $ip
304
     *
305
     * @return $this
306
     *
307
     * @author duc <[email protected]>
308
     */
309 12
    public function setIp(string $ip)
310
    {
311 12
        $this->checkIp($ip);
312
313 12
        $this->ip = $ip;
314
315 12
        return $this;
316
    }
317
318
    /**
319
     * @param string[] ...$provider
320
     *
321
     * @return $this
322
     *
323
     * @author duc <[email protected]>
324
     */
325 8
    public function useProvider(string ...$provider)
326
    {
327 8
        $providers = array_merge($this->providers ?? [], array_filter($provider));
328 8
        $this->providers = array_unique($providers);
329
330 8
        return $this;
331
    }
332
333
    /**
334
     * @param string $provider
335
     * @param array|string $config
336
     *
337
     * @return $this
338
     *
339
     * @author duc <[email protected]>
340
     */
341 2
    public function setProviderConfig(string $provider, $config)
342
    {
343 2
        $this->providerConfig[$provider] = $config;
344
345 2
        return $this;
346
    }
347
348
    /**
349
     * @param DataMapImp $dataMapper
350
     *
351
     * @return $this
352
     *
353
     * @author duc <[email protected]>
354
     */
355 1
    public function setDataMapper(DataMapImp $dataMapper)
356
    {
357 1
        $this->dataMapper = $dataMapper;
358
359 1
        return $this;
360
    }
361
362
    /**
363
     * @param RequestHandlerImp $requestHandler
364
     *
365
     * @return $this
366
     *
367
     * @author duc <[email protected]>
368
     */
369 1
    public function setRequestHandler(RequestHandlerImp $requestHandler)
370
    {
371 1
        $this->requestHandler = $requestHandler;
372
373 1
        return $this;
374
    }
375
376
    /**
377
     * @param CacheStoreImp $cacheStore
378
     *
379
     * @return $this
380
     *
381
     * @author duc <[email protected]>
382
     */
383 1
    public function setCacheStore(CacheStoreImp $cacheStore)
384
    {
385 1
        $this->cacheStore = $cacheStore;
386
387 1
        return $this;
388
    }
389
390
    /**
391
     * @param string $provider
392
     * @param IpImp  $instance
393
     *
394
     * @return $this
395
     *
396
     * @author duc <[email protected]>
397
     */
398 7
    public function bound(string $provider, IpImp $instance)
399
    {
400 7
        $this->instances[$provider] = $instance;
401
402 7
        return $this;
403
    }
404
405
    /**
406
     * @param string[] ...$provider
407
     *
408
     * @return IpClient
409
     *
410
     * @author duc <[email protected]>
411
     */
412 2
    public function use(string ...$provider)
413
    {
414 2
        return $this->useProvider(...$provider);
415
    }
416
417
    /**
418
     * @return $this
419
     *
420
     * @author duc <[email protected]>
421
     */
422 1
    public function clearUse()
423
    {
424 1
        $this->providers = null;
425
426 1
        return $this;
427
    }
428
429
    /**
430
     * @param string $name
431
     *
432
     * @return mixed|null
433
     *
434
     * @author duc <[email protected]>
435
     */
436 1
    public function getInstanceByName(string $name)
437
    {
438 1
        return isset($this->instances[$name]) ? $this->instances[$name] : null;
439
    }
440
441
    /**
442
     * @param string $name
443
     * @param $arguments
444
     *
445
     * @return array
446
     *
447
     * @author duc <[email protected]>
448
     */
449
    public function __call(string $name, $arguments)
450
    {
451
        return $this->getDataMapper()->{$name}(...$arguments);
452
    }
453
454
    /**
455
     * @param string $name
456
     *
457
     * @return mixed|string
458
     *
459
     * @author duc <[email protected]>
460
     */
461
    public function __get(string $name)
462
    {
463
        return $this->getDataMapper()->{$name};
464
    }
465
}
466