1+ <?php
2+
3+ namespace Astrotomic\GithubSponsors;
4+
5+ use Astrotomic\GraphqlQueryBuilder\Graph;
6+ use Astrotomic\GraphqlQueryBuilder\Query;
7+ use Exception;
8+ use Generator;
9+ use Illuminate\Support\Arr;
10+ use Illuminate\Support\Collection;
11+ use Illuminate\Support\Facades\Http;
12+ use Illuminate\Support\Fluent;
13+ use Illuminate\Support\LazyCollection;
14+
15+ class GithubSponsors
16+ {
17+ protected string $fromName;
18+ protected array $fromArguments = [];
19+ protected array $select = [
20+ 'login'
21+ ];
22+ protected string $token;
23+
24+ public function __construct(string $token)
25+ {
26+ $this->token = $token;
27+ }
28+
29+ public function fromViewer(): self
30+ {
31+ $this->fromName = 'viewer';
32+ $this->fromArguments = [];
33+
34+ return $this;
35+ }
36+
37+ public function fromUser(string $login): self
38+ {
39+ $this->fromName = 'user';
40+ $this->fromArguments = [
41+ 'login' => $login,
42+ ];
43+
44+ return $this;
45+ }
46+
47+ public function fromOrganization(string $login): self
48+ {
49+ $this->fromName = 'organization';
50+ $this->fromArguments = [
51+ 'login' => $login,
52+ ];
53+
54+ return $this;
55+ }
56+
57+ public function select(string ...$fields): self
58+ {
59+ $this->select = $fields;
60+
61+ return $this;
62+ }
63+
64+ public function all(): Collection
65+ {
66+ return $this->cursor()->collect();
67+ }
68+
69+ public function cursor(): LazyCollection
70+ {
71+ return LazyCollection::make(function (): Generator {
72+ $cursor = null;
73+
74+ do {
75+ $data = $this->request($this->query($cursor));
76+ $cursor = $data['pageInfo']['endCursor'];
77+
78+ foreach (data_get($data, 'nodes.*.sponsorEntity') as $sponsor) {
79+ yield new Fluent($sponsor);
80+ }
81+ } while ($data['pageInfo']['hasNextPage'] ?? false);
82+ });
83+ }
84+
85+ protected function query(?string $after = null): string
86+ {
87+ return (string) Graph::query(
88+ Query::from($this->fromName)
89+ ->with($this->fromArguments)
90+ ->select(
91+ Query::from('sponsorshipsAsMaintainer')
92+ ->with(array_filter(['first' => 100, 'after' => $after]))
93+ ->select(
94+ Query::from('pageInfo')->select('hasNextPage', 'endCursor'),
95+ Query::from('nodes')->select(
96+ Query::from('sponsorEntity')->select(
97+ '__typename',
98+ Query::for('User')->select(...$this->select),
99+ Query::for('Organization')->select(...$this->select),
100+ )
101+ )
102+ )
103+ )
104+ );
105+ }
106+
107+ protected function request(string $query): array
108+ {
109+ $response = Http::baseUrl('https://api.github.com')
110+ ->accept('application/vnd.github.v3+json')
111+ ->withUserAgent('astrotomic/laravel-github-sponsors')
112+ ->withOptions(['http_errors' => true])
113+ ->withToken($this->token)
114+ ->post('/graphql', ['query' => $query])
115+ ->json();
116+
117+ if (array_key_exists('errors', $response)) {
118+ throw new Exception(Arr::first($response['errors'])['message']);
119+ }
120+
121+ return data_get($response, "data.{$this->fromName}.sponsorshipsAsMaintainer");
122+ }
123+ }
0 commit comments