start refactoring to promises
[pharext/pharext.org] / app / Github / API / Call.php
1 <?php
2
3 namespace app\Github\API;
4
5 use app\Github\API;
6 use app\Github\Storage\Item;
7 use http\Client\Response;
8 use http\QueryString;
9 use http\Url;
10 use merry\Config;
11
12 use React\Promise;
13
14 abstract class Call
15 {
16 /**
17 * @var Config
18 */
19 protected $config;
20
21 /**
22 * @var \app\Gituhub\API
23 */
24 protected $api;
25
26 /**
27 * @var array
28 */
29 protected $args = [];
30
31 /**
32 * @var \http\Url
33 */
34 protected $url;
35
36 /**
37 * @var QueryString
38 */
39 protected $query;
40
41 /**
42 * @var array
43 */
44 protected $result;
45
46 /**
47 * @var \React\Promise\Deferred
48 */
49 protected $deferred;
50
51 /**
52 * @return Request
53 */
54 abstract protected function request();
55
56 /**
57 * @return array
58 */
59 abstract protected function response(Response $response);
60
61 /**
62 * @param API $api
63 * @param array $args
64 */
65 function __construct(API $api, array $args = null) {
66 $this->api = $api;
67 $this->config = $this->api->getConfig();
68 $this->url = new Url($this->config->api->url, null, 0);
69 $this->deferred = new Promise\Deferred;
70
71 if ($args) {
72 $this->args = $args;
73 }
74 if (isset($this->config->api->call->{$this}->args)) {
75 $this->args += $this->config->api->call->{$this}->args->toArray();
76 }
77 }
78
79 /**
80 * @return \React\Promise\Promise
81 */
82 function __invoke() {
83 if ($this->readFromCache($this->result)) {
84 return new Promise\FulfilledPromise($this->result);
85 } else {
86 $this->api->getClient()->enqueue(
87 $this->request(),
88 function($response) {
89 try {
90 $this->deferred->resolve($this->response($response));
91 } catch (\Exception $e) {
92 $this->deferred->reject($e);
93 }
94 return true;
95 }
96 );
97 return $this->deferred->promise();
98 }
99 }
100
101 /**
102 * Get type of call
103 * @return string
104 */
105 function __toString() {
106 $parts = explode("\\", get_class($this));
107 return strtolower(end($parts));
108 }
109
110 /**
111 * Call Client::send()
112 */
113 function send() {
114 $this->api->getClient()->send();
115 return $this->result;
116 }
117
118 /**
119 * Get associated cache storage
120 * @param int $ttl out param of configure ttl
121 * @return Storage
122 */
123 function getCache(&$ttl = null) {
124 if (isset($this->config->storage->cache->{$this}->ttl)) {
125 $ttl = $this->config->storage->cache->{$this}->ttl;
126 }
127 return $this->api->getCacheStorage();
128 }
129
130 function getCacheKey() {
131 $args = $this->args;
132 unset($args["fresh"]);
133 if (isset($args["page"]) && !strcmp($args["page"], "1")) {
134 unset($args["page"]);
135 }
136 ksort($args);
137 return sprintf("%s:%s:%s", $this->api->getToken(), $this,
138 new QueryString($args));
139 }
140
141 function readFromCache(array &$value = null) {
142 if (!empty($this->args["fresh"])) {
143 return false;
144 }
145 if (!($cache = $this->api->getCacheStorage())) {
146 return false;
147 }
148 if (!strlen($key = $this->getCacheKey())) {
149 return false;
150 }
151 if (!$cache->get($key, $cached)) {
152 return false;
153 }
154 if (null !== $this->api->getMaxAge() && $cached->getAge() > $this->api->getMaxAge()) {
155 return false;
156 }
157 $this->api->getLogger()->debug("Cache-Hit: $this", $this->args);
158 $value = $cached->getValue();
159 return true;
160 }
161
162 function saveToCache(array $fresh) {
163 if (($cache = $this->api->getCacheStorage())) {
164 if (isset($this->config->storage->cache->{$this}->ttl)) {
165 $ttl = $this->config->storage->cache->{$this}->ttl;
166 } else {
167 $ttl = null;
168 }
169
170 $key = $this->getCacheKey();
171 $cache->set($key, new Item($fresh, $ttl));
172 }
173 }
174
175 function dropFromCache() {
176 if (($cache = $this->api->getCacheStorage())) {
177 $key = $this->getCacheKey();
178 $cache->del($key);
179 }
180 }
181 }