1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
namespace WyriHaximus\ApiClient\Transport; |
5
|
|
|
|
6
|
|
|
use GuzzleHttp\Client as GuzzleClient; |
7
|
|
|
use GuzzleHttp\Psr7\Request; |
8
|
|
|
use Psr\Http\Message\ResponseInterface; |
9
|
|
|
use React\Cache\CacheInterface; |
10
|
|
|
use React\EventLoop\LoopInterface; |
11
|
|
|
use React\Promise\Deferred; |
12
|
|
|
use React\Promise\FulfilledPromise; |
13
|
|
|
use React\Promise\PromiseInterface; |
14
|
|
|
use function React\Promise\reject; |
15
|
|
|
use function React\Promise\resolve; |
16
|
|
|
use function WyriHaximus\React\futureFunctionPromise; |
17
|
|
|
|
18
|
|
|
class Client |
19
|
|
|
{ |
20
|
|
|
const DEFAULT_OPTIONS = [ |
21
|
|
|
'schema' => 'https', |
22
|
|
|
'path' => '/', |
23
|
|
|
'user_agent' => 'WyriHaximus/php-api-client', |
24
|
|
|
'headers' => [], |
25
|
|
|
]; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var GuzzleClient |
29
|
|
|
*/ |
30
|
|
|
protected $handler; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var LoopInterface |
34
|
|
|
*/ |
35
|
|
|
protected $loop; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var array |
39
|
|
|
*/ |
40
|
|
|
protected $options = []; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var Hydrator |
44
|
|
|
*/ |
45
|
|
|
protected $hydrator; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var CacheInterface |
49
|
|
|
*/ |
50
|
|
|
protected $cache; |
51
|
|
|
|
52
|
9 |
|
public function __construct(LoopInterface $loop, GuzzleClient $handler, array $options = []) |
53
|
|
|
{ |
54
|
9 |
|
$this->loop = $loop; |
55
|
9 |
|
$this->handler = $handler; |
56
|
9 |
|
$this->options = self::DEFAULT_OPTIONS + $options; |
57
|
9 |
|
if (isset($this->options['cache']) && $this->options['cache'] instanceof CacheInterface) { |
58
|
3 |
|
$this->cache = $this->options['cache']; |
59
|
|
|
} |
60
|
9 |
|
$this->hydrator = new Hydrator($this, $options); |
61
|
9 |
|
} |
62
|
|
|
|
63
|
5 |
|
public function request(string $path, bool $refresh = false): PromiseInterface |
64
|
|
|
{ |
65
|
5 |
|
if ($refresh) { |
66
|
2 |
|
return $this->sendRequest($path); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
return $this->checkCache($path)->otherwise(function () use ($path) { |
70
|
2 |
|
return $this->sendRequest($path); |
71
|
3 |
|
}); |
72
|
|
|
} |
73
|
|
|
|
74
|
3 |
View Code Duplication |
protected function checkCache(string $path) |
|
|
|
|
75
|
|
|
{ |
76
|
3 |
|
if ($this->cache instanceof CacheInterface) { |
77
|
|
|
return $this->cache->get($path)->then(function ($json) use ($path) { |
78
|
1 |
|
return $this->jsonDecode($json); |
79
|
2 |
|
}); |
80
|
|
|
} |
81
|
|
|
|
82
|
1 |
|
return reject(); |
83
|
|
|
} |
84
|
|
|
|
85
|
4 |
|
protected function sendRequest(string $path, string $method = 'GET'): PromiseInterface |
86
|
|
|
{ |
87
|
4 |
|
$deferred = new Deferred(); |
88
|
|
|
|
89
|
4 |
|
$this->handler->sendAsync( |
90
|
4 |
|
$this->createRequest($method, $path) |
91
|
|
|
)->then(function (ResponseInterface $response) use ($deferred) { |
92
|
2 |
|
$deferred->resolve($response->getBody()->getContents()); |
93
|
|
|
}, function ($error) use ($deferred) { |
94
|
|
|
$deferred->reject($error); |
95
|
4 |
|
}); |
96
|
|
|
|
97
|
|
View Code Duplication |
return $deferred->promise()->then(function ($json) use ($path) { |
|
|
|
|
98
|
2 |
|
if ($this->cache instanceof CacheInterface) { |
99
|
2 |
|
$this->cache->set($path, $json); |
100
|
|
|
} |
101
|
2 |
|
return $this->jsonDecode($json); |
102
|
4 |
|
}); |
103
|
|
|
} |
104
|
|
|
|
105
|
4 |
|
protected function createRequest(string $method, string $path) |
106
|
|
|
{ |
107
|
4 |
|
$url = $this->options['schema'] . '://' . $this->options['host'] . $this->options['path'] . $path; |
108
|
|
|
$headers = [ |
109
|
4 |
|
'User-Agent' => $this->options['user_agent'], |
110
|
|
|
]; |
111
|
4 |
|
$headers += $this->options['headers']; |
112
|
4 |
|
return new Request($method, $url, $headers); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
protected function jsonDecode(string $json): PromiseInterface |
116
|
|
|
{ |
117
|
3 |
|
return futureFunctionPromise($this->loop, $json, function ($json) { |
118
|
3 |
|
return json_decode($json, true); |
119
|
3 |
|
}); |
120
|
|
|
} |
121
|
|
|
|
122
|
1 |
|
public function getHydrator(): Hydrator |
123
|
|
|
{ |
124
|
1 |
|
return $this->hydrator; |
125
|
|
|
} |
126
|
|
|
|
127
|
3 |
|
public function getLoop(): LoopInterface |
128
|
|
|
{ |
129
|
3 |
|
return $this->loop; |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.