PHP GitHub Sponsors is a package that integrates directly with the GitHub Sponsors GraphQL API.

Overview

PHP GitHub Sponsors

Tests Code Style Latest Stable Version Total Downloads

PHP GitHub Sponsors is a package that integrates directly with the GitHub Sponsors GraphQL API. Using it, you can easily check if a GitHub account is sponsoring another account. This helps you implement powerful ACL capibilities in your application and the ability to grant users access to specific resources when they sponsor you.

The library is PHP agnostic but provides deep integration with Laravel.

Here's an example how you'd use it:

use GitHub\Sponsors\Client;

$client = new Client(getenv('GH_SPONSORS_TOKEN'));

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

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

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

// Get all of the sponsors for Gummibeer...
$sponsors = $client->login('Gummibeer')->sponsors();

Roadmap

Here's some of the features on our roadmap. We'd always appreciate PR's to kickstart these.

Not seeing the feature you seek? Consider opening up an issue.

Requirements

  • PHP 7.4 or higher
  • Laravel 8.0 or higher (optional when using Laravel)

Installation

Install the package with composer:

composer require github-php/sponsors

Updating

Please refer to the upgrade guide when updating the library.

Configuration

Authentication

All of the GitHub GraphQL autentication goes through a personal access token. A token is always needed when working with the GitHub GraphQL.

To get started using this library, head over to your settings screen and create a personal access token that has access to the user:read and org:read scopes. This is the token that you'll use in the code examples below.

It's important to note that this will be the main point-of-view of how the GraphQL will view sponsorships so make sure to pick the correct user account. For example, if you're Laravel and you need to perform checks to see if anyone is sponsoring Laravel publically or privately, the token should be created under someone who has access to the Laravel organization (like taylorotwell).

Authentication in Laravel

If you're integrating with Laravel, the package will be set up automatically through Package Discovery. The only thing that's left to do is to set the personal access token in your .env file:

GH_SPONSORS_TOKEN=ghp_xxx

Usage

Initializing the client

All of this library's API calls are made from the core GitHub\Sponsors\Client class. The client makes use of the Illuminate HTTP Client client to perform the API calls. This client needs to be authenticated using the GitHub Personal Access token which you've created in the authentication step above.

To get started, initialize the GitHub API client, authenticate using the token (preferable through an environment variable) and initialize the Sponsors client:

use GitHub\Sponsors\Client;

$client = new Client(getenv('GH_SPONSORS_TOKEN'));

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.

Initializing the client using Laravel

If you're using Laravel, the client is already bound to the container as a singleton. Simply retrieve it from the container:

use GitHub\Sponsors\Client;

$client = app(Client::class);

The client was authenticated with the env variable you've set in your .env file.

Checking Sponsorships

At its core, this library allows you to easily check wether a specific user or organization is sponsoring another one:

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

// Check if the blade-ui-kit organization is being sponsored by 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.

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

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

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

// Is the current authed user sponsored by the laravel organization?
$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.

Checking Sponsorships with a Facade

If you use Laravel you can also make use of the shipped GitHubSponsors facade:

use GitHub\Sponsors\Facades\GitHubSponsors;

// Check if driesvints is being sponsored by nunomaduro...
GitHubSponsors::login('driesvints')->isSponsoredBy('nunomaduro');

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

Retrieving Sponsors

You can also use the client to retrieve sponsorships:

$sponsors = $client->login('Gummibeer')->sponsors();

This will return an instance of Illuminate\Support\LazyCollection which contains the lazy loaded sponsorships of the given account.

Additionally, you may retrieve additional fields that are available on the User and Organization objects:

$sponsors = $client->login('Gummibeer')->sponsors(['avatarUrl', 'name']);

foreach ($sponsors as $sponsor) {
    $sponsor['avatarUrl']; // The sponsor's GitHub avatar url...
    $sponsor['name']; // The sponsor's GitHub name...
}

Lastly you may use the hasSponsors check to see if an account has any sponsors at all:

if ($client->login('Gummibeer')->hasSponsors() {
    // ...
}

Sponsorable Behavior

PHP GitHub Sponsors ships with a Sponsorable trait that can add sponsorable behavior to an object. Let's say you have a User object in your app. By letting that user provide a personal access token of their own, you can perform sponsorship checks on them as if they were browsing GitHub themselves.

The Sponsorable trait

To get started, add the trait to any object you want to use it on and set the user's GitHub username and their personal access token:

use GitHub\Sponsors\Concerns\Sponsorable;
use GitHub\Sponsors\Contracts\Sponsorable as SponsorableContract;

class User implements SponsorableContract
{
    use Sponsorable;

    private string $github;

    private string $github_token;

    public function __construct(string $github, string $github_token)
    {
        $this->github = $github;
        $this->github_token = $github_token;
    }
}

Notice that we also added the GitHub\Sponsors\Contracts\Sponsorable to make sure the API is properly implemented on the User class.

The $github_token can be the same personal access token you use to initialize the GitHub\Sponsors\Client class but if you also want to check private sponsorships on the user you'll need them to provide you with their own token.

⚠️ Note that there is no check being performed on wether the github username and a user provided personal access token belong together. This is your own responsibility to do through an API call to GitHub.

Using the sponsorable

Now that we've configured our object, we can use it to perform GitHub Sponsors checks against:

$user = new User('driesvints', getenv('GH_SPONSORS_TOKEN'));

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

// Check if driesvints is being sponsored by the blade-ui-kit organization...
$user->isSponsoredBy('blade-ui-kit');

// Check if driesvints is sponsoring nunomaduro...
$user->isSponsoring('nunomaduro');

// Check if driesvints is sponsoring spatie...
$user->isSponsoring('spatie');

// Retrieve all of the sponsors for driesvints...
$sponsors = $user->sponsors();

// Check if driesvints has any sponsors...
$user->hasSponsors();

Using the Sponsorable trait with Eloquent

If your sponsorable is an Eloquent model from Laravel, the setup differs a bit:

use GitHub\Sponsors\Concerns\Sponsorable;
use GitHub\Sponsors\Contracts\Sponsorable as SponsorableContract;
use Illuminate\Database\Eloquent\Model;

class User extends Model implements SponsorableContract
{
    use Sponsorable;
}

What's important is that there's a github column (string) on the model's table. This column will need to have the GitHub username that belongs to the model.

With an Eloquent model, you also don't need to pass a personal access token. By default, it'll use the GitHub\Sponsors\Client class that's bound to the container. If you do want to identify the sponsorable to also check their private sponsorships you can add a github_token column (string) to the model's table and make sure the value is filled in. That way, all API requests will behave as if the user themselves is doing it.

⚠️ Note that there is no check being performed on wether the github username and a user provided personal access token belong together. This is your own responsibility to do through an API call to GitHub.

And then you can use the model as follows:

$user = User::where('github', 'driesvints')->first();

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

Customizing the Sponsorable properties

If you want to customize the $github & $github_token property names you'll also need to update their getters:

use GitHub\Sponsors\Concerns\Sponsorable;
use GitHub\Sponsors\Contracts\Sponsorable as SponsorableContract;

class User implements SponsorableContract
{
    use Sponsorable;

    private string $gitHubUsername;

    private string $gitHubToken;

    public function __construct(string $gitHubUsername, string $gitHubToken)
    {
        $this->gitHubUsername = $gitHubUsername;
        $this->gitHubToken = $gitHubToken;
    }

    public function gitHubUsername(): string
    {
        return $this->gitHubUsername;
    }

    public function gitHubToken(): ?string
    {
        return $this->gitHubToken;
    }
}

Customizing the Sponsorable client

When providing the sponsorable with a token, it'll initialize a new GitHub client. You may also provide the pre-set client if you wish:

use GitHub\Sponsors\Client;
use GitHub\Sponsors\Concerns\Sponsorable;
use GitHub\Sponsors\Contracts\Sponsorable as SponsorableContract;

class User implements SponsorableContract
{
    use Sponsorable;

    private Client $client;

    private string $github;

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

    protected function sponsorsClient(): Client
    {
        return $this->client;
    }
}

Tutorials

Usage in Laravel Policies

PHP GitHub Sponsors is an ideal way to grant your users access to certain resources in your app. Therefor, it's also an ideal candidate for a Laravel policy. For example, you could write a policy that grants access to a product when a user is sponsoring you.

First, you'll have to set the GH_SPONSORS_TOKEN in your .env file. This token needs to be created by the user that's being sponsored or a user that is a member of the organization that's being sponsored. Then, the client will be authenticated with this token.

Next, you'll need to add the Sponsorable trait to your User model. Additionally, you'll need to make sure that the users database has a github column (VARCHAR(255)) and all users have their GitHub usernames filled out.

Then, we'll write out policy. Let's say that we're creating this policy for Spatie:



namespace App\Policies;

use App\Models\User;

class ProductPolicy
{
    /**
     * Determine if a product can be reached by the user.
     *
     * @param  \App\Models\User  $user
     * @return bool
     */
    public function view(User $user)
    {
        return $user->isSponsoring('spatie');
    }
}

We wire up the policy in the AuthServiceProvider of our app:

use App\Models\Product;
use App\Policies\ProductPolicy;

/**
 * The policy mappings for the application.
 *
 * @var array
 */
protected $policies = [
    Product::class => ProductPolicy::class,
];

And now we can use the policy to do ACL checks to see if the authenticated user can access Spatie's products:

View Products @else Sponsor us to use our products! @endcan ">
@can('view', App\Models\Product::class)
    <a href="{{ route('products') }}">
        View Products
    a>
@else
    <a href="https://github.com/sponsors/spatie">
        Sponsor us to use our products!
    a> 
@endcan

And that's it. Of course, you'd probably also want to protect any controller giving access to the products route.

FAQ

Why is the sponsorship check returning false for private sponsorship checks?

The way the GitHub GraphQL mostly works is through personal access tokens. Because these tokens are always created from a specific user in GitHub, the API calls will return results based on the visibility of the user and their access to the target resource.

For example, if I as driesvints were to privately sponsor spatie I could do an ->login('driesvints')->isSponsoredBy('spatie') check and it would return true for me because I have access to my account through my personal access token that was created on driesvints. But if nunomaduro would be privately sponsoring spatie and I was to attempt ->login('nunomaduro')->isSponsoredBy('spatie') with the token created on driesvints, it will return false because I don't have access to nunomaduro's account.

It is also important that if you're checking against organizations that you're using a token of a user that is a member of the organization. Any other GitHub user will not have access to check private sponsorships for that organization.

Public sponsorships will always be visible though, regardless on which user the token was created.

Why are the user:read and org:read scopes needed?

These are both needed to authenticate the GitHub client to perform checks on a user's private sponsorships. Since by default these are hidden from any public API call, we need to explicitely grant consumers of the token permission to read these.

Changelog

Check out the CHANGELOG in this repository for all the recent changes.

Maintainers

PHP GitHub Sponsors is developed and maintained by Dries Vints and Tom Witkowski.

License

PHP GitHub Sponsors is open-sourced software licensed under the MIT license.

Comments
  • Adopt fluent syntax for client calls

    Adopt fluent syntax for client calls

    resolves #13

    This PR switches the current single method calls to a fluent builder style for easier readability and this also allows us to use different classes per context - as the GraphQL queries for viewer and user/organization are different and also allow different things. For example only a viewer can retrieve the tiers for a sponsorship.

    I renamed and changed some more class names in that context as I think they match better now. But I'm open for discussion here and change things back.

    enhancement 
    opened by Gummibeer 1
  • Adopt fluent syntax for client calls

    Adopt fluent syntax for client calls

    Improve the API to work more like https://github.com/Astrotomic/laravel-github-sponsors

    // Before...
    $client->isSponsoredBy('driesvints', 'nunomaduro');
    $client->isViewerSponsoring('driesvints');
    $client->isViewerSponsoredBy('driesvints');
    
    // After...
    $client->login('driesvints')->isSponsoredBy('nunomaduro');
    $client->viewer()->isSponsoring('driesvints');
    $client->viewer()->isSponsoredBy('driesvints');
    
    enhancement 
    opened by driesvints 0
  • Drop organization methods

    Drop organization methods

    Ideally we'd like to get rid of the organization methods so the user doesn't needs to know up front if they're checking a user or organization. An idea opted by @claudiodekker was to perform both the user and organization query with the username login and check which one would give the result:

    query { 
      user(login: "driesvints") {
        viewerIsSponsoring
      },
      organization(login: "driesvints") {
        viewerIsSponsoring
      }
    }
    

    I think this would work. We'd have to rewrite some internals but then we could drop organization specific methods in the library.

    enhancement 
    opened by driesvints 0
  • Retrieve sponsorships

    Retrieve sponsorships

    Retrieving a list of sponsorships should be a core feature of this library. With this, people can display the sponsorships on their app/website as well as do additional syncing in their app. The sponsorships on a GitHub account can be retrieved with the sponsorshipsAsMaintainer field. Ideally, you we'd hydrate a new GitHubSponsor object with the data from the GitHub account.

    The api could like like this:

    // Retrieve all sponsors of driesvints...
    $sponsors = $client->sponsors('driesvints');
    
    // With the Sponsorable trait...
    $sponsors = $user->sponsors();
    
    // Check if a user has sponsors...
    $sponsors = $user->hasSponsors();
    

    Which would return a lazy collection. I'd also opt to implement a cursor based paginator approach as well:

    // Retrieve all sponsors of driesvints...
    $sponsors = $client->paginateSponsors('driesvints');
    

    Which would return an instance of Illuminate\Pagination\CursorPaginator. I'd also make use of BuildsWithQueries to resolve the cursor from the request for a Laravel implementation. See PaginationState.

    enhancement 
    opened by driesvints 0
  • Dedicated docs site

    Dedicated docs site

    Ideally we'd build a dedicated documentation website with separate PHP-only and Laravel sections so it's more clear how to use the library in specific situations.

    enhancement 
    opened by driesvints 0
  • Fake GraphQL requests with HTTP client

    Fake GraphQL requests with HTTP client

    To speed things up we should fake the GraphQL requests. This will also be necessary to allow pull requests from GitHub since those won't be authenticated with a token and thus all PR's will fail.

    We should also keep a portion of an integration test suite with a real token but those tests can be skipped if no token is set on the environment.

    enhancement 
    opened by driesvints 1
  • Implement a check to see if a username and token belong together

    Implement a check to see if a username and token belong together

    For our Sponsorable trait we offer to set a GitHub username and token on the implementing class. But we don't actually check if the user or the token belong together. It would be good if we offered a way to users to do this or to either do this ourselves in the library before making API requests.

    The way we could check this is to auth the client with the token and retrieve the user details, then check if the username is the same as the one set on the object.

    enhancement 
    opened by driesvints 0
  • Add migrations to package

    Add migrations to package

    Ideally we'd ship with a migration to add the github and github_token columns to the users table for Laravel.

    Make use of the same way of ignoring migrations in Laravel first party packages if people don't want these to run automatically with the packge: https://laravel.com/docs/8.x/billing#database-migrations

    enhancement 
    opened by driesvints 0
  • More sponsorship methods

    More sponsorship methods

    Extend the API with even more useful methods:

    // Check if driesvints has a sponsor listing...
    $client->hasSponsorsListing('driesvints');
    
    // Check if driesvints can sponsor nunomaduro...
    $client->canSponsor('driesvints', 'nunomaduro');
    
    // Check if driesvints is privately sponsored by nunomaduro...
    $client->isPrivatelySponsoredBy('driesvints', 'nunomaduro');
    
    enhancement 
    opened by driesvints 0
Releases(0.3.2)
Owner
GitHub PHP
Packages for PHP that integrate with the GitHub API's.
GitHub PHP
SimSimi Bot - a Telegram ChatBot like the old SimSimi app that simulates a normal chat experience, created directly by users

SimSimi Bot - a Telegram ChatBot like the old SimSimi app that simulates a normal chat experience, created directly by users

NeleB54Gold 4 Oct 21, 2022
Facebook GraphQL for Laravel 5. It supports Relay, eloquent models, validation and GraphiQL.

Laravel GraphQL This package is no longuer maintained. Please use rebing/graphql-laravel or other Laravel GraphQL packages Use Facebook GraphQL with L

Folklore Inc. 1.8k Dec 11, 2022
A simple PHP GitHub API client, Object Oriented, tested and documented.

PHP GitHub API A simple Object Oriented wrapper for GitHub API, written with PHP. Uses GitHub API v3 & supports GitHub API v4. The object API (v3) is

KNP Labs 2k Jan 7, 2023
PHP library for the GitHub API v3

GitHub API v3 - PHP Library Currently under construction. Overview Provides access to GitHub API v3 via an Object Oriented PHP library. The goal of th

Darren Rees 62 Jul 28, 2022
A GitHub API bridge for Laravel

Laravel GitHub Laravel GitHub was created by, and is maintained by Graham Campbell, and is a PHP GitHub API bridge for Laravel. It utilises my Laravel

Graham Campbell 547 Dec 30, 2022
Generate pretty release changelogs using the commit log and Github API.

zenstruck/changelog Generate pretty release changelogs using the commit log and Github API. Changelog entries are in the following format: {short hash

Kevin Bond 3 Jun 20, 2022
This package is a simple API laravel wrapper for Pokemontcg with a sleek Model design for API routes and authentication.

This package is a simple API laravel wrapper for Pokemontcg with a sleek Model design for API routes and authentication.

Daniel Henze 3 Aug 29, 2022
GitHub Action to dynamically update CONTRIBUTORS file

Generate / Update CONTRIBUTORS File - GitHub Action This GitHub Action updates a CONTRIBUTORS file with the top contributors from the specified projec

minicli 86 Dec 21, 2022
A discord bot for creating github repo issues.

Discord Issue Bot A discord bot for creating github repo issues. Requires: php-zlib, php-json, mysql, composer Tested on: Ubuntu 20.04.3, PHP Version

null 1 Jan 20, 2022
PHP package to manage google-api interactions

Google-api-client PHP package to manage google-api interactions Supports: Google Drive API Google Spreadsheet API Installation composer require obrio-

OBRIO 3 Apr 28, 2022
PHP package for the Limg.app website - allowing to upload images via the API of the website.

Limg PHP Client Package. Installation You can install the package via composer: composer require havenstd06/limg-php-client Usage use Havenstd06\Limg\

Thomas 3 Jul 27, 2021
🌐 Free Google Translate API PHP Package. Translates totally free of charge.

Google Translate PHP Free Google Translate API PHP Package. Translates totally free of charge. Installation Basic Usage Advanced Usage Language Detect

Levan Velijanashvili 1.5k Dec 31, 2022
PHP package providing easy and fast access to Twitter API V2.

Twitter API V2 is a PHP package that provides an easy and fast access to Twitter REST API for Version 2 endpoints.

Julien SCHMITT 38 Dec 12, 2022
Nexmo REST API client for PHP. API support for SMS, Voice, Text-to-Speech, Numbers, Verify (2FA) and more.

Client Library for PHP Support Notice This library and it's associated packages, nexmo/client and nexmo/client-core have transitioned into a "Maintena

Nexmo 75 Sep 23, 2022
OpenAI API Client is a component-oriented, extensible client library for the OpenAI API. It's designed to be faster and more memory efficient than traditional PHP libraries.

OpenAI API Client in PHP (community-maintained) This library is a component-oriented, extensible client library for the OpenAI API. It's designed to b

Mounir R'Quiba 6 Jun 14, 2023
A simple API documentation package for Laravel using OpenAPI and Redoc

Laravel Redoc Easily publish your API documentation using your OpenAPI document in your Laravel Application. Installation You can install this package

Steve McDougall 15 Dec 27, 2022
Package to fetch cryptocurrency price, market value, assets etc. using coincap API endpoints

cryptocap-pkg Package to fetch cryptocurrency price, market value, assets etc. using coincap API endpoints. This package was developed to work with co

Wisdom Diala 14 Nov 8, 2022
This package generates API resources with keys preset to their respective table's columns

Ever thought it was a bit tedious to define an API resource for a large table? This package makes life a bit simpler by presetting all columns in a Resource, so you can simply remove the ones you don't need, instead of adding the ones you need.

Protoqol 22 Jun 21, 2022
Laravel 8.x package wrapper library for Metatrader 5 Web API

Laravel 8.x package wrapper library for Metatrader 5 Web API

Ali A. Dhillon 10 Nov 13, 2022