flush
[pharext/pharext.org] / app / Github / Fetch.php
1 <?php
2
3 namespace app\Github;
4
5 use http\Header;
6 use http\Params;
7 use http\Url;
8
9 abstract class Fetch
10 {
11 /**
12 * @var \app\Github\API
13 */
14 protected $api;
15
16 /**
17 * @var \merry\Config
18 */
19 protected $config;
20
21 /**
22 * @var array
23 */
24 protected $args;
25
26 /**
27 * @var int
28 */
29 protected $page = 1;
30
31 /**
32 * @var \http\Url
33 */
34 protected $url;
35
36 function __construct(API $api, array $args = []) {
37 $this->api = $api;
38 $this->config = $api->getConfig();
39 $this->args = $args;
40 $this->url = new Url("https://api.github.com/", null, 0);
41 if (isset($this->config->fetch->{$this}->per_page)) {
42 $this->url->query = "per_page=" . $this->config->fetch->{$this}->per_page;
43 }
44 }
45
46 function setPage($page) {
47 $this->page = $page;
48 return $this;
49 }
50
51 function getPage() {
52 return $this->page;
53 }
54
55 function __toString() {
56 $parts = explode("\\", get_class($this));
57 return strtolower(end($parts));
58 }
59
60 function getStorage(&$ttl = null) {
61 if (isset($this->config->storage->cache->{$this}->ttl)) {
62 $ttl = $this->config->storage->cache->{$this}->ttl;
63 }
64 return $this->api->getCacheStorage();
65 }
66
67 abstract function getRequest();
68 abstract function getException($message, $code, $previous = null);
69 abstract function getCacheKey();
70
71 function parseLinks(Header $header) {
72 $params = new Params($header->value, ",", ";", "=",
73 Params::PARSE_RFC5988 | Params::PARSE_ESCAPED);
74 $links = [];
75 foreach ($params->params as $link => $param) {
76 // strip enclosing brackets
77 $links[$param["arguments"]["rel"]] = $link;
78 }
79 return $links;
80 }
81
82 function __invoke(callable $callback) {
83 $ttl = -1;
84 $key = $this->getCacheKey();
85 if (($cache = $this->api->getCacheStorage())
86 && $cache->get($key, $cached, $ttl)) {
87 call_user_func_array($callback, $cached);
88 } else {
89 $this->enqueue($callback);
90 }
91 return $this->api->getClient();
92 }
93
94 protected function wrap(callable $callback) {
95 return function($response) use($callback) {
96 $rc = $response->getResponseCode();
97
98 if ($rc !== 200) {
99 if ($response->getHeader("Content-Type", Header::class)->match("application/json", Header::MATCH_WORD)) {
100 $message = json_decode($response->getBody())->message;
101 } else {
102 $message = $response->getBody();
103 }
104 throw $this->getException($message, $rc);
105 }
106
107 $json = json_decode($response->getBody());
108 if (($link = $response->getHeader("Link", Header::class))) {
109 $links = $this->parseLinks($link);
110 } else {
111 $links = [];
112 }
113
114 if (isset($json->error)) {
115 throw $this->getException($json->error_description, $rc);
116 } elseif (($cache = $this->getStorage($ttl))) {
117 $cache->set($this->getCacheKey(), [$json, $links], $ttl);
118 }
119
120 $callback($json, $links);
121
122 return true;
123 };
124 }
125
126 function enqueue(callable $callback) {
127 $request = $this->getRequest();
128 $wrapper = $this->wrap($callback);
129 return $this->api->getClient()->enqueue($request, $wrapper);
130 }
131 }