Skip to content
This repository has been archived by the owner on Apr 4, 2022. It is now read-only.

Adopt fluent syntax for client calls #15

Merged
merged 12 commits into from
Aug 27, 2021
53 changes: 32 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,22 @@ The library is PHP agnostic but provides deep integration with [Laravel](https:/
Here's an example how you'd use it:

```php
use GitHub\Sponsors\GitHubSponsors;
use GitHub\Sponsors\Client;
use Illuminate\Http\Client\Factory;

$client = new GitHubSponsors(new Factory(), getenv('GH_SPONSORS_TOKEN'));
$client = new Client(getenv('GH_SPONSORS_TOKEN'));

// Check if driesvints is being sponsored by nunomaduro...
$client->isSponsoredBy('driesvints', 'nunomaduro');
$client->login('driesvints')->isSponsoredBy('nunomaduro');

// Check if the blade-ui-kit organization is being sponsored by nunomaduro...
$client->isSponsoredBy('blade-ui-kit', 'nunomaduro');
// Check if the blade-ui-kit organization is sponsored by nunomaduro...
$client->login('nunomaduro')->isSponsoring('blade-ui-kit');

// Check if the authenticated user is sponsored by Gummibeer...
$client->viewer()->isSponsoredBy('Gummibeer');

// Check if the authenticated user is sponsoring by driesvints...
$client->viewer()->isSponsoring('driesvints');
```

## Roadmap
Expand Down Expand Up @@ -91,10 +97,10 @@ All of this library's API calls are made from the core `GitHub\Sponsors\GitHubSp
To get started, initialize the GitHub API client, authenticate using the token (preferable through an environment variable) and initialize the Sponsors client:

```php
use GitHub\Sponsors\GitHubSponsors;
use GitHub\Sponsors\Client;
use Illuminate\Http\Client\Factory;

$client = new GitHubSponsors(new Factory(), getenv('GH_SPONSORS_TOKEN'));
$client = new Client(new Factory(), getenv('GH_SPONSORS_TOKEN'));
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved
```

This will be the client we'll use throughout the rest of these docs. We'll re-use the `$client` variable in the below examples.
Expand All @@ -104,9 +110,9 @@ This will be the client we'll use throughout the rest of these docs. We'll re-us
If you're using Laravel, the client is already bound to the container as a singleton. Simply retrieve it from the container:

```php
use GitHub\Sponsors\GitHubSponsors;
use GitHub\Sponsors\Client;

$client = app(GitHubSponsors::class);
$client = app(Client::class);
```

The client was authenticated with the env variable you've set in your `.env` file.
Expand All @@ -116,29 +122,33 @@ The client was authenticated with the env variable you've set in your `.env` fil
At its core, this library allows you to easily check wether a specific user or organization is sponsoring another one:

```php
/** @var \GitHub\Sponsors\Client $client */
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved

// Check if driesvints is being sponsored by nunomaduro...
$client->isSponsoredBy('driesvints', 'nunomaduro');
$client->login('driesvints')->isSponsoredBy('nunomaduro');

// Check if the blade-ui-kit organization is being sponsored by nunomaduro...
$client->isSponsoredBy('blade-ui-kit', 'nunomaduro');
$client->login('blade-ui-kit')->isSponsoredBy('nunomaduro');
```

### Checking Sponsorships as a Viewer

You can also perform these checks from the point-of-view of the user that was used to authenticate the GitHub API client. If you'll use the methods below, it would be as if you'd be browsing GitHub as the user that created the token.

```php
/** @var \GitHub\Sponsors\Client $client */
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved

// Is the current authed user sponsoring driesvints?
$client->isViewerSponsoring('driesvints');
$client->viewer()->isSponsoring('driesvints');

// Is the current authed user sponsoring the laravel organization?
$client->isViewerSponsoring('laravel');
$client->viewer()->isSponsoring('laravel');

// Is the current authed user sponsored by driesvints?
$client->isViewerSponsoredBy('driesvints');
$client->viewer()->isSponsoredBy('driesvints');

// Is the current authed user sponsored by the laravel organization?
$client->isViewerSponsoredBy('laravel');
$client->viewer()->isSponsoredBy('laravel');
```

You might be wondering why we're using the "Viewer" wording here. "Viewer" is also a concept in the GraphQL API of GitHub. It represents the currently authenticated user that's performing the API requests. That's why we've decided to also use this terminology in the package's API.
Expand All @@ -148,11 +158,12 @@ You might be wondering why we're using the "Viewer" wording here. "Viewer" is al
If you use Laravel you can also make use of the shipped `GitHubSponsors` facade:

```php
use GitHub\Sponsors\Facades\GitHubSponsors;
// Check if driesvints is being sponsored by nunomaduro...
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved
GitHubSponsors::isSponsoredBy('driesvints', 'nunomaduro');
GitHubSponsors::login('driesvints')->isSponsoredBy('nunomaduro');

// Check if the blade-ui-kit organization is being sponsored by nunomaduro...
GitHubSponsors::isSponsoredBy('blade-ui-kit', 'nunomaduro');
GitHubSponsors::login('blade-ui-kit')->isSponsoredBy('nunomaduro');
```

### Sponsorable Behavior
Expand Down Expand Up @@ -274,23 +285,23 @@ When providing the sponsorable with a token, it'll initialize a new GitHub clien

```php
use GitHub\Sponsors\Concerns\Sponsorable;
use GitHub\Sponsors\GitHubSponsors;
use GitHub\Sponsors\Clients\Login;

class User
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved
{
use Sponsorable;

private GitHubSponsors $client;
private Login $client;

private string $github;

public function __construct(GitHubSponsors $client, string $github)
public function __construct(Login $client, string $github)
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved
{
$this->client = $client;
$this->github = $github;
}

protected function sponsorsClient(): GitHubSponsors
protected function sponsorsClient(): Login
{
return $this->client;
}
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"extra": {
"laravel": {
"aliases": {
"GitHubSponsors": "GitHub\\Sponsors\\Facades\\GitHubSponsorsFacade"
"GitHubSponsors": "GitHubSponsors"
},
"providers": [
"GitHub\\Sponsors\\GitHubSponsorsServiceProvider"
Expand Down
29 changes: 29 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace GitHub\Sponsors;

use GitHub\Sponsors\Clients\Login;
use GitHub\Sponsors\Clients\Viewer;
use Illuminate\Http\Client\Factory;

final class Client
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge the logic of this class with GraphqlClient and name it Client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was that the Client is more a Factory now - possibly we should rename it!?
And the GraphqlClient only cares about sending GraphQL queries to GitHub.

Merging them would also mean that I would have to pass an instance of Client to the Login/Viewer classes which would mean that they could also call themselves or the other client.

{
private GraphqlClient $graphql;

public function __construct(string $token)
{
$this->graphql = new GraphqlClient(new Factory(), $token);
}

public function viewer(): Viewer
{
return new Viewer($this->graphql);
}

public function login(string $login): Login
{
return new Login($this->graphql, $login);
}
}
69 changes: 69 additions & 0 deletions src/Clients/Login.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved

namespace GitHub\Sponsors\Clients;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this back to the GitHub\Sponsors namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the coming things in mind I think that having them in a dedicated namespace than all in package root is a better idea to keep classes structured and organized.


use GitHub\Sponsors\Contracts\Sponsorable;
use GitHub\Sponsors\GraphqlClient;

final class Login implements Sponsorable
{
private GraphqlClient $client;

private string $login;

public function __construct(GraphqlClient $client, string $login)
{
$this->client = $client;
$this->login = $login;
}

public function isSponsoredBy(string $sponsor): bool
{
$query = <<<'QUERY'
query (
$account: String!
$sponsor: String!
) {
user(login: $account) {
isSponsoredBy(accountLogin: $sponsor)
}
organization(login: $account) {
isSponsoredBy(accountLogin: $sponsor)
}
}
QUERY;

$result = $this->client->send($query, [
'account' => $this->login,
'sponsor' => $sponsor,
]);

return ($result['user']['isSponsoredBy'] ?? false) ||
($result['organization']['isSponsoredBy'] ?? false);
}

public function isSponsoring(string $account): bool
{
$query = <<<'QUERY'
query (
$account: String!
$sponsor: String!
) {
user(login: $account) {
isSponsoredBy(accountLogin: $sponsor)
}
organization(login: $account) {
isSponsoredBy(accountLogin: $sponsor)
}
}
QUERY;

$result = $this->client->send($query, [
'account' => $account,
'sponsor' => $this->login,
]);

return ($result['user']['isSponsoredBy'] ?? false) ||
($result['organization']['isSponsoredBy'] ?? false);
}
}
58 changes: 58 additions & 0 deletions src/Clients/Viewer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
Gummibeer marked this conversation as resolved.
Show resolved Hide resolved

namespace GitHub\Sponsors\Clients;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this back to the GitHub\Sponsors namespace.


use GitHub\Sponsors\Contracts\Sponsorable;
use GitHub\Sponsors\GraphqlClient;

final class Viewer implements Sponsorable
{
private GraphqlClient $client;

public function __construct(GraphqlClient $client)
{
$this->client = $client;
}

public function isSponsoredBy(string $sponsor): bool
{
$query = <<<'QUERY'
query (
$sponsor: String!
) {
user(login: $sponsor) {
isSponsoringViewer
}
organization(login: $sponsor) {
isSponsoringViewer
}
}
QUERY;

$result = $this->client->send($query, compact('sponsor'));

return ($result['user']['isSponsoringViewer'] ?? false) ||
($result['organization']['isSponsoringViewer'] ?? false);
}

public function isSponsoring(string $account): bool
{
$query = <<<'QUERY'
query (
$account: String!
) {
user(login: $account) {
viewerIsSponsoring
}
organization(login: $account) {
viewerIsSponsoring
}
}
QUERY;

$result = $this->client->send($query, compact('account'));

return ($result['user']['viewerIsSponsoring'] ?? false) ||
($result['organization']['viewerIsSponsoring'] ?? false);
}
}
24 changes: 11 additions & 13 deletions src/Concerns/Sponsorable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@

namespace GitHub\Sponsors\Concerns;

use GitHub\Sponsors\GitHubSponsors;
use Illuminate\Http\Client\Factory;
use GitHub\Sponsors\Client;
use GitHub\Sponsors\Clients\Login;

trait Sponsorable
{
public function isSponsoredBy(string $sponsor): bool
{
return $this->sponsorsClient()->isSponsoredBy(
$this->gitHubUsername(), $sponsor
);
return $this->sponsorsClient()
->isSponsoredBy($sponsor);
}

public function isSponsoring(string $account): bool
{
return $this->sponsorsClient()->isSponsoredBy(
$account, $this->gitHubUsername()
);
return $this->sponsorsClient()
->isSponsoring($account);
}

public function gitHubUsername(): string
Expand All @@ -38,12 +36,12 @@ public function hasGitHubToken(): bool
return $this->gitHubToken() !== null;
}

protected function sponsorsClient(): GitHubSponsors
protected function sponsorsClient(): Login
{
if (! $this->hasGitHubToken()) {
return app(GitHubSponsors::class);
}
$factory = $this->hasGitHubToken()
? new Client($this->gitHubToken())
: app(Client::class);

return new GitHubSponsors(new Factory(), $this->gitHubToken());
return $factory->login($this->gitHubUsername());
}
}
10 changes: 10 additions & 0 deletions src/Contracts/Sponsorable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace GitHub\Sponsors\Contracts;

interface Sponsorable
{
public function isSponsoredBy(string $sponsor): bool;

public function isSponsoring(string $account): bool;
}
22 changes: 22 additions & 0 deletions src/Facades/GitHubSponsors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace GitHub\Sponsors\Facades;

use GitHub\Sponsors\Client;
use Illuminate\Support\Facades\Facade;

/**
* @method static \GitHub\Sponsors\Clients\Viewer viewer()
* @method static \GitHub\Sponsors\Clients\Login login(string $login)
*
* @see \GitHub\Sponsors\Client
*/
final class GitHubSponsors extends Facade
{
protected static function getFacadeAccessor(): string
{
return Client::class;
}
}