├── bin ├── git │ └── hooks │ │ └── pre-commit └── new-api-cli-test-client.php ├── examples ├── README.md └── users │ └── get_user_example.md ├── src ├── NewTwitchApi.php ├── NewTwitchApi │ ├── NewTwitchApi.php │ └── HelixGuzzleClient.php ├── Auth │ ├── AuthGuzzleClient.php │ └── OauthApi.php ├── Resources │ ├── GoalsApi.php │ ├── AdsApi.php │ ├── WebhooksApi.php │ ├── WhispersApi.php │ ├── HypeTrainApi.php │ ├── RaidsApi.php │ ├── CharityApi.php │ ├── GamesApi.php │ ├── TeamsApi.php │ ├── SearchApi.php │ ├── TagsApi.php │ ├── SubscriptionsApi.php │ ├── VideosApi.php │ ├── PollsApi.php │ ├── BitsApi.php │ ├── PredictionsApi.php │ ├── AnalyticsApi.php │ ├── AbstractResource.php │ ├── ClipsApi.php │ ├── ChannelsApi.php │ ├── EntitlementsApi.php │ ├── StreamsApi.php │ ├── ChannelPointsApi.php │ ├── ScheduleApi.php │ ├── UsersApi.php │ └── ChatApi.php ├── HelixGuzzleClient.php ├── RequestGenerator.php ├── Webhooks │ └── WebhooksSubscriptionApi.php └── TwitchApi.php ├── .gitignore ├── Makefile ├── .php-cs-fixer.dist.php ├── phpunit.xml.dist ├── spec └── TwitchApi │ ├── Auth │ ├── AuthGuzzleClientSpec.php │ └── OauthApiSpec.php │ ├── Resources │ ├── GoalsApiSpec.php │ ├── AdsApiSpec.php │ ├── WhispersApiSpec.php │ ├── RaidsApiSpec.php │ ├── HypeTrainApiSpec.php │ ├── CharityApiSpec.php │ ├── WebhooksApiSpec.php │ ├── SearchApiSpec.php │ ├── TeamsApiSpec.php │ ├── SubscriptionsApiSpec.php │ ├── GamesApiSpec.php │ ├── TagsApiSpec.php │ ├── BitsApiSpec.php │ ├── PollsApiSpec.php │ ├── PredictionsApiSpec.php │ ├── ClipsApiSpec.php │ ├── ChannelsApiSpec.php │ ├── AnalyticsApiSpec.php │ ├── VideosApiSpec.php │ ├── ScheduleApiSpec.php │ ├── EntitlementsApiSpec.php │ ├── ChatApiSpec.php │ └── UsersApiSpec.php │ ├── HelixGuzzleClientSpec.php │ └── TwitchApiSpec.php ├── LICENSE ├── composer.json ├── .github └── workflows │ └── test.yaml ├── test └── TwitchApi │ └── Resources │ └── UsersTest.php └── README.md /bin/git/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | ./vendor/bin/php-cs-fixer fix 3 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Examples 2 | 3 | #### Users 4 | - [Get User](users/get_user_example.md) 5 | 6 | More to come... 7 | -------------------------------------------------------------------------------- /src/NewTwitchApi.php: -------------------------------------------------------------------------------- 1 | run(); 10 | } catch (InvalidArgumentException $e) { 11 | echo $e->getMessage(); 12 | } 13 | -------------------------------------------------------------------------------- /src/Auth/AuthGuzzleClient.php: -------------------------------------------------------------------------------- 1 | self::BASE_URI, 17 | ]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in('src/') 5 | ->in('test/') 6 | ; 7 | 8 | $config = new PhpCsFixer\Config(); 9 | 10 | return $config->setRules([ 11 | '@PSR2' => true, 12 | '@Symfony' => true, 13 | 'phpdoc_annotation_without_dot' => false, 14 | 'phpdoc_no_alias_tag' => false, 15 | 'phpdoc_separation' => false, 16 | 'yoda_style' => false, 17 | ]) 18 | ->setFinder($finder) 19 | ; 20 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | test 7 | 8 | 9 | 10 | 11 | src 12 | 13 | src/ 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/users/get_user_example.md: -------------------------------------------------------------------------------- 1 | # Get User 2 | 3 | ## Supported API Versions 4 | 5 | v3 & v5 6 | 7 | ### v3 Example 8 | 9 | ```php 10 | $options = [ 11 | 'client_id' => 'YOUR-CLIENT-ID', 12 | 'api_version' => 3, 13 | ]; 14 | 15 | $twitchApi = new \TwitchApi\TwitchApi($options); 16 | $user = $twitchApi->getUser('summit1g'); 17 | ``` 18 | 19 | ### v5 Example 20 | 21 | ```php 22 | $options = [ 23 | 'client_id' => 'YOUR-CLIENT-ID', 24 | ]; 25 | 26 | $twitchApi = new \TwitchApi\TwitchApi($options); 27 | $user = $twitchApi->getUser(26490481); 28 | ``` 29 | -------------------------------------------------------------------------------- /src/Resources/GoalsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 20 | 21 | return $this->getApi('goals', $bearer, $queryParamsMap); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Resources/AdsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | $bodyParamsMap[] = ['key' => 'length', 'value' => $length]; 22 | 23 | return $this->postApi('channels/commercial', $bearer, [], $bodyParamsMap); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Resources/WebhooksApi.php: -------------------------------------------------------------------------------- 1 | 'first', 'value' => $first]; 21 | } 22 | if ($after) { 23 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 24 | } 25 | 26 | return $this->getApi('webhooks/subscriptions', $bearer, $queryParamsMap); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Resources/WhispersApi.php: -------------------------------------------------------------------------------- 1 | 'from_user_id', 'value' => $fromUserId]; 21 | $queryParamsMap[] = ['key' => 'to_user_id', 'value' => $toUserId]; 22 | 23 | $bodyParamsMap[] = ['key' => 'message', 'value' => $message]; 24 | 25 | return $this->postApi('whispers', $bearer, $queryParamsMap, $bodyParamsMap); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spec/TwitchApi/Auth/AuthGuzzleClientSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedThrough('getClient'); 13 | $this->shouldHaveType('\GuzzleHttp\Client'); 14 | 15 | /** @var Uri $uri */ 16 | $uri = $this->getConfig('base_uri'); 17 | $uri->getScheme()->shouldBe('https'); 18 | $uri->getHost()->shouldBe('id.twitch.tv'); 19 | $uri->getPath()->shouldBe('/oauth2/'); 20 | } 21 | 22 | function it_should_have_passed_in_config_params_instead_of_defaults() 23 | { 24 | $this->beConstructedThrough('getClient', [['base_uri' => 'https://different.url']]); 25 | $this->shouldHaveType('\GuzzleHttp\Client'); 26 | $this->getConfig('base_uri')->getHost()->shouldBe('different.url'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/GoalsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_goals_by_broadcaster_id(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'goals', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getGoals('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/AdsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_start_commercial(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('POST', 'channels/commercial', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'length', 'value' => 30]])->willReturn($request); 22 | $this->startCommercial('TEST_TOKEN', '123', 30)->shouldBe($response); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Resources/HypeTrainApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | if ($first) { 23 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 24 | } 25 | 26 | if ($cursor) { 27 | $queryParamsMap[] = ['key' => 'cursor', 'value' => $cursor]; 28 | } 29 | 30 | return $this->getApi('hypetrain/events', $bearer, $queryParamsMap); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/WhispersApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_send_a_whisper(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('POST', 'whispers', 'TEST_TOKEN', [['key' => 'from_user_id', 'value' => '123'], ['key' => 'to_user_id', 'value' => '456']], [['key' => 'message', 'value' => 'abc']])->willReturn($request); 22 | $this->sendWhisper('TEST_TOKEN', '123', '456', 'abc')->shouldBe($response); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 Nicholas Law 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/HelixGuzzleClient.php: -------------------------------------------------------------------------------- 1 | $clientId, 22 | 'Content-Type' => 'application/json', 23 | ]; 24 | 25 | $client_config = [ 26 | 'base_uri' => $baseUri, 27 | 'headers' => $headers, 28 | ]; 29 | 30 | if (isset($config['handler'])) { 31 | $client_config = []; 32 | } 33 | 34 | $client_config = array_merge($client_config, $config); 35 | 36 | $this->client = new Client($client_config); 37 | } 38 | 39 | public function getConfig($option = null) 40 | { 41 | return $this->client->getConfig($option); 42 | } 43 | 44 | public function send($request) 45 | { 46 | return $this->client->send($request); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nicklaw5/twitch-api-php", 3 | "type": "library", 4 | "description": "A Twitch API client for PHP.", 5 | "keywords": [ 6 | "twitch", 7 | "twitch.tv", 8 | "twitch-tv", 9 | "twitch-api", 10 | "api" 11 | ], 12 | "homepage": "http://github.com/nicklaw5/twitch-api-php", 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Nicholas Law", 17 | "homepage": "https://github.com/nicklaw5" 18 | }, 19 | { 20 | "name": "Brian Zwahr", 21 | "homepage": "https://github.com/echosa" 22 | }, 23 | { 24 | "name": "Brandin Arsenault", 25 | "homepage": "https://github.com/brandinarsenault" 26 | } 27 | ], 28 | "require": { 29 | "php": ">=7.4.0", 30 | "ext-json": "*", 31 | "guzzlehttp/guzzle": "~6.0|~7.0" 32 | }, 33 | "require-dev": { 34 | "friendsofphp/php-cs-fixer": "^3.10", 35 | "phpspec/phpspec": "^7.2", 36 | "phpunit/phpunit": "^9.5" 37 | }, 38 | "autoload": { 39 | "psr-4": { 40 | "TwitchApi\\": "src/", 41 | "TwitchApi\\Tests\\": "test/TwitchApi", 42 | "NewTwitchApi\\": "src/NewTwitchApi" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "Tests\\": "test/" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Resources/RaidsApi.php: -------------------------------------------------------------------------------- 1 | 'from_broadcaster_id', 'value' => $fromBroadcasterId]; 21 | $queryParamsMap[] = ['key' => 'to_broadcaster_id', 'value' => $toBroadcasterId]; 22 | 23 | return $this->postApi('raids', $bearer, $queryParamsMap); 24 | } 25 | 26 | /** 27 | * @throws GuzzleException 28 | * @link https://dev.twitch.tv/docs/api/reference#cancel-a-raid 29 | */ 30 | public function cancelRaid(string $bearer, string $toBroadcasterId): ResponseInterface 31 | { 32 | $queryParamsMap = []; 33 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $toBroadcasterId]; 34 | 35 | return $this->deleteApi('raids', $bearer, $queryParamsMap); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Run tests 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - master 8 | push: 9 | branches: 10 | - master 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | php: ['7.4', '8.0', '8.1'] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Setup PHP 24 | uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: "${{ matrix.php }}" 27 | 28 | # Cache Composer dependencies, based on the example at https://github.com/actions/cache/blob/main/examples.md#php---composer 29 | - name: Get Composer Cache Directory 30 | id: composer-cache 31 | run: echo "::set-output name=dir::$(composer config cache-files-dir)" 32 | 33 | - name: Cache Composer dependencies 34 | uses: actions/cache@v2 35 | with: 36 | path: ${{ steps.composer-cache.outputs.dir }} 37 | key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.lock') }} 38 | restore-keys: | 39 | php${{ matrix.php }}-composer- 40 | 41 | - name: Install dependencies using Composer 42 | run: composer install --prefer-source --no-interaction 43 | 44 | - name: Run tests 45 | run: make test 46 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/RaidsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_start_a_raid(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('POST', 'raids', 'TEST_TOKEN', [['key' => 'from_broadcaster_id', 'value' => '123'], ['key' => 'to_broadcaster_id', 'value' => '456']], [])->willReturn($request); 22 | $this->startRaid('TEST_TOKEN', '123', '456')->shouldBe($response); 23 | } 24 | 25 | function it_should_cancel_a_raid(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('DELETE', 'raids', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 28 | $this->cancelRaid('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/HypeTrainApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_hype_train_events(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'hypetrain/events', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getHypeTrainEvents('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_hype_train_events_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'hypetrain/events', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'first', 'value' => 100], ['key' => 'cursor', 'value' => 'abc']], [])->willReturn($request); 28 | $this->getHypeTrainEvents('TEST_TOKEN', '123', 100, 'abc')->shouldBe($response); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Resources/CharityApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 20 | 21 | return $this->getApi('charity/campaigns', $bearer, $queryParamsMap); 22 | } 23 | 24 | /** 25 | * @throws GuzzleException 26 | * @link https://dev.twitch.tv/docs/api/reference#get-charity-campaign-donations 27 | */ 28 | public function getCharityCampaignDonations(string $bearer, string $broadcasterId, int $first = null, string $after = null): ResponseInterface 29 | { 30 | $queryParamsMap = []; 31 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 32 | 33 | if ($first) { 34 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 35 | } 36 | 37 | if ($after) { 38 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 39 | } 40 | 41 | return $this->getApi('charity/donations', $bearer, $queryParamsMap); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /spec/TwitchApi/HelixGuzzleClientSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith('TEST_CLIENT_ID'); 13 | } 14 | 15 | function it_should_have_correct_base_uri() 16 | { 17 | $this->shouldHaveType('\TwitchApi\HelixGuzzleClient'); 18 | 19 | /** @var Uri $uri */ 20 | $uri = $this->getConfig('base_uri'); 21 | $uri->getScheme()->shouldBe('https'); 22 | $uri->getHost()->shouldBe('api.twitch.tv'); 23 | $uri->getPath()->shouldBe('/helix/'); 24 | } 25 | 26 | function it_should_have_client_id_header() 27 | { 28 | $this->shouldHaveType('\TwitchApi\HelixGuzzleClient'); 29 | $this->getConfig('headers')->shouldHaveKeyWithValue('Client-ID', 'TEST_CLIENT_ID'); 30 | } 31 | 32 | function it_should_have_json_content_type_header() 33 | { 34 | 35 | $this->shouldHaveType('\TwitchApi\HelixGuzzleClient'); 36 | $this->getConfig('headers')->shouldHaveKeyWithValue('Content-Type', 'application/json'); 37 | } 38 | 39 | function it_should_have_passed_in_config_params_instead_of_defaults() 40 | { 41 | $this->beConstructedWith('TEST_CLIENT_ID', ['base_uri' => 'https://different.url']); 42 | $this->shouldHaveType('\TwitchApi\HelixGuzzleClient'); 43 | $this->getConfig('base_uri')->getHost()->shouldBe('different.url'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/GamesApi.php: -------------------------------------------------------------------------------- 1 | 'id', 'value' => $id]; 21 | } 22 | foreach ($names as $name) { 23 | $queryParamsMap[] = ['key' => 'name', 'value' => $name]; 24 | } 25 | 26 | return $this->getApi('games', $bearer, $queryParamsMap); 27 | } 28 | 29 | /** 30 | * @throws GuzzleException 31 | * @link https://dev.twitch.tv/docs/api/reference/#get-top-games 32 | */ 33 | public function getTopGames(string $bearer, int $first = null, string $before = null, string $after = null): ResponseInterface 34 | { 35 | $queryParamsMap = []; 36 | 37 | if ($first) { 38 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 39 | } 40 | 41 | if ($before) { 42 | $queryParamsMap[] = ['key' => 'before', 'value' => $before]; 43 | } 44 | 45 | if ($after) { 46 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 47 | } 48 | 49 | return $this->getApi('games/top', $bearer, $queryParamsMap); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Resources/TeamsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | return $this->getApi('teams/channel', $bearer, $queryParamsMap); 23 | } 24 | 25 | /** 26 | * @throws GuzzleException 27 | * @link https://dev.twitch.tv/docs/api/reference#get-teams 28 | */ 29 | public function getTeams(string $bearer, string $name = null, string $id = null): ResponseInterface 30 | { 31 | $queryParamsMap = []; 32 | 33 | if ($name) { 34 | $queryParamsMap[] = ['key' => 'name', 'value' => $name]; 35 | } 36 | 37 | if ($id) { 38 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 39 | } 40 | 41 | return $this->getApi('teams', $bearer, $queryParamsMap); 42 | } 43 | 44 | /** 45 | * @throws GuzzleException 46 | */ 47 | public function getTeamsByName(string $bearer, string $name): ResponseInterface 48 | { 49 | return $this->getTeams($bearer, $name, null); 50 | } 51 | 52 | /** 53 | * @throws GuzzleException 54 | */ 55 | public function getTeamsById(string $bearer, string $id): ResponseInterface 56 | { 57 | return $this->getTeams($bearer, null, $id); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Resources/SearchApi.php: -------------------------------------------------------------------------------- 1 | 'query', 'value' => $query]; 21 | 22 | if ($first) { 23 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 24 | } 25 | 26 | if ($after) { 27 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 28 | } 29 | 30 | return $this->getApi('search/categories', $bearer, $queryParamsMap); 31 | } 32 | 33 | /** 34 | * @throws GuzzleException 35 | * @link https://dev.twitch.tv/docs/api/reference#search-channels 36 | */ 37 | public function searchChannels(string $bearer, string $query, $liveOnly = null, string $first = null, string $after = null): ResponseInterface 38 | { 39 | $queryParamsMap = []; 40 | 41 | $queryParamsMap[] = ['key' => 'query', 'value' => $query]; 42 | 43 | if ($liveOnly) { 44 | $queryParamsMap[] = ['key' => 'live_only', 'value' => $liveOnly]; 45 | } 46 | 47 | if ($first) { 48 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 49 | } 50 | 51 | if ($after) { 52 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 53 | } 54 | 55 | return $this->getApi('search/channels', $bearer, $queryParamsMap); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/CharityApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_charity_campaigns(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'charity/campaigns', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getCharityCampaign('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_charity_campaign_donations(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'charity/donations', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 28 | $this->getCharityCampaignDonations('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_charity_campaign_donations_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'charity/donations', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 34 | $this->getCharityCampaignDonations('TEST_TOKEN', '123', 100, 'abc')->shouldBe($response); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Resources/TagsApi.php: -------------------------------------------------------------------------------- 1 | 'tag_id', 'value' => $tagId]; 22 | } 23 | if ($first) { 24 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 25 | } 26 | 27 | if ($after) { 28 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 29 | } 30 | 31 | return $this->getApi('tags/streams', $bearer, $queryParamsMap); 32 | } 33 | 34 | /** 35 | * @throws GuzzleException 36 | * @link https://dev.twitch.tv/docs/api/reference#get-stream-tags 37 | */ 38 | public function getStreamTags(string $bearer, string $broadcasterId): ResponseInterface 39 | { 40 | $queryParamsMap = []; 41 | 42 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 43 | 44 | return $this->getApi('streams/tags', $bearer, $queryParamsMap); 45 | } 46 | 47 | /** 48 | * @throws GuzzleException 49 | * @link https://dev.twitch.tv/docs/api/reference#replace-stream-tags 50 | */ 51 | public function replaceStreamTags(string $bearer, string $broadcasterId, $tags = []): ResponseInterface 52 | { 53 | $queryParamsMap = $bodyParamsMap = []; 54 | 55 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 56 | 57 | if (count($tags) > 0) { 58 | $bodyParamsMap[] = ['key' => 'tag_ids', 'value' => $tags]; 59 | } 60 | 61 | return $this->putApi('streams/tags', $bearer, $queryParamsMap, $bodyParamsMap); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/WebhooksApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_webhooks_subscriptions(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'webhooks/subscriptions', 'TEST_TOKEN', [], [])->willReturn($request); 22 | $this->getWebhookSubscriptions('TEST_TOKEN')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_webhooks_subscriptions_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'webhooks/subscriptions', 'TEST_TOKEN', [['key' => 'first', 'value' => 100]], [])->willReturn($request); 28 | $this->getWebhookSubscriptions('TEST_TOKEN', 100)->shouldBe($response); 29 | } 30 | 31 | function it_should_get_webhooks_subscriptions_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'webhooks/subscriptions', 'TEST_TOKEN', [['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 34 | $this->getWebhookSubscriptions('TEST_TOKEN', null, 'abc')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_webhooks_subscriptions_with_everything(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'webhooks/subscriptions', 'TEST_TOKEN', [['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 40 | $this->getWebhookSubscriptions('TEST_TOKEN', 100, 'abc')->shouldBe($response); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Resources/SubscriptionsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | if ($first) { 23 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 24 | } 25 | 26 | if ($after) { 27 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 28 | } 29 | 30 | return $this->getApi('subscriptions', $bearer, $queryParamsMap); 31 | } 32 | 33 | /** 34 | * @throws GuzzleException 35 | * @link https://dev.twitch.tv/docs/api/reference/#get-broadcaster-subscriptions 36 | */ 37 | public function getBroadcasterSubscribers(string $bearer, string $broadcasterId, array $ids = []): ResponseInterface 38 | { 39 | $queryParamsMap = []; 40 | 41 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 42 | 43 | foreach ($ids as $id) { 44 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $id]; 45 | } 46 | 47 | return $this->getApi('subscriptions', $bearer, $queryParamsMap); 48 | } 49 | 50 | /** 51 | * @throws GuzzleException 52 | * @link https://dev.twitch.tv/docs/api/reference#check-user-subscription 53 | */ 54 | public function checkUserSubscription(string $bearer, string $broadcasterId, string $userId): ResponseInterface 55 | { 56 | $queryParamsMap = []; 57 | 58 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 59 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 60 | 61 | return $this->getApi('subscriptions/user', $bearer, $queryParamsMap); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/SearchApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_search_categories(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'search/categories', 'TEST_TOKEN', [['key' => 'query', 'value' => 'test']], [])->willReturn($request); 22 | $this->searchCategories('TEST_TOKEN', 'test')->shouldBe($response); 23 | } 24 | 25 | function it_should_search_categories_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'search/categories', 'TEST_TOKEN', [['key' => 'query', 'value' => 'test'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 28 | $this->searchCategories('TEST_TOKEN', 'test', 100, 'abc')->shouldBe($response); 29 | } 30 | 31 | function it_should_search_channels(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'search/channels', 'TEST_TOKEN', [['key' => 'query', 'value' => 'test']], [])->willReturn($request); 34 | $this->searchChannels('TEST_TOKEN', 'test')->shouldBe($response); 35 | } 36 | 37 | function it_should_search_channels_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'search/channels', 'TEST_TOKEN', [['key' => 'query', 'value' => 'test'], ['key' => 'live_only', 'value' => true], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 40 | $this->searchChannels('TEST_TOKEN', 'test', true, 100, 'abc')->shouldBe($response); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Resources/VideosApi.php: -------------------------------------------------------------------------------- 1 | 'id', 'value' => $id]; 22 | } 23 | 24 | if ($userId) { 25 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 26 | } 27 | 28 | if ($gameId) { 29 | $queryParamsMap[] = ['key' => 'game_id', 'value' => $gameId]; 30 | } 31 | 32 | if ($first) { 33 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 34 | } 35 | 36 | if ($before) { 37 | $queryParamsMap[] = ['key' => 'before', 'value' => $before]; 38 | } 39 | 40 | if ($after) { 41 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 42 | } 43 | 44 | if ($language) { 45 | $queryParamsMap[] = ['key' => 'language', 'value' => $language]; 46 | } 47 | 48 | if ($period) { 49 | $queryParamsMap[] = ['key' => 'period', 'value' => $period]; 50 | } 51 | 52 | if ($sort) { 53 | $queryParamsMap[] = ['key' => 'sort', 'value' => $sort]; 54 | } 55 | 56 | if ($type) { 57 | $queryParamsMap[] = ['key' => 'type', 'value' => $type]; 58 | } 59 | 60 | return $this->getApi('videos', $bearer, $queryParamsMap); 61 | } 62 | 63 | /** 64 | * @throws GuzzleException 65 | * @link https://dev.twitch.tv/docs/api/reference#delete-videos 66 | */ 67 | public function deleteVideos(string $bearer, array $ids = []): ResponseInterface 68 | { 69 | $queryParamsMap = []; 70 | 71 | foreach ($ids as $id) { 72 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 73 | } 74 | 75 | return $this->deleteApi('videos', $bearer, $queryParamsMap); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Resources/PollsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | foreach ($ids as $id) { 23 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 24 | } 25 | 26 | if ($after) { 27 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 28 | } 29 | 30 | if ($first) { 31 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 32 | } 33 | 34 | return $this->getApi('polls', $bearer, $queryParamsMap); 35 | } 36 | 37 | /** 38 | * @throws GuzzleException 39 | * @link https://dev.twitch.tv/docs/api/reference#create-poll 40 | */ 41 | public function createPoll(string $bearer, string $broadcasterId, string $title, array $choices, int $duration, $optionalBodyParams = []): ResponseInterface 42 | { 43 | $bodyParamsMap = []; 44 | 45 | $bodyParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 46 | $bodyParamsMap[] = ['key' => 'title', 'value' => $title]; 47 | $bodyParamsMap[] = ['key' => 'choices', 'value' => $choices]; 48 | $bodyParamsMap[] = ['key' => 'duration', 'value' => $duration]; 49 | 50 | foreach ($optionalBodyParams as $key => $value) { 51 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 52 | } 53 | 54 | return $this->postApi('polls', $bearer, [], $bodyParamsMap); 55 | } 56 | 57 | /** 58 | * @throws GuzzleException 59 | * @link https://dev.twitch.tv/docs/api/reference#end-poll 60 | */ 61 | public function endPoll(string $bearer, string $broadcasterId, string $pollId, string $status): ResponseInterface 62 | { 63 | $bodyParamsMap = []; 64 | 65 | $bodyParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 66 | $bodyParamsMap[] = ['key' => 'id', 'value' => $pollId]; 67 | $bodyParamsMap[] = ['key' => 'status', 'value' => $status]; 68 | 69 | return $this->patchApi('polls', $bearer, [], $bodyParamsMap); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Resources/BitsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 22 | } 23 | 24 | return $this->getApi('bits/cheermotes', $bearer, $queryParamsMap); 25 | } 26 | 27 | /** 28 | * @throws GuzzleException 29 | * @link https://dev.twitch.tv/docs/api/reference#get-bits-leaderboard 30 | */ 31 | public function getBitsLeaderboard(string $bearer, int $count = null, string $period = null, string $startedAt = null, string $userId = null): ResponseInterface 32 | { 33 | $queryParamsMap = []; 34 | 35 | if ($count) { 36 | $queryParamsMap[] = ['key' => 'count', 'value' => $count]; 37 | } 38 | 39 | if ($period) { 40 | $queryParamsMap[] = ['key' => 'period', 'value' => $period]; 41 | } 42 | 43 | if ($startedAt) { 44 | $queryParamsMap[] = ['key' => 'started_at', 'value' => $startedAt]; 45 | } 46 | 47 | if ($userId) { 48 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 49 | } 50 | 51 | return $this->getApi('bits/leaderboard', $bearer, $queryParamsMap); 52 | } 53 | 54 | /** 55 | * @throws GuzzleException 56 | * @link https://dev.twitch.tv/docs/api/reference#get-extension-transactions 57 | */ 58 | public function getExtensionTransactions(string $bearer, string $extensionId, array $transactionIds = [], int $first = null, string $after = null): ResponseInterface 59 | { 60 | $queryParamsMap = []; 61 | 62 | $queryParamsMap[] = ['key' => 'extension_id', 'value' => $extensionId]; 63 | 64 | foreach ($transactionIds as $transactionId) { 65 | $queryParamsMap[] = ['key' => 'id', 'value' => $transactionId]; 66 | } 67 | 68 | if ($first) { 69 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 70 | } 71 | 72 | if ($after) { 73 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 74 | } 75 | 76 | return $this->getApi('extensions/transactions', $bearer, $queryParamsMap); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/TeamsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_channel_teams(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'teams/channel', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getChannelTeams('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_teams(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'teams', 'TEST_TOKEN', [], [])->willReturn($request); 28 | $this->getTeams('TEST_TOKEN')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_teams_by_name(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'teams', 'TEST_TOKEN', [['key' => 'name', 'value' => 'abc']], [])->willReturn($request); 34 | $this->getTeams('TEST_TOKEN', 'abc')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_teams_by_name_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'teams', 'TEST_TOKEN', [['key' => 'name', 'value' => 'abc']], [])->willReturn($request); 40 | $this->getTeamsByName('TEST_TOKEN', 'abc')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_teams_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'teams', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 46 | $this->getTeams('TEST_TOKEN', null, '123')->shouldBe($response); 47 | } 48 | 49 | function it_should_get_teams_by_id_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'teams', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 52 | $this->getTeamsById('TEST_TOKEN', '123')->shouldBe($response); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Resources/PredictionsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | foreach ($ids as $id) { 23 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 24 | } 25 | 26 | if ($after) { 27 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 28 | } 29 | 30 | if ($first) { 31 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 32 | } 33 | 34 | return $this->getApi('predictions', $bearer, $queryParamsMap); 35 | } 36 | 37 | /** 38 | * @throws GuzzleException 39 | * @link https://dev.twitch.tv/docs/api/reference#create-prediction 40 | */ 41 | public function createPrediction(string $bearer, string $broadcasterId, string $title, array $outcomes, int $predictionWindow): ResponseInterface 42 | { 43 | $bodyParamsMap = []; 44 | 45 | $bodyParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 46 | $bodyParamsMap[] = ['key' => 'title', 'value' => $title]; 47 | $bodyParamsMap[] = ['key' => 'outcomes', 'value' => $outcomes]; 48 | $bodyParamsMap[] = ['key' => 'prediction_window', 'value' => $predictionWindow]; 49 | 50 | return $this->postApi('predictions', $bearer, [], $bodyParamsMap); 51 | } 52 | 53 | /** 54 | * @throws GuzzleException 55 | * @link https://dev.twitch.tv/docs/api/reference#end-prediction 56 | */ 57 | public function endPrediction(string $bearer, string $broadcasterId, string $pollId, string $status, string $winningOutcomeId = null): ResponseInterface 58 | { 59 | $bodyParamsMap = []; 60 | 61 | $bodyParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 62 | $bodyParamsMap[] = ['key' => 'id', 'value' => $pollId]; 63 | $bodyParamsMap[] = ['key' => 'status', 'value' => $status]; 64 | 65 | if ($winningOutcomeId) { 66 | $bodyParamsMap[] = ['key' => 'winning_outcome_id', 'value' => $winningOutcomeId]; 67 | } 68 | 69 | return $this->patchApi('predictions', $bearer, [], $bodyParamsMap); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/TwitchApi/Resources/UsersTest.php: -------------------------------------------------------------------------------- 1 | getHelixGuzzleClientWithMockUserResponse(), $this->getRequestGenerator()); 20 | $response = $users->getUserById('TEST_APP_ACCESS_TOKEN', '44322889'); 21 | 22 | $this->assertEquals(200, $response->getStatusCode()); 23 | $contents = json_decode($response->getBody()->getContents()); 24 | $this->assertEquals('dallas', $contents->data[0]->login); 25 | } 26 | 27 | public function testGetUserByUsernameShouldReturnSuccessfulResponseWithUserData(): void 28 | { 29 | $users = new UsersApi($this->getHelixGuzzleClientWithMockUserResponse(), $this->getRequestGenerator()); 30 | $response = $users->getUserByUsername('TEST_APP_ACCESS_TOKEN', 'dallas'); 31 | 32 | $this->assertEquals(200, $response->getStatusCode()); 33 | $contents = json_decode($response->getBody()->getContents()); 34 | $this->assertEquals(44322889, $contents->data[0]->id); 35 | } 36 | 37 | private function getHelixGuzzleClientWithMockUserResponse(): HelixGuzzleClient 38 | { 39 | // Example response from https://dev.twitch.tv/docs/api/reference/#get-users 40 | $getUserReponseJson = << $handler]); 62 | } 63 | 64 | private function getRequestGenerator(): RequestGenerator 65 | { 66 | return new RequestGenerator(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Resources/AnalyticsApi.php: -------------------------------------------------------------------------------- 1 | 'extension_id', 'value' => $extensionId]; 22 | } 23 | 24 | if ($type) { 25 | $queryParamsMap[] = ['key' => 'type', 'value' => $type]; 26 | } 27 | 28 | if ($first) { 29 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 30 | } 31 | 32 | if ($after) { 33 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 34 | } 35 | 36 | if ($startedAt) { 37 | $queryParamsMap[] = ['key' => 'started_at', 'value' => $startedAt]; 38 | } 39 | 40 | if ($endedAt) { 41 | $queryParamsMap[] = ['key' => 'ended_at', 'value' => $endedAt]; 42 | } 43 | 44 | return $this->getApi('analytics/extensions', $bearer, $queryParamsMap); 45 | } 46 | 47 | /** 48 | * @throws GuzzleException 49 | * @link https://dev.twitch.tv/docs/api/reference#get-game-analytics 50 | */ 51 | public function getGameAnalytics(string $bearer, string $gameId = null, string $type = null, int $first = null, string $after = null, string $startedAt = null, string $endedAt = null): ResponseInterface 52 | { 53 | $queryParamsMap = []; 54 | 55 | if ($gameId) { 56 | $queryParamsMap[] = ['key' => 'game_id', 'value' => $gameId]; 57 | } 58 | 59 | if ($type) { 60 | $queryParamsMap[] = ['key' => 'type', 'value' => $type]; 61 | } 62 | 63 | if ($first) { 64 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 65 | } 66 | 67 | if ($after) { 68 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 69 | } 70 | 71 | if ($startedAt) { 72 | $queryParamsMap[] = ['key' => 'started_at', 'value' => $startedAt]; 73 | } 74 | 75 | if ($endedAt) { 76 | $queryParamsMap[] = ['key' => 'ended_at', 'value' => $endedAt]; 77 | } 78 | 79 | return $this->getApi('analytics/games', $bearer, $queryParamsMap); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/RequestGenerator.php: -------------------------------------------------------------------------------- 1 | 'application/json', 14 | ]; 15 | 16 | if ($bearer) { 17 | $headers['Authorization'] = sprintf('Bearer %s', $bearer); 18 | } 19 | 20 | if (count($bodyParams) > 0) { 21 | $request = new Request( 22 | $httpMethod, 23 | sprintf( 24 | '%s%s', 25 | $uriEndpoint, 26 | $this->generateQueryParams($queryParamsMap) 27 | ), 28 | $headers, 29 | $this->generateBodyParams($bodyParams) 30 | ); 31 | } else { 32 | $request = new Request( 33 | $httpMethod, 34 | sprintf( 35 | '%s%s', 36 | $uriEndpoint, 37 | $this->generateQueryParams($queryParamsMap) 38 | ), 39 | $headers 40 | ); 41 | } 42 | 43 | return $request; 44 | } 45 | 46 | /** 47 | * $queryParamsMap should be a mapping of the param key expected in the API call URL, 48 | * and the value to be sent for that key. 49 | * 50 | * [['key' => 'param_key', 'value' => 42],['key' => 'other_key', 'value' => 'asdf']] 51 | * would result in 52 | * ?param_key=42&other_key=asdf 53 | */ 54 | protected function generateQueryParams(array $queryParamsMap): string 55 | { 56 | $queryStringParams = ''; 57 | foreach ($queryParamsMap as $paramMap) { 58 | if ($paramMap['value'] !== null) { 59 | if (is_bool($paramMap['value'])) { 60 | $paramMap['value'] = (int) $paramMap['value']; 61 | } 62 | $format = is_int($paramMap['value']) ? '%d' : '%s'; 63 | $queryStringParams .= sprintf('&%s='.$format, $paramMap['key'], $paramMap['value']); 64 | } 65 | } 66 | 67 | return $queryStringParams ? '?'.substr($queryStringParams, 1) : ''; 68 | } 69 | 70 | protected function generateBodyParams(array $bodyParamsMap): string 71 | { 72 | $bodyParams = []; 73 | foreach ($bodyParamsMap as $bodyParam) { 74 | if ($bodyParam['value'] !== null) { 75 | $bodyParams[$bodyParam['key']] = $bodyParam['value']; 76 | } 77 | } 78 | 79 | return json_encode($bodyParams); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Resources/AbstractResource.php: -------------------------------------------------------------------------------- 1 | guzzleClient = $guzzleClient; 20 | $this->requestGenerator = $requestGenerator; 21 | } 22 | 23 | /** 24 | * @throws GuzzleException 25 | */ 26 | protected function getApi(string $uriEndpoint, string $bearer, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 27 | { 28 | return $this->sendToApi('GET', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 29 | } 30 | 31 | /** 32 | * @throws GuzzleException 33 | */ 34 | protected function getApiWithOptionalAuth(string $uriEndpoint, string $bearer = null, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 35 | { 36 | return $this->sendToApi('GET', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 37 | } 38 | 39 | /** 40 | * @throws GuzzleException 41 | */ 42 | protected function deleteApi(string $uriEndpoint, string $bearer, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 43 | { 44 | return $this->sendToApi('DELETE', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 45 | } 46 | 47 | /** 48 | * @throws GuzzleException 49 | */ 50 | protected function patchApi(string $uriEndpoint, string $bearer, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 51 | { 52 | return $this->sendToApi('PATCH', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 53 | } 54 | 55 | /** 56 | * @throws GuzzleException 57 | */ 58 | protected function postApi(string $uriEndpoint, string $bearer, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 59 | { 60 | return $this->sendToApi('POST', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 61 | } 62 | 63 | /** 64 | * @throws GuzzleException 65 | */ 66 | protected function putApi(string $uriEndpoint, string $bearer, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 67 | { 68 | return $this->sendToApi('PUT', $uriEndpoint, $bearer, $queryParamsMap, $bodyParams); 69 | } 70 | 71 | private function sendToApi(string $httpMethod, string $uriEndpoint, string $bearer = null, array $queryParamsMap = [], array $bodyParams = []): ResponseInterface 72 | { 73 | return $this->guzzleClient->send($this->requestGenerator->generate($httpMethod, $uriEndpoint, $bearer, $queryParamsMap, $bodyParams)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/SubscriptionsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_broadcaster_subscriptions(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'subscriptions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getBroadcasterSubscriptions('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_broadcaster_subscriptions_with_all(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'subscriptions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 28 | $this->getBroadcasterSubscriptions('TEST_TOKEN', '123', 100, 'abc')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_broadcaster_subscribers(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'subscriptions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 34 | $this->getBroadcasterSubscribers('TEST_TOKEN', '123')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_broadcaster_subscribers_with_id(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'subscriptions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'user_id', 'value' => '321']], [])->willReturn($request); 40 | $this->getBroadcasterSubscribers('TEST_TOKEN', '123', ['321'])->shouldBe($response); 41 | } 42 | 43 | function it_should_get_broadcaster_subscribers_with_ids(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'subscriptions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'user_id', 'value' => '321'], ['key' => 'user_id', 'value' => '456']], [])->willReturn($request); 46 | $this->getBroadcasterSubscribers('TEST_TOKEN', '123', ['321', '456'])->shouldBe($response); 47 | } 48 | 49 | function it_should_check_user_subscriptions(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'subscriptions/user', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'user_id', 'value' => '456']], [])->willReturn($request); 52 | $this->checkUserSubscription('TEST_TOKEN', '123', '456')->shouldBe($response); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/GamesApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_games_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'games', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 22 | $this->getGames('TEST_TOKEN', ['123'])->shouldBe($response); 23 | } 24 | 25 | function it_should_get_games_by_ids(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'games', 'TEST_TOKEN', [['key' => 'id', 'value' => '123'], ['key' => 'id', 'value' => '456']], [])->willReturn($request); 28 | $this->getGames('TEST_TOKEN', ['123', '456'])->shouldBe($response); 29 | } 30 | 31 | function it_should_get_games_by_name(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'games', 'TEST_TOKEN', [['key' => 'name', 'value' => 'abc']], [])->willReturn($request); 34 | $this->getGames('TEST_TOKEN', [], ['abc'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_games_by_names(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'games', 'TEST_TOKEN', [['key' => 'name', 'value' => 'abc'], ['key' => 'name', 'value' => 'def']], [])->willReturn($request); 40 | $this->getGames('TEST_TOKEN', [], ['abc', 'def'])->shouldBe($response); 41 | } 42 | 43 | function it_should_get_games_by_ids_and_names(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'games', 'TEST_TOKEN', [['key' => 'id', 'value' => '123'], ['key' => 'id', 'value' => '456'], ['key' => 'name', 'value' => 'abc'], ['key' => 'name', 'value' => 'def']], [])->willReturn($request); 46 | $this->getGames('TEST_TOKEN', ['123', '456'], ['abc', 'def'])->shouldBe($response); 47 | } 48 | 49 | function it_should_get_top_games(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'games/top', 'TEST_TOKEN', [], [])->willReturn($request); 52 | $this->getTopGames('TEST_TOKEN')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_top_games_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'games/top', 'TEST_TOKEN', [['key' => 'first', 'value' => 100], ['key' => 'before', 'value' => 'abc'], ['key' => 'after', 'value' => 'def']], [])->willReturn($request); 58 | $this->getTopGames('TEST_TOKEN', 100, 'abc', 'def')->shouldBe($response); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Resources/ClipsApi.php: -------------------------------------------------------------------------------- 1 | getClips($bearer, $broadcasterId, null, null, $first, $before, $after, $startedAt, $endedAt); 18 | } 19 | 20 | /** 21 | * @throws GuzzleException 22 | */ 23 | public function getClipsByGameId(string $bearer, string $gameId, int $first = null, string $before = null, string $after = null, string $startedAt = null, string $endedAt = null): ResponseInterface 24 | { 25 | return $this->getClips($bearer, null, $gameId, null, $first, $before, $after, $startedAt, $endedAt); 26 | } 27 | 28 | /** 29 | * @throws GuzzleException 30 | */ 31 | public function getClipsByIds(string $bearer, string $clipIds, string $startedAt = null, string $endedAt = null): ResponseInterface 32 | { 33 | return $this->getClips($bearer, null, null, $clipIds, null, null, null, $startedAt, $endedAt); 34 | } 35 | 36 | /** 37 | * @throws GuzzleException 38 | * @link https://dev.twitch.tv/docs/api/reference#get-clips 39 | */ 40 | public function getClips(string $bearer, string $broadcasterId = null, string $gameId = null, string $clipIds = null, int $first = null, string $before = null, string $after = null, string $startedAt = null, string $endedAt = null): ResponseInterface 41 | { 42 | $queryParamsMap = []; 43 | if ($broadcasterId) { 44 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 45 | } 46 | if ($gameId) { 47 | $queryParamsMap[] = ['key' => 'game_id', 'value' => $gameId]; 48 | } 49 | if ($clipIds) { 50 | $queryParamsMap[] = ['key' => 'id', 'value' => $clipIds]; 51 | } 52 | if ($first) { 53 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 54 | } 55 | if ($before) { 56 | $queryParamsMap[] = ['key' => 'before', 'value' => $before]; 57 | } 58 | if ($after) { 59 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 60 | } 61 | if ($startedAt) { 62 | $queryParamsMap[] = ['key' => 'started_at', 'value' => $startedAt]; 63 | } 64 | if ($endedAt) { 65 | $queryParamsMap[] = ['key' => 'ended_at', 'value' => $endedAt]; 66 | } 67 | 68 | return $this->getApi('clips', $bearer, $queryParamsMap); 69 | } 70 | 71 | /** 72 | * @throws GuzzleException 73 | * @link https://dev.twitch.tv/docs/api/reference#create-clip 74 | */ 75 | public function createClip(string $bearer, string $broadcasterId, bool $hasDelay = null): ResponseInterface 76 | { 77 | $queryParamsMap = []; 78 | 79 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 80 | 81 | if ($hasDelay) { 82 | $queryParamsMap[] = ['key' => 'has_delay', 'value' => $hasDelay]; 83 | } 84 | 85 | return $this->postApi('clips', $bearer, $queryParamsMap); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/TagsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_all_tags(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'tags/streams', 'TEST_TOKEN', [], [])->willReturn($request); 22 | $this->getAllStreamTags('TEST_TOKEN')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_all_tags_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'tags/streams', 'TEST_TOKEN', [['key' => 'tag_id', 'value' => '123']], [])->willReturn($request); 28 | $this->getAllStreamTags('TEST_TOKEN', ['123'])->shouldBe($response); 29 | } 30 | 31 | function it_should_get_all_tags_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'tags/streams', 'TEST_TOKEN', [['key' => 'first', 'value' => 100]], [])->willReturn($request); 34 | $this->getAllStreamTags('TEST_TOKEN', [], 100)->shouldBe($response); 35 | } 36 | 37 | function it_should_get_all_tags_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'tags/streams', 'TEST_TOKEN', [['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 40 | $this->getAllStreamTags('TEST_TOKEN', [], null, 'abc')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_stream_tags(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'streams/tags', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 46 | $this->getStreamTags('TEST_TOKEN', '123')->shouldBe($response); 47 | } 48 | 49 | function it_should_replace_stream_tags(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('PUT', 'streams/tags', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 52 | $this->replaceStreamTags('TEST_TOKEN', '123')->shouldBe($response); 53 | } 54 | 55 | function it_should_replace_stream_tags_with_one_tag(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('PUT', 'streams/tags', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'tag_ids', 'value' => ['456']]])->willReturn($request); 58 | $this->replaceStreamTags('TEST_TOKEN', '123', ['456'])->shouldBe($response); 59 | } 60 | 61 | function it_should_replace_stream_tags_with_multiple_tags(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('PUT', 'streams/tags', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'tag_ids', 'value' => ['456', '789']]])->willReturn($request); 64 | $this->replaceStreamTags('TEST_TOKEN', '123', ['456', '789'])->shouldBe($response); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Resources/ChannelsApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | return $this->getApi('channels', $bearer, $queryParamsMap); 23 | } 24 | 25 | /** 26 | * @throws GuzzleException 27 | * @link https://dev.twitch.tv/docs/api/reference#get-channel-editors 28 | */ 29 | public function getChannelEditors(string $bearer, string $broadcasterId): ResponseInterface 30 | { 31 | $queryParamsMap = []; 32 | 33 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 34 | 35 | return $this->getApi('channels/editors', $bearer, $queryParamsMap); 36 | } 37 | 38 | /** 39 | * @throws GuzzleException 40 | * @link https://dev.twitch.tv/docs/api/reference#modify-channel-information 41 | */ 42 | public function modifyChannelInfo(string $bearer, string $broadcasterId, $bodyParams = []): ResponseInterface 43 | { 44 | // $bodyParams should be a standard key => value format, eg. ['game_id' => '1']; 45 | $queryParamsMap = $bodyParamsMap = []; 46 | 47 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 48 | 49 | foreach ($bodyParams as $key => $value) { 50 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 51 | } 52 | 53 | return $this->patchApi('channels', $bearer, $queryParamsMap, $bodyParamsMap); 54 | } 55 | 56 | /** 57 | * @throws GuzzleException 58 | * @link https://dev.twitch.tv/docs/api/reference/#get-followed-channels 59 | */ 60 | public function getFollowedChannels(string $bearer, string $userId, string $broadcasterId = null, int $first = null, string $after = null): ResponseInterface 61 | { 62 | $queryParamsMap = []; 63 | 64 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 65 | 66 | if ($broadcasterId) { 67 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 68 | } 69 | 70 | if ($first) { 71 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 72 | } 73 | 74 | if ($after) { 75 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 76 | } 77 | 78 | return $this->getApi('channels/followed', $bearer, $queryParamsMap); 79 | } 80 | 81 | /** 82 | * @throws GuzzleException 83 | * @link https://dev.twitch.tv/docs/api/reference/#get-channel-followers 84 | */ 85 | public function getChannelFollowers(string $bearer, string $broadcasterId, string $userId = null, int $first = null, string $after = null): ResponseInterface 86 | { 87 | $queryParamsMap = []; 88 | 89 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 90 | 91 | if ($userId) { 92 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 93 | } 94 | 95 | if ($first) { 96 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 97 | } 98 | 99 | if ($after) { 100 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 101 | } 102 | 103 | return $this->getApi('channels/followers', $bearer, $queryParamsMap); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/BitsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_getcheermotes(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'bits/cheermotes', 'TEST_TOKEN', [], [])->willReturn($request); 22 | $this->getCheermotes('TEST_TOKEN')->shouldBe($response); 23 | } 24 | 25 | function it_should_getcheermotes_by_broadcaster_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'bits/cheermotes', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 28 | $this->getCheermotes('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | 31 | function it_should_extension_transactions(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'extensions/transactions', 'TEST_TOKEN', [['key' => 'extension_id', 'value' => '1']], [])->willReturn($request); 34 | $this->getExtensionTransactions('TEST_TOKEN', '1')->shouldBe($response); 35 | } 36 | 37 | function it_should_extension_transactions_with_transaction_id(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'extensions/transactions', 'TEST_TOKEN', [['key' => 'extension_id', 'value' => '1'], ['key' => 'id', 'value' => '321']], [])->willReturn($request); 40 | $this->getExtensionTransactions('TEST_TOKEN', '1', ['321'])->shouldBe($response); 41 | } 42 | 43 | function it_should_extension_transactions_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'extensions/transactions', 'TEST_TOKEN', [['key' => 'extension_id', 'value' => '1'], ['key' => 'first', 'value' => '100']], [])->willReturn($request); 46 | $this->getExtensionTransactions('TEST_TOKEN', '1', [], 100)->shouldBe($response); 47 | } 48 | 49 | function it_should_extension_transactions_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'extensions/transactions', 'TEST_TOKEN', [['key' => 'extension_id', 'value' => '1'], ['key' => 'after', 'value' => '100']], [])->willReturn($request); 52 | $this->getExtensionTransactions('TEST_TOKEN', '1', [], null, 100)->shouldBe($response); 53 | } 54 | 55 | function it_should_get_bits_leaderboard(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'bits/leaderboard', 'TEST_TOKEN', [], [])->willReturn($request); 58 | $this->getBitsLeaderboard('TEST_TOKEN')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_bits_leaderboard_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'bits/leaderboard', 'TEST_TOKEN', [['key' => 'count', 'value' => '100'], ['key' => 'period', 'value' => 'all'], ['key' => 'started_at', 'value' => '2019-10-12T07:20:50.52Z'], ['key' => 'user_id', 'value' => '123']], [])->willReturn($request); 64 | $this->getBitsLeaderboard('TEST_TOKEN', 100, 'all', '2019-10-12T07:20:50.52Z', '123')->shouldBe($response); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/PollsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_polls(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'polls', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getPolls('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_polls_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'polls', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '321']], [])->willReturn($request); 28 | $this->getPolls('TEST_TOKEN', '123', ['321'])->shouldBe($response); 29 | } 30 | 31 | function it_should_get_polls_by_ids(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'polls', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '321'], ['key' => 'id', 'value' => '456']], [])->willReturn($request); 34 | $this->getPolls('TEST_TOKEN', '123', ['321', '456'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_polls_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'polls', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'after', 'value' => 'abc'], ['key' => 'first', 'value' => 100]], [])->willReturn($request); 40 | $this->getPolls('TEST_TOKEN', '123', [], 'abc', 100)->shouldBe($response); 41 | } 42 | 43 | function it_should_create_a_poll(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('POST', 'polls', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'title', 'value' => 'What is my name?'], ['key' => 'choices', 'value' => [['title' => 'John'], ['title' => 'Doe']]], ['key' => 'duration', 'value' => 15]])->willReturn($request); 46 | $this->createPoll('TEST_TOKEN', '123', 'What is my name?', [['title' => 'John'], ['title' => 'Doe']], 15)->shouldBe($response); 47 | } 48 | 49 | function it_should_create_a_poll_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('POST', 'polls', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'title', 'value' => 'What is my name?'], ['key' => 'choices', 'value' => [['title' => 'John'], ['title' => 'Doe']]], ['key' => 'duration', 'value' => 15], ['key' => 'bits_voting_enabled', 'value' => 1]])->willReturn($request); 52 | $this->createPoll('TEST_TOKEN', '123', 'What is my name?', [['title' => 'John'], ['title' => 'Doe']], 15, ['bits_voting_enabled' => 1])->shouldBe($response); 53 | } 54 | 55 | function it_should_end_a_poll(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('PATCH', 'polls', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456'], ['key' => 'status', 'value' => 'TERMINATED']])->willReturn($request); 58 | $this->endPoll('TEST_TOKEN', '123', '456', 'TERMINATED')->shouldBe($response); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/PredictionsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_predictions(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'predictions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getPredictions('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_predictions_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'predictions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '321']], [])->willReturn($request); 28 | $this->getPredictions('TEST_TOKEN', '123', ['321'])->shouldBe($response); 29 | } 30 | 31 | function it_should_get_predictions_by_ids(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'predictions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '321'], ['key' => 'id', 'value' => '456']], [])->willReturn($request); 34 | $this->getPredictions('TEST_TOKEN', '123', ['321', '456'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_predictions_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'predictions', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'after', 'value' => 'abc'], ['key' => 'first', 'value' => 100]], [])->willReturn($request); 40 | $this->getPredictions('TEST_TOKEN', '123', [], 'abc', 100)->shouldBe($response); 41 | } 42 | 43 | function it_should_create_a_prediction(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('POST', 'predictions', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'title', 'value' => 'Will the coin land on heads or tails?'], ['key' => 'outcomes', 'value' => [['title' => 'Heads'], ['title' => 'Tails']]], ['key' => 'prediction_window', 'value' => 15]])->willReturn($request); 46 | $this->createPrediction('TEST_TOKEN', '123', 'Will the coin land on heads or tails?', [['title' => 'Heads'], ['title' => 'Tails']], 15)->shouldBe($response); 47 | } 48 | 49 | function it_should_end_a_prediction(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('PATCH', 'predictions', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456'], ['key' => 'status', 'value' => 'CANCELLED']])->willReturn($request); 52 | $this->endPrediction('TEST_TOKEN', '123', '456', 'CANCELLED')->shouldBe($response); 53 | } 54 | 55 | function it_should_resolve_a_prediction(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('PATCH', 'predictions', 'TEST_TOKEN', [], [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456'], ['key' => 'status', 'value' => 'RESOLVED'], ['key' => 'winning_outcome_id', 'value' => '1']])->willReturn($request); 58 | $this->endPrediction('TEST_TOKEN', '123', '456', 'RESOLVED', '1')->shouldBe($response); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Resources/EntitlementsApi.php: -------------------------------------------------------------------------------- 1 | 'manifest_id', 'value' => $manifestId]; 20 | $queryParamsMap[] = ['key' => 'type', 'value' => $type]; 21 | 22 | return $this->postApi('entitlements/upload', $bearer, $queryParamsMap); 23 | } 24 | 25 | /** 26 | * @throws GuzzleException 27 | * @link https://dev.twitch.tv/docs/api/reference#get-code-status 28 | */ 29 | public function getCodeStatus(string $bearer, int $userId, array $codes = []): ResponseInterface 30 | { 31 | $queryParamsMap = []; 32 | 33 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 34 | 35 | foreach ($codes as $code) { 36 | $queryParamsMap[] = ['key' => 'code', 'value' => $code]; 37 | } 38 | 39 | return $this->getApi('entitlements/codes', $bearer, $queryParamsMap); 40 | } 41 | 42 | /** 43 | * @throws GuzzleException 44 | * @link https://dev.twitch.tv/docs/api/reference#get-drops-entitlements 45 | */ 46 | public function getDropsEntitlements(string $bearer, string $id = null, string $userId = null, string $gameId = null, string $after = null, int $first = null, string $fulfillmentStatus = null): ResponseInterface 47 | { 48 | $queryParamsMap = []; 49 | 50 | if ($id) { 51 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 52 | } 53 | 54 | if ($userId) { 55 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 56 | } 57 | 58 | if ($gameId) { 59 | $queryParamsMap[] = ['key' => 'game_id', 'value' => $gameId]; 60 | } 61 | 62 | if ($after) { 63 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 64 | } 65 | 66 | if ($first) { 67 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 68 | } 69 | 70 | if ($fulfillmentStatus) { 71 | $queryParamsMap[] = ['key' => 'fulfillment_status', 'value' => $fulfillmentStatus]; 72 | } 73 | 74 | return $this->getApi('entitlements/drops', $bearer, $queryParamsMap); 75 | } 76 | 77 | /** 78 | * @throws GuzzleException 79 | * @link https://dev.twitch.tv/docs/api/reference#update-drops-entitlements 80 | */ 81 | public function updateDropsEntitlements(string $bearer, array $entitlement_ids = null, string $fulfillment_status = null): ResponseInterface 82 | { 83 | $bodyParamsMap = []; 84 | 85 | if ($entitlement_ids) { 86 | $bodyParamsMap[] = ['key' => 'entitlement_ids', 'value' => $entitlement_ids]; 87 | } 88 | 89 | if ($fulfillment_status) { 90 | $bodyParamsMap[] = ['key' => 'fulfillment_status', 'value' => $fulfillment_status]; 91 | } 92 | 93 | return $this->patchApi('entitlements/drops', $bearer, [], $bodyParamsMap); 94 | } 95 | 96 | /** 97 | * @throws GuzzleException 98 | * @link https://dev.twitch.tv/docs/api/reference#redeem-code 99 | */ 100 | public function redeemCode(string $bearer, int $userId, array $codes = []): ResponseInterface 101 | { 102 | $queryParamsMap = []; 103 | 104 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 105 | 106 | foreach ($codes as $code) { 107 | $queryParamsMap[] = ['key' => 'code', 'value' => $code]; 108 | } 109 | 110 | return $this->postApi('entitlements/code', $bearer, $queryParamsMap); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /spec/TwitchApi/Auth/OauthApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith('client-id', 'client-secret', $guzzleClient); 15 | } 16 | 17 | function it_should_get_auth_url(Client $guzzleClient) 18 | { 19 | $guzzleClient->getConfig('base_uri')->willReturn('https://id.twitch.tv/oauth2/'); 20 | $this->getAuthUrl('https://redirect.url')->shouldReturn( 21 | 'https://id.twitch.tv/oauth2/authorize?client_id=client-id&redirect_uri=https://redirect.url&response_type=code&scope=' 22 | ); 23 | } 24 | 25 | function it_should_get_access_token(Client $guzzleClient, Response $response) 26 | { 27 | $request = new Request( 28 | 'POST', 29 | 'token' 30 | ); 31 | $guzzleClient->send($request, ['json' => [ 32 | 'client_id' => 'client-id', 33 | 'client_secret' => 'client-secret', 34 | 'grant_type' => 'authorization_code', 35 | 'redirect_uri' => 'https://redirect.url', 36 | 'code' => 'user-code-from-twitch', 37 | 'state' => null, 38 | ]])->willReturn($response); 39 | 40 | $this->getUserAccessToken('user-code-from-twitch', 'https://redirect.url')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_refresh_token(Client $guzzleClient, Response $response) 44 | { 45 | $request = new Request( 46 | 'POST', 47 | 'token' 48 | ); 49 | $guzzleClient->send($request, ['json' => [ 50 | 'client_id' => 'client-id', 51 | 'client_secret' => 'client-secret', 52 | 'grant_type' => 'refresh_token', 53 | 'refresh_token' => 'user-refresh-token', 54 | ]])->willReturn($response); 55 | 56 | $this->refreshToken('user-refresh-token')->shouldBe($response); 57 | } 58 | 59 | function it_should_validate_access_token(Client $guzzleClient, Response $response) 60 | { 61 | $request = new Request( 62 | 'GET', 63 | 'validate', 64 | [ 65 | 'Authorization' => 'OAuth user-access-token', 66 | ] 67 | ); 68 | $guzzleClient->send($request, [])->willReturn($response); 69 | 70 | $this->validateAccessToken('user-access-token')->shouldBe($response); 71 | } 72 | 73 | function it_should_return_true_if_access_token_is_valid(Client $guzzleClient, Response $response) 74 | { 75 | $request = new Request( 76 | 'GET', 77 | 'validate', 78 | [ 79 | 'Authorization' => 'OAuth user-access-token', 80 | ] 81 | ); 82 | $response->getStatusCode()->willReturn(200); 83 | $guzzleClient->send($request, [])->willReturn($response); 84 | 85 | $this->isValidAccessToken('user-access-token')->shouldReturn(true); 86 | } 87 | 88 | function it_should_return_false_if_access_token_is_invalid(Client $guzzleClient, Response $response) 89 | { 90 | $request = new Request( 91 | 'GET', 92 | 'validate', 93 | [ 94 | 'Authorization' => 'OAuth invalid-user-access-token', 95 | ] 96 | ); 97 | $response->getStatusCode()->willReturn(401); 98 | $guzzleClient->send($request, [])->willReturn($response); 99 | 100 | $this->isValidAccessToken('invalid-user-access-token')->shouldReturn(false); 101 | } 102 | 103 | function it_should_get_app_access_token(Client $guzzleClient, Response $response) 104 | { 105 | $request = new Request( 106 | 'POST', 107 | 'token' 108 | ); 109 | $guzzleClient->send($request, ['json' => [ 110 | 'client_id' => 'client-id', 111 | 'client_secret' => 'client-secret', 112 | 'grant_type' => 'client_credentials', 113 | 'scope' => '', 114 | ]])->willReturn($response); 115 | 116 | $this->getAppAccessToken()->shouldBe($response); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/ClipsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_clips_by_broadcaster_id(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getClips('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_clips_by_broadcaster_id_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 28 | $this->getClipsByBroadcasterId('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_clips_by_game_id(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '123']], [])->willReturn($request); 34 | $this->getClips('TEST_TOKEN', null, '123')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_clips_by_game_id_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '123']], [])->willReturn($request); 40 | $this->getClipsByGameId('TEST_TOKEN', '123')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_one_clip_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 46 | $this->getClips('TEST_TOKEN', null, null, '123')->shouldBe($response); 47 | } 48 | 49 | function it_should_get_one_clip_by_id_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 52 | $this->getClipsByIds('TEST_TOKEN', '123')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_multiple_clips_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'id', 'value' => '123,456']], [])->willReturn($request); 58 | $this->getClips('TEST_TOKEN', null, null, '123,456')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_multiple_clips_by_id_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'id', 'value' => '123,456']], [])->willReturn($request); 64 | $this->getClipsByIds('TEST_TOKEN', '123,456')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_clips_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'clips', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'first', 'value' => '10'], ['key' => 'before', 'value' => 'abc'], ['key' => 'after', 'value' => 'def'], ['key' => 'started_at', 'value' => '2018-10-12T07:20:50.52Z'], ['key' => 'ended_at', 'value' => '2019-10-12T07:20:50.52Z']], [])->willReturn($request); 70 | $this->getClips('TEST_TOKEN', '123', null, null, 10, 'abc', 'def', '2018-10-12T07:20:50.52Z', '2019-10-12T07:20:50.52Z')->shouldBe($response); 71 | } 72 | 73 | function it_should_create_a_clip(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('POST', 'clips', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'has_delay', 'value' => 'true']], [])->willReturn($request); 76 | $this->createClip('TEST_TOKEN', '123', true)->shouldBe($response); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Auth/OauthApi.php: -------------------------------------------------------------------------------- 1 | clientId = $clientId; 22 | $this->clientSecret = $clientSecret; 23 | $this->guzzleClient = $guzzleClient ?? AuthGuzzleClient::getClient(); 24 | } 25 | 26 | /** 27 | * @return string A full authentication URL, including the Guzzle client's base URI. 28 | */ 29 | public function getAuthUrl(string $redirectUri, string $responseType = 'code', string $scope = '', bool $forceVerify = false, string $state = null): string 30 | { 31 | return sprintf( 32 | '%s%s', 33 | $this->guzzleClient->getConfig('base_uri'), 34 | $this->getPartialAuthUrl($redirectUri, $responseType, $scope, $forceVerify, $state) 35 | ); 36 | } 37 | 38 | /** 39 | * @throws GuzzleException 40 | */ 41 | public function getUserAccessToken($code, string $redirectUri, $state = null): ResponseInterface 42 | { 43 | return $this->makeRequest( 44 | new Request('POST', 'token'), 45 | [ 46 | RequestOptions::JSON => [ 47 | 'client_id' => $this->clientId, 48 | 'client_secret' => $this->clientSecret, 49 | 'grant_type' => 'authorization_code', 50 | 'redirect_uri' => $redirectUri, 51 | 'code' => $code, 52 | 'state' => $state, 53 | ], 54 | ] 55 | ); 56 | } 57 | 58 | /** 59 | * @throws GuzzleException 60 | */ 61 | public function refreshToken(string $refeshToken, string $scope = ''): ResponseInterface 62 | { 63 | $requestOptions = [ 64 | 'client_id' => $this->clientId, 65 | 'client_secret' => $this->clientSecret, 66 | 'grant_type' => 'refresh_token', 67 | 'refresh_token' => $refeshToken, 68 | ]; 69 | if ($scope) { 70 | $requestOptions['scope'] = $scope; 71 | } 72 | 73 | return $this->makeRequest( 74 | new Request('POST', 'token'), 75 | [ 76 | RequestOptions::JSON => $requestOptions, 77 | ] 78 | ); 79 | } 80 | 81 | /** 82 | * @throws GuzzleException 83 | */ 84 | public function validateAccessToken(string $accessToken): ResponseInterface 85 | { 86 | return $this->makeRequest( 87 | new Request( 88 | 'GET', 89 | 'validate', 90 | [ 91 | 'Authorization' => sprintf('OAuth %s', $accessToken), 92 | ] 93 | ) 94 | ); 95 | } 96 | 97 | /** 98 | * @throws GuzzleException 99 | */ 100 | public function isValidAccessToken(string $accessToken): bool 101 | { 102 | return $this->validateAccessToken($accessToken)->getStatusCode() === 200; 103 | } 104 | 105 | /** 106 | * @throws GuzzleException 107 | */ 108 | public function getAppAccessToken(string $scope = ''): ResponseInterface 109 | { 110 | return $this->makeRequest( 111 | new Request('POST', 'token'), 112 | [ 113 | RequestOptions::JSON => [ 114 | 'client_id' => $this->clientId, 115 | 'client_secret' => $this->clientSecret, 116 | 'grant_type' => 'client_credentials', 117 | 'scope' => $scope, 118 | ], 119 | ] 120 | ); 121 | } 122 | 123 | /** 124 | * @throws GuzzleException 125 | */ 126 | private function makeRequest(Request $request, array $options = []): ResponseInterface 127 | { 128 | return $this->guzzleClient->send($request, $options); 129 | } 130 | 131 | /** 132 | * @return string A partial authentication URL, excluding the Guzzle client's base URI. 133 | */ 134 | private function getPartialAuthUrl(string $redirectUri, string $responseType = 'code', string $scope = '', bool $forceVerify = false, string $state = null): string 135 | { 136 | $optionalParameters = ''; 137 | $optionalParameters .= $forceVerify ? '&force_verify=true' : ''; 138 | $optionalParameters .= $state ? sprintf('&state=%s', $state) : ''; 139 | 140 | return sprintf( 141 | 'authorize?client_id=%s&redirect_uri=%s&response_type=%s&scope=%s%s', 142 | $this->clientId, 143 | $redirectUri, 144 | $responseType, 145 | $scope, 146 | $optionalParameters 147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/ChannelsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_channel_info(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getChannelInfo('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_channel_editors(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'channels/editors', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 28 | $this->getChannelEditors('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | 31 | function it_should_modify_channel_with_game_id(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('PATCH', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'game_id', 'value' => '0']])->willReturn($request); 34 | $this->modifyChannelInfo('TEST_TOKEN', '123', ['game_id' => '0'])->shouldBe($response); 35 | } 36 | 37 | function it_should_modify_channel_with_language(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('PATCH', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'broadcaster_language', 'value' => 'en']])->willReturn($request); 40 | $this->modifyChannelInfo('TEST_TOKEN', '123', ['broadcaster_language' => 'en'])->shouldBe($response); 41 | } 42 | 43 | function it_should_modify_channel_with_title(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('PATCH', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'title', 'value' => 'test 123']])->willReturn($request); 46 | $this->modifyChannelInfo('TEST_TOKEN', '123', ['title' => 'test 123'])->shouldBe($response); 47 | } 48 | 49 | function it_should_modify_channel_with_delay(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('PATCH', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'delay', 'value' => 5]])->willReturn($request); 52 | $this->modifyChannelInfo('TEST_TOKEN', '123', ['delay' => 5])->shouldBe($response); 53 | } 54 | 55 | function it_should_modify_channel_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('PATCH', 'channels', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'game_id', 'value' => '0'], ['key' => 'broadcaster_language', 'value' => 'en'], ['key' => 'title', 'value' => 'test 123'], ['key' => 'delay', 'value' => 5]])->willReturn($request); 58 | $this->modifyChannelInfo('TEST_TOKEN', '123', ['game_id' => '0', 'broadcaster_language' => 'en', 'title' => 'test 123', 'delay' => 5])->shouldBe($response); 59 | } 60 | 61 | function it_should_get_followed_channels(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'channels/followed', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123']], [])->willReturn($request); 64 | $this->getFollowedChannels('TEST_TOKEN', '123')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_followed_channels_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'channels/followed', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'broadcaster_id', 'value' => '456'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 70 | $this->getFollowedChannels('TEST_TOKEN', '123', '456', 100, 'abc')->shouldBe($response); 71 | } 72 | 73 | function it_should_get_channel_followers(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('GET', 'channels/followers', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 76 | $this->getChannelFollowers('TEST_TOKEN', '123')->shouldBe($response); 77 | } 78 | 79 | function it_should_get_channel_followers_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('GET', 'channels/followers', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'user_id', 'value' => '456'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 82 | $this->getChannelFollowers('TEST_TOKEN', '123', '456', 100, 'abc')->shouldBe($response); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Webhooks/WebhooksSubscriptionApi.php: -------------------------------------------------------------------------------- 1 | clientId = $clientId; 21 | $this->secret = $secret; 22 | $this->guzzleClient = $guzzleClient ?? HelixGuzzleClient::getClient($clientId); 23 | } 24 | 25 | public function subscribeToStream(string $twitchId, string $callback, string $bearer, int $leaseSeconds = 0): void 26 | { 27 | $this->subscribe( 28 | sprintf('https://api.twitch.tv/helix/streams?user_id=%s', $twitchId), 29 | $callback, 30 | $bearer, 31 | $leaseSeconds 32 | ); 33 | } 34 | 35 | public function subscribeToSubscriptionEvents(string $twitchId, string $callback, string $bearer, int $leaseSeconds = 0): void 36 | { 37 | $this->subscribe( 38 | sprintf('https://api.twitch.tv/helix/subscriptions/events?broadcaster_id=%s&first=1', $twitchId), 39 | $callback, 40 | $bearer, 41 | $leaseSeconds 42 | ); 43 | } 44 | 45 | public function subscribeToUser(string $twitchId, string $callback, string $bearer, int $leaseSeconds = 0): void 46 | { 47 | $this->subscribe( 48 | sprintf('https://api.twitch.tv/helix/users?id=%s', $twitchId), 49 | $callback, 50 | $bearer, 51 | $leaseSeconds 52 | ); 53 | } 54 | 55 | public function subscribeToUserFollows(string $followerId, string $followedUserId, int $first, string $callback, string $bearer, int $leaseSeconds = 0): void 56 | { 57 | $queryParams = []; 58 | if ($followerId) { 59 | $queryParams['from_id'] = $followerId; 60 | } 61 | if ($followedUserId) { 62 | $queryParams['to_id'] = $followedUserId; 63 | } 64 | if ($first) { 65 | $queryParams['first'] = $first; 66 | } 67 | $this->subscribe( 68 | sprintf('https://api.twitch.tv/helix/users/follows?%s', http_build_query($queryParams)), 69 | $callback, 70 | $bearer, 71 | $leaseSeconds 72 | ); 73 | } 74 | 75 | public function unsubscribeFromStream(string $twitchId, string $callback, string $bearer): void 76 | { 77 | $this->unsubscribe( 78 | sprintf('https://api.twitch.tv/helix/streams?user_id=%s', $twitchId), 79 | $callback, 80 | $bearer 81 | ); 82 | } 83 | 84 | public function unsubscribeFromUser(string $twitchId, string $callback, string $bearer) 85 | { 86 | $this->unsubscribe( 87 | sprintf('https://api.twitch.tv/helix/users?id=%s', $twitchId), 88 | $callback, 89 | $bearer 90 | ); 91 | } 92 | 93 | public function unsubscribeFromUserFollows(string $followerId, string $followedUserId, int $first, string $callback, string $bearer) 94 | { 95 | $queryParams = []; 96 | if ($followerId) { 97 | $queryParams['from_id'] = $followerId; 98 | } 99 | if ($followedUserId) { 100 | $queryParams['to_id'] = $followedUserId; 101 | } 102 | if ($first) { 103 | $queryParams['first'] = $first; 104 | } 105 | $this->unsubscribe( 106 | sprintf('https://api.twitch.tv/helix/users/follows?%s', http_build_query($queryParams)), 107 | $callback, 108 | $bearer 109 | ); 110 | } 111 | 112 | public function validateWebhookEventCallback(string $xHubSignature, string $content): bool 113 | { 114 | [$hashAlgorithm, $expectedHash] = explode('=', $xHubSignature); 115 | $generatedHash = hash_hmac($hashAlgorithm, $content, $this->secret); 116 | 117 | return $expectedHash === $generatedHash; 118 | } 119 | 120 | private function subscribe(string $topic, string $callback, string $bearer, int $leaseSeconds = 0): void 121 | { 122 | $headers = [ 123 | 'Client-ID' => $this->clientId, 124 | ]; 125 | 126 | $headers['Authorization'] = sprintf('Bearer %s', $bearer); 127 | 128 | $body = [ 129 | 'hub.callback' => $callback, 130 | 'hub.mode' => self::SUBSCRIBE, 131 | 'hub.topic' => $topic, 132 | 'hub.lease_seconds' => $leaseSeconds, 133 | 'hub.secret' => $this->secret, 134 | ]; 135 | 136 | $this->guzzleClient->post('webhooks/hub', [ 137 | 'headers' => $headers, 138 | 'body' => json_encode($body), 139 | ]); 140 | } 141 | 142 | private function unsubscribe(string $topic, string $callback, string $bearer): void 143 | { 144 | $headers = [ 145 | 'Client-ID' => $this->clientId, 146 | ]; 147 | 148 | $headers['Authorization'] = sprintf('Bearer %s', $bearer); 149 | 150 | $body = [ 151 | 'hub.callback' => $callback, 152 | 'hub.mode' => self::UNSUBSCRIBE, 153 | 'hub.topic' => $topic, 154 | ]; 155 | 156 | $this->guzzleClient->post('webhooks/hub', [ 157 | 'headers' => $headers, 158 | 'body' => json_encode($body), 159 | ]); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/Resources/StreamsApi.php: -------------------------------------------------------------------------------- 1 | getStreams($bearer, [$userId]); 18 | } 19 | 20 | /** 21 | * @throws GuzzleException 22 | */ 23 | public function getStreamForUsername(string $bearer, string $username): ResponseInterface 24 | { 25 | return $this->getStreams($bearer, [], [$username]); 26 | } 27 | 28 | /** 29 | * @throws GuzzleException 30 | */ 31 | public function getStreamsByGameId(string $bearer, string $gameId, int $first = null, string $before = null, string $after = null): ResponseInterface 32 | { 33 | return $this->getStreams($bearer, [], [], [$gameId]); 34 | } 35 | 36 | /** 37 | * @throws GuzzleException 38 | */ 39 | public function getStreamsByLanguage(string $bearer, string $language, int $first = null, string $before = null, string $after = null): ResponseInterface 40 | { 41 | return $this->getStreams($bearer, [], [], [], [$language]); 42 | } 43 | 44 | /** 45 | * @throws GuzzleException 46 | * @link https://dev.twitch.tv/docs/api/reference#get-stream-key 47 | */ 48 | public function getStreamKey(string $bearer, string $broadcasterId): ResponseInterface 49 | { 50 | $queryParamsMap = []; 51 | 52 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 53 | 54 | return $this->getApi('streams/key', $bearer, $queryParamsMap); 55 | } 56 | 57 | /** 58 | * @throws GuzzleException 59 | * @link https://dev.twitch.tv/docs/api/reference/#get-streams 60 | */ 61 | public function getStreams(string $bearer, array $userIds = [], array $usernames = [], array $gameIds = [], array $languages = [], int $first = null, string $before = null, string $after = null): ResponseInterface 62 | { 63 | $queryParamsMap = []; 64 | foreach ($userIds as $id) { 65 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $id]; 66 | } 67 | foreach ($usernames as $username) { 68 | $queryParamsMap[] = ['key' => 'user_login', 'value' => $username]; 69 | } 70 | foreach ($gameIds as $gameId) { 71 | $queryParamsMap[] = ['key' => 'game_id', 'value' => $gameId]; 72 | } 73 | foreach ($languages as $language) { 74 | $queryParamsMap[] = ['key' => 'language', 'value' => $language]; 75 | } 76 | if ($first) { 77 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 78 | } 79 | if ($before) { 80 | $queryParamsMap[] = ['key' => 'before', 'value' => $before]; 81 | } 82 | if ($after) { 83 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 84 | } 85 | 86 | return $this->getApi('streams', $bearer, $queryParamsMap); 87 | } 88 | 89 | /** 90 | * @throws GuzzleException 91 | * @link https://dev.twitch.tv/docs/api/reference/#get-stream-markers 92 | */ 93 | public function getStreamMarkers(string $bearer, string $userId = null, string $videoId = null, string $first = null, string $before = null, string $after = null): ResponseInterface 94 | { 95 | $queryParamsMap = []; 96 | 97 | if ($userId) { 98 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 99 | } 100 | 101 | if ($videoId) { 102 | $queryParamsMap[] = ['key' => 'video_id', 'value' => $videoId]; 103 | } 104 | 105 | if ($first) { 106 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 107 | } 108 | 109 | if ($before) { 110 | $queryParamsMap[] = ['key' => 'before', 'value' => $before]; 111 | } 112 | 113 | if ($after) { 114 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 115 | } 116 | 117 | return $this->getApi('streams/markers', $bearer, $queryParamsMap); 118 | } 119 | 120 | /** 121 | * @throws GuzzleException 122 | * @link https://dev.twitch.tv/docs/api/reference/#get-followed-streams 123 | */ 124 | public function getFollowedStreams(string $bearer, string $userId, int $first = null, string $after = null): ResponseInterface 125 | { 126 | $queryParamsMap = []; 127 | 128 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 129 | 130 | if ($first) { 131 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 132 | } 133 | 134 | if ($after) { 135 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 136 | } 137 | 138 | return $this->getApi('streams/followed', $bearer, $queryParamsMap); 139 | } 140 | 141 | /** 142 | * @throws GuzzleException 143 | * @link https://dev.twitch.tv/docs/api/reference#create-stream-marker 144 | */ 145 | public function createStreamMarker(string $bearer, string $userId, string $description = null): ResponseInterface 146 | { 147 | $bodyParamsMap = []; 148 | 149 | $bodyParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 150 | if ($description) { 151 | $bodyParamsMap[] = ['key' => 'description', 'value' => $description]; 152 | } 153 | 154 | return $this->postApi('streams/markers', $bearer, [], $bodyParamsMap); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/Resources/ChannelPointsApi.php: -------------------------------------------------------------------------------- 1 | getCustomReward($bearer, $broadcasterId, [$id], $onlyManageableRewards); 18 | } 19 | 20 | /** 21 | * @throws GuzzleException 22 | * @link https://dev.twitch.tv/docs/api/reference#get-custom-reward 23 | */ 24 | public function getCustomReward(string $bearer, string $broadcasterId, array $ids = [], bool $onlyManageableRewards = null): ResponseInterface 25 | { 26 | $queryParamsMap = []; 27 | 28 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 29 | 30 | foreach ($ids as $id) { 31 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 32 | } 33 | 34 | if ($onlyManageableRewards) { 35 | $queryParamsMap[] = ['key' => 'only_manageable_rewards', 'value' => $onlyManageableRewards]; 36 | } 37 | 38 | return $this->getApi('channel_points/custom_rewards', $bearer, $queryParamsMap); 39 | } 40 | 41 | /** 42 | * @throws GuzzleException 43 | * @link https://dev.twitch.tv/docs/api/reference#get-custom-reward-redemption 44 | */ 45 | public function getCustomRewardRedemption(string $bearer, string $broadcasterId, string $rewardId = null, array $ids = [], string $status = null, string $sort = null, string $after = null, string $first = null): ResponseInterface 46 | { 47 | $queryParamsMap = []; 48 | 49 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 50 | 51 | if ($rewardId) { 52 | $queryParamsMap[] = ['key' => 'reward_id', 'value' => $rewardId]; 53 | } 54 | 55 | foreach ($ids as $id) { 56 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 57 | } 58 | 59 | if ($status) { 60 | $queryParamsMap[] = ['key' => 'status', 'value' => $status]; 61 | } 62 | 63 | if ($sort) { 64 | $queryParamsMap[] = ['key' => 'sort', 'value' => $sort]; 65 | } 66 | 67 | if ($after) { 68 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 69 | } 70 | 71 | if ($first) { 72 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 73 | } 74 | 75 | return $this->getApi('channel_points/custom_rewards/redemptions', $bearer, $queryParamsMap); 76 | } 77 | 78 | /** 79 | * @throws GuzzleException 80 | * @link https://dev.twitch.tv/docs/api/reference#create-custom-rewards 81 | */ 82 | public function createCustomReward(string $bearer, string $broadcasterId, string $title, int $cost, $additionalBodyParams = []): ResponseInterface 83 | { 84 | // $additionalBodyParams should be a standard key => value format, eg. ['game_id' => '1']; 85 | $queryParamsMap = $bodyParamsMap = []; 86 | 87 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 88 | 89 | $bodyParamsMap[] = ['key' => 'title', 'value' => $title]; 90 | $bodyParamsMap[] = ['key' => 'cost', 'value' => $cost]; 91 | 92 | foreach ($additionalBodyParams as $key => $value) { 93 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 94 | } 95 | 96 | return $this->postApi('channel_points/custom_rewards', $bearer, $queryParamsMap, $bodyParamsMap); 97 | } 98 | 99 | /** 100 | * @throws GuzzleException 101 | * @link https://dev.twitch.tv/docs/api/reference#update-custom-reward 102 | */ 103 | public function updateCustomReward(string $bearer, string $broadcasterId, string $rewardId, $bodyParams = []): ResponseInterface 104 | { 105 | // $bodyParams should be a standard key => value format, eg. ['game_id' => '1']; 106 | $queryParamsMap = $bodyParamsMap = []; 107 | 108 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 109 | $queryParamsMap[] = ['key' => 'id', 'value' => $rewardId]; 110 | 111 | foreach ($bodyParams as $key => $value) { 112 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 113 | } 114 | 115 | return $this->patchApi('channel_points/custom_rewards', $bearer, $queryParamsMap, $bodyParamsMap); 116 | } 117 | 118 | /** 119 | * @throws GuzzleException 120 | * @link https://dev.twitch.tv/docs/api/reference#delete-custom-reward 121 | */ 122 | public function deleteCustomReward(string $bearer, string $broadcasterId, string $id): ResponseInterface 123 | { 124 | $queryParamsMap = []; 125 | 126 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 127 | 128 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 129 | 130 | return $this->deleteApi('channel_points/custom_rewards', $bearer, $queryParamsMap); 131 | } 132 | 133 | /** 134 | * @throws GuzzleException 135 | * @link https://dev.twitch.tv/docs/api/reference#update-redemption-status 136 | */ 137 | public function updateRedemptionStatus(string $bearer, string $broadcasterId, string $rewardId, string $redemptionId, string $status): ResponseInterface 138 | { 139 | $queryParamsMap = $bodyParamsMap = []; 140 | 141 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 142 | $queryParamsMap[] = ['key' => 'reward_id', 'value' => $rewardId]; 143 | $queryParamsMap[] = ['key' => 'id', 'value' => $redemptionId]; 144 | 145 | $bodyParamsMap[] = ['key' => 'status', 'value' => $status]; 146 | 147 | return $this->patchApi('channel_points/custom_rewards/redemptions', $bearer, $queryParamsMap, $bodyParamsMap); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /spec/TwitchApi/TwitchApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, 'client-id', 'client-secret'); 43 | } 44 | 45 | function it_should_provide_oauth_api() 46 | { 47 | $this->getOauthApi()->shouldBeAnInstanceOf(OauthApi::class); 48 | } 49 | 50 | function it_should_provide_ads_api() 51 | { 52 | $this->getAdsApi()->shouldBeAnInstanceOf(AdsApi::class); 53 | } 54 | 55 | function it_should_provide_analytics_api() 56 | { 57 | $this->getAnalyticsApi()->shouldBeAnInstanceOf(AnalyticsApi::class); 58 | } 59 | 60 | function it_should_provide_bits_api() 61 | { 62 | $this->getBitsApi()->shouldBeAnInstanceOf(BitsApi::class); 63 | } 64 | 65 | function it_should_provide_channel_points_api() 66 | { 67 | $this->getChannelPointsApi()->shouldBeAnInstanceOf(ChannelPointsApi::class); 68 | } 69 | 70 | function it_should_provide_channels_api() 71 | { 72 | $this->getChannelsApi()->shouldBeAnInstanceOf(ChannelsApi::class); 73 | } 74 | 75 | function it_should_provide_charity_api() 76 | { 77 | $this->getCharityApi()->shouldBeAnInstanceOf(CharityApi::class); 78 | } 79 | 80 | function it_should_provide_chat_api() 81 | { 82 | $this->getChatApi()->shouldBeAnInstanceOf(ChatApi::class); 83 | } 84 | 85 | function it_should_provide_clips_api() 86 | { 87 | $this->getClipsApi()->shouldBeAnInstanceOf(ClipsApi::class); 88 | } 89 | 90 | function it_should_provide_entitlements_api() 91 | { 92 | $this->getEntitlementsApi()->shouldBeAnInstanceOf(EntitlementsApi::class); 93 | } 94 | 95 | function it_should_provide_event_sub_api() 96 | { 97 | $this->getEventSubApi()->shouldBeAnInstanceOf(EventSubApi::class); 98 | } 99 | 100 | function it_should_provide_games_api() 101 | { 102 | $this->getGamesApi()->shouldBeAnInstanceOf(GamesApi::class); 103 | } 104 | 105 | function it_should_provide_goals_api() 106 | { 107 | $this->getGoalsApi()->shouldBeAnInstanceOf(GoalsApi::class); 108 | } 109 | 110 | function it_should_provide_hype_train_api() { 111 | $this->getHypeTrainApi()->shouldBeAnInstanceOf(HypeTrainApi::class); 112 | } 113 | 114 | function it_should_provide_moderation_api() 115 | { 116 | $this->getModerationApi()->shouldBeAnInstanceOf(ModerationApi::class); 117 | } 118 | 119 | function it_should_provide_polls_api() 120 | { 121 | $this->getPollsApi()->shouldBeAnInstanceOf(PollsApi::class); 122 | } 123 | 124 | function it_should_provide_predictions_api() 125 | { 126 | $this->getPredictionsApi()->shouldBeAnInstanceOf(PredictionsApi::class); 127 | } 128 | 129 | function it_should_provide_raids_api() 130 | { 131 | $this->getRaidsApi()->shouldBeAnInstanceOf(RaidsApi::class); 132 | } 133 | 134 | function it_should_provide_schedule_api() 135 | { 136 | $this->getScheduleApi()->shouldBeAnInstanceOf(ScheduleApi::class); 137 | } 138 | 139 | function it_should_provide_search_api() 140 | { 141 | $this->getSearchApi()->shouldBeAnInstanceOf(SearchApi::class); 142 | } 143 | 144 | function it_should_provide_streams_api() 145 | { 146 | $this->getStreamsApi()->shouldBeAnInstanceOf(StreamsApi::class); 147 | } 148 | 149 | function it_should_provide_subscriptions_api() 150 | { 151 | $this->getSubscriptionsApi()->shouldBeAnInstanceOf(SubscriptionsApi::class); 152 | } 153 | 154 | function it_should_provide_tags_api() 155 | { 156 | $this->getTagsApi()->shouldBeAnInstanceOf(TagsApi::class); 157 | } 158 | 159 | function it_should_provide_teams_api() 160 | { 161 | $this->getTeamsApi()->shouldBeAnInstanceOf(TeamsApi::class); 162 | } 163 | 164 | function it_should_provide_users_api() 165 | { 166 | $this->getUsersApi()->shouldBeAnInstanceOf(UsersApi::class); 167 | } 168 | 169 | function it_should_provide_videos_api() 170 | { 171 | $this->getVideosApi()->shouldBeAnInstanceOf(VideosApi::class); 172 | } 173 | 174 | function it_should_provide_webhooks_api() 175 | { 176 | $this->getWebhooksApi()->shouldBeAnInstanceOf(WebhooksApi::class); 177 | } 178 | 179 | function it_should_provide_whispers_api() 180 | { 181 | $this->getWhispersApi()->shouldBeAnInstanceOf(WhispersApi::class); 182 | } 183 | 184 | function it_should_provide_webhooks_subscription_api() 185 | { 186 | $this->getWebhooksSubscriptionApi()->shouldBeAnInstanceOf(WebhooksSubscriptionApi::class); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/Resources/ScheduleApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 21 | 22 | foreach ($ids as $id) { 23 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 24 | } 25 | 26 | if ($startTime) { 27 | $queryParamsMap[] = ['key' => 'start_time', 'value' => $startTime]; 28 | } 29 | 30 | if ($utcOffset) { 31 | $queryParamsMap[] = ['key' => 'utc_offset', 'value' => $utcOffset]; 32 | } 33 | 34 | if ($first) { 35 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 36 | } 37 | 38 | if ($after) { 39 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 40 | } 41 | 42 | return $this->getApi('schedule', $bearer, $queryParamsMap); 43 | } 44 | 45 | /** 46 | * @throws GuzzleException 47 | * @link https://dev.twitch.tv/docs/api/reference/#get-channel-icalendar 48 | */ 49 | public function getChanneliCalendar(string $bearer = null, string $broadcasterId): ResponseInterface 50 | { 51 | // This endpoint at the time of addition does not require any authorization, so the bearer is null. 52 | // However, to prevent a breaking update in the future, it will remain the first function parameter. 53 | // You may simple pass NULL to this to bypass authentication. 54 | 55 | $queryParamsMap = []; 56 | 57 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 58 | 59 | return $this->getApiWithOptionalAuth('schedule/icalendar', $bearer, $queryParamsMap); 60 | } 61 | 62 | /** 63 | * @throws GuzzleException 64 | * @link https://dev.twitch.tv/docs/api/reference/#update-channel-stream-schedule 65 | */ 66 | public function updateChannelStreamSchedule(string $bearer, string $broadcasterId, bool $isVacationEnabled = null, $vacationStartTime = null, $vacationEndTime = null, $timezone = null): ResponseInterface 67 | { 68 | $queryParamsMap = []; 69 | 70 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 71 | 72 | if ($isVacationEnabled) { 73 | $queryParamsMap[] = ['key' => 'is_vacation_enabled', 'value' => $isVacationEnabled]; 74 | } 75 | 76 | if ($vacationStartTime) { 77 | $queryParamsMap[] = ['key' => 'vacation_start_time', 'value' => $vacationStartTime]; 78 | } 79 | 80 | if ($vacationEndTime) { 81 | $queryParamsMap[] = ['key' => 'vacation_end_time', 'value' => $vacationEndTime]; 82 | } 83 | 84 | if ($timezone) { 85 | $queryParamsMap[] = ['key' => 'timezone', 'value' => $timezone]; 86 | } 87 | 88 | return $this->patchApi('schedule/settings', $bearer, $queryParamsMap); 89 | } 90 | 91 | /** 92 | * @throws GuzzleException 93 | * @link https://dev.twitch.tv/docs/api/reference/#create-channel-stream-schedule-segment 94 | */ 95 | public function createChannelStreamScheduleSegment(string $bearer, string $broadcasterId, string $startTime, string $timezone, bool $isRecurring, array $additionalBodyParams = []): ResponseInterface 96 | { 97 | // $additionalBodyParams should be a standard key => value format, eg. ['duration' => '240']; 98 | $queryParamsMap = $bodyParamsMap = []; 99 | 100 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 101 | 102 | $bodyParamsMap[] = ['key' => 'start_time', 'value' => $startTime]; 103 | $bodyParamsMap[] = ['key' => 'timezone', 'value' => $timezone]; 104 | $bodyParamsMap[] = ['key' => 'is_recurring', 'value' => $isRecurring]; 105 | 106 | foreach ($additionalBodyParams as $key => $value) { 107 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 108 | } 109 | 110 | return $this->postApi('schedule/segment', $bearer, $queryParamsMap, $bodyParamsMap); 111 | } 112 | 113 | /** 114 | * @throws GuzzleException 115 | * @link https://dev.twitch.tv/docs/api/reference/#update-channel-stream-schedule-segment 116 | */ 117 | public function updateChannelStreamScheduleSegment(string $bearer, string $broadcasterId, string $segmentId, array $updateValues = []): ResponseInterface 118 | { 119 | // $updateValues should be a standard key => value format based on the values available on the documentation, eg. ['duration' => '240']; 120 | $queryParamsMap = $bodyParamsMap = []; 121 | 122 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 123 | $queryParamsMap[] = ['key' => 'id', 'value' => $segmentId]; 124 | 125 | foreach ($updateValues as $key => $value) { 126 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 127 | } 128 | 129 | return $this->patchApi('schedule/segment', $bearer, $queryParamsMap, $bodyParamsMap); 130 | } 131 | 132 | /** 133 | * @throws GuzzleException 134 | * @link https://dev.twitch.tv/docs/api/reference/#delete-channel-stream-schedule-segment 135 | */ 136 | public function deleteChannelStreamScheduleSegment(string $bearer, string $broadcasterId, string $segmentId): ResponseInterface 137 | { 138 | $queryParamsMap = []; 139 | 140 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 141 | $queryParamsMap[] = ['key' => 'id', 'value' => $segmentId]; 142 | 143 | return $this->deleteApi('schedule/segment', $bearer, $queryParamsMap); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Resources/UsersApi.php: -------------------------------------------------------------------------------- 1 | getUsers($userAccessToken, [], [], $includeEmail); 18 | } 19 | 20 | /** 21 | * @throws GuzzleException 22 | */ 23 | public function getUserById(string $bearer, string $id, bool $includeEmail = false): ResponseInterface 24 | { 25 | return $this->getUsers($bearer, [$id], [], $includeEmail); 26 | } 27 | 28 | /** 29 | * @throws GuzzleException 30 | */ 31 | public function getUserByUsername(string $bearer, string $username, bool $includeEmail = false): ResponseInterface 32 | { 33 | return $this->getUsers($bearer, [], [$username], $includeEmail); 34 | } 35 | 36 | /** 37 | * @throws GuzzleException 38 | * @link https://dev.twitch.tv/docs/api/reference/#get-users 39 | */ 40 | public function getUsers(string $bearer, array $ids = [], array $usernames = [], bool $includeEmail = false): ResponseInterface 41 | { 42 | $queryParamsMap = []; 43 | foreach ($ids as $id) { 44 | $queryParamsMap[] = ['key' => 'id', 'value' => $id]; 45 | } 46 | foreach ($usernames as $username) { 47 | $queryParamsMap[] = ['key' => 'login', 'value' => $username]; 48 | } 49 | if ($includeEmail) { 50 | $queryParamsMap[] = ['key' => 'scope', 'value' => 'user:read:email']; 51 | } 52 | 53 | return $this->getApi('users', $bearer, $queryParamsMap); 54 | } 55 | 56 | /** 57 | * @throws GuzzleException 58 | * @link https://dev.twitch.tv/docs/api/reference/#get-users-follows 59 | */ 60 | public function getUsersFollows(string $bearer, string $followerId = null, string $followedUserId = null, int $first = null, string $after = null): ResponseInterface 61 | { 62 | $queryParamsMap = []; 63 | if ($followerId) { 64 | $queryParamsMap[] = ['key' => 'from_id', 'value' => $followerId]; 65 | } 66 | if ($followedUserId) { 67 | $queryParamsMap[] = ['key' => 'to_id', 'value' => $followedUserId]; 68 | } 69 | if ($first) { 70 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 71 | } 72 | if ($after) { 73 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 74 | } 75 | 76 | return $this->getApi('users/follows', $bearer, $queryParamsMap); 77 | } 78 | 79 | /** 80 | * @throws GuzzleException 81 | * @link https://dev.twitch.tv/docs/api/reference/#get-user-extensions 82 | */ 83 | public function getUserExtensions(string $bearer): ResponseInterface 84 | { 85 | $queryParamsMap = []; 86 | 87 | return $this->getApi('users/extensions/list', $bearer, $queryParamsMap); 88 | } 89 | 90 | /** 91 | * @throws GuzzleException 92 | * @link https://dev.twitch.tv/docs/api/reference/#get-user-active-extensions 93 | */ 94 | public function getActiveUserExtensions(string $bearer, string $userId = null): ResponseInterface 95 | { 96 | $queryParamsMap = []; 97 | 98 | if ($userId) { 99 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 100 | } 101 | 102 | return $this->getApi('users/extensions', $bearer, $queryParamsMap); 103 | } 104 | 105 | /** 106 | * @throws GuzzleException 107 | * @link https://dev.twitch.tv/docs/api/reference#update-user 108 | */ 109 | public function updateUser(string $bearer, string $description = null): ResponseInterface 110 | { 111 | $queryParamsMap = []; 112 | 113 | if ($description) { 114 | $queryParamsMap[] = ['key' => 'description', 'value' => $description]; 115 | } 116 | 117 | return $this->putApi('users', $bearer, $queryParamsMap); 118 | } 119 | 120 | /** 121 | * @throws GuzzleException 122 | * @link https://dev.twitch.tv/docs/api/reference#get-user-block-list 123 | */ 124 | public function getUserBlockList(string $bearer, string $broadcasterId, int $first = null, string $after = null): ResponseInterface 125 | { 126 | $queryParamsMap = []; 127 | 128 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 129 | 130 | if ($first) { 131 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 132 | } 133 | if ($after) { 134 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 135 | } 136 | 137 | return $this->getApi('users/blocks', $bearer, $queryParamsMap); 138 | } 139 | 140 | /** 141 | * @throws GuzzleException 142 | * @link https://dev.twitch.tv/docs/api/reference#block-user 143 | */ 144 | public function blockUser(string $bearer, string $targetUserId, string $sourceContext = null, string $reason = null): ResponseInterface 145 | { 146 | $queryParamsMap = []; 147 | 148 | $queryParamsMap[] = ['key' => 'target_user_id', 'value' => $targetUserId]; 149 | 150 | if ($sourceContext) { 151 | $queryParamsMap[] = ['key' => 'source_context', 'value' => $sourceContext]; 152 | } 153 | 154 | if ($reason) { 155 | $queryParamsMap[] = ['key' => 'reason', 'value' => $reason]; 156 | } 157 | 158 | return $this->putApi('users/blocks', $bearer, $queryParamsMap); 159 | } 160 | 161 | /** 162 | * @throws GuzzleException 163 | * @link https://dev.twitch.tv/docs/api/reference#unblock-user 164 | */ 165 | public function unblockUser(string $bearer, string $targetUserId): ResponseInterface 166 | { 167 | $queryParamsMap = []; 168 | 169 | $queryParamsMap[] = ['key' => 'target_user_id', 'value' => $targetUserId]; 170 | 171 | return $this->deleteApi('users/blocks', $bearer, $queryParamsMap); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/AnalyticsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_extension_analytics(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [], [])->willReturn($request); 22 | $this->getExtensionAnalytics('TEST_TOKEN')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_extension_analytics_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'extension_id', 'value' => '1']], [])->willReturn($request); 28 | $this->getExtensionAnalytics('TEST_TOKEN', '1')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_extension_analytics_with_type(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'type', 'value' => 'overview_v1']], [])->willReturn($request); 34 | $this->getExtensionAnalytics('TEST_TOKEN', null, 'overview_v1')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_extension_analytics_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'first', 'value' => '100']], [])->willReturn($request); 40 | $this->getExtensionAnalytics('TEST_TOKEN', null, null, 100)->shouldBe($response); 41 | } 42 | 43 | function it_should_get_extension_analytics_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 46 | $this->getExtensionAnalytics('TEST_TOKEN', null, null, null, 'abc')->shouldBe($response); 47 | } 48 | 49 | function it_should_get_extension_analytics_with_started_at(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'started_at', 'value' => '2020-01-01T00:00:00Z']], [])->willReturn($request); 52 | $this->getExtensionAnalytics('TEST_TOKEN', null, null, null, null, '2020-01-01T00:00:00Z')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_extension_analytics_with_ended_at(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'analytics/extensions', 'TEST_TOKEN', [['key' => 'ended_at', 'value' => '2020-01-01T00:00:00Z']], [])->willReturn($request); 58 | $this->getExtensionAnalytics('TEST_TOKEN', null, null, null, null, null, '2020-01-01T00:00:00Z')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_game_analytics(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [], [])->willReturn($request); 64 | $this->getGameAnalytics('TEST_TOKEN')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_game_analytics_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '1']], [])->willReturn($request); 70 | $this->getGameAnalytics('TEST_TOKEN', '1')->shouldBe($response); 71 | } 72 | 73 | function it_should_get_game_analytics_with_type(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'type', 'value' => 'overview_v1']], [])->willReturn($request); 76 | $this->getGameAnalytics('TEST_TOKEN', null, 'overview_v1')->shouldBe($response); 77 | } 78 | 79 | function it_should_get_game_analytics_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'first', 'value' => '100']], [])->willReturn($request); 82 | $this->getGameAnalytics('TEST_TOKEN', null, null, 100)->shouldBe($response); 83 | } 84 | 85 | function it_should_get_game_analytics_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 86 | { 87 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 88 | $this->getGameAnalytics('TEST_TOKEN', null, null, null, 'abc')->shouldBe($response); 89 | } 90 | 91 | function it_should_get_game_analytics_with_started_at(RequestGenerator $requestGenerator, Request $request, Response $response) 92 | { 93 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'started_at', 'value' => '2020-01-01T00:00:00Z']], [])->willReturn($request); 94 | $this->getGameAnalytics('TEST_TOKEN', null, null, null, null, '2020-01-01T00:00:00Z')->shouldBe($response); 95 | } 96 | 97 | function it_should_get_game_analytics_with_ended_at(RequestGenerator $requestGenerator, Request $request, Response $response) 98 | { 99 | $requestGenerator->generate('GET', 'analytics/games', 'TEST_TOKEN', [['key' => 'ended_at', 'value' => '2020-01-01T00:00:00Z']], [])->willReturn($request); 100 | $this->getGameAnalytics('TEST_TOKEN', null, null, null, null, null, '2020-01-01T00:00:00Z')->shouldBe($response); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/VideosApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_video_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 22 | $this->getVideos('TEST_TOKEN', ['123'])->shouldBe($response); 23 | } 24 | 25 | function it_should_get_videos_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'id', 'value' => '123'], ['key' => 'id', 'value' => '321']], [])->willReturn($request); 28 | $this->getVideos('TEST_TOKEN', ['123', '321'])->shouldBe($response); 29 | } 30 | 31 | function it_should_get_videos_by_user_id(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123']], [])->willReturn($request); 34 | $this->getVideos('TEST_TOKEN', [], '123')->shouldBe($response); 35 | } 36 | 37 | function it_should_get_videos_by_game_id(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '123']], [])->willReturn($request); 40 | $this->getVideos('TEST_TOKEN', [], null, '123')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_videos_with_first(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'first', 'value' => 100]], [])->willReturn($request); 46 | $this->getVideos('TEST_TOKEN', [], null, null, 100)->shouldBe($response); 47 | } 48 | 49 | function it_should_get_videos_with_before(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'before', 'value' => 'abc']], [])->willReturn($request); 52 | $this->getVideos('TEST_TOKEN', [], null, null, null, 'abc')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_videos_with_after(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'after', 'value' => 'cba']], [])->willReturn($request); 58 | $this->getVideos('TEST_TOKEN', [], null, null, null, null, 'cba')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_videos_with_language(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'language', 'value' => 'en']], [])->willReturn($request); 64 | $this->getVideos('TEST_TOKEN', [], null, null, null, null, null, 'en')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_videos_with_period(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'period', 'value' => 'all']], [])->willReturn($request); 70 | $this->getVideos('TEST_TOKEN', [], null, null, null, null, null, null, 'all')->shouldBe($response); 71 | } 72 | 73 | function it_should_get_videos_with_sort(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'sort', 'value' => 'trending']], [])->willReturn($request); 76 | $this->getVideos('TEST_TOKEN', [], null, null, null, null, null, null, null, 'trending')->shouldBe($response); 77 | } 78 | 79 | function it_should_get_videos_with_type(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'type', 'value' => 'all']], [])->willReturn($request); 82 | $this->getVideos('TEST_TOKEN', [], null, null, null, null, null, null, null, null, 'all')->shouldBe($response); 83 | } 84 | 85 | function it_should_get_videos_with_everything(RequestGenerator $requestGenerator, Request $request, Response $response) 86 | { 87 | $requestGenerator->generate('GET', 'videos', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'game_id', 'value' => '321'], ['key' => 'first', 'value' => 100], ['key' => 'before', 'value' => 'abc'], ['key' => 'after', 'value' => 'def'], ['key' => 'language', 'value' => 'en'], ['key' => 'period', 'value' => 'all'], ['key' => 'sort', 'value' => 'trending'], ['key' => 'type', 'value' => 'all']], [])->willReturn($request); 88 | $this->getVideos('TEST_TOKEN', [], '123', '321', 100, 'abc', 'def', 'en', 'all', 'trending', 'all')->shouldBe($response); 89 | } 90 | 91 | function it_should_delete_videos(RequestGenerator $requestGenerator, Request $request, Response $response) 92 | { 93 | $requestGenerator->generate('DELETE', 'videos', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 94 | $this->deleteVideos('TEST_TOKEN', ['123'])->shouldBe($response); 95 | } 96 | 97 | function it_should_delete_multiple_videos(RequestGenerator $requestGenerator, Request $request, Response $response) 98 | { 99 | $requestGenerator->generate('DELETE', 'videos', 'TEST_TOKEN', [['key' => 'id', 'value' => '123'], ['key' => 'id', 'value' => '321']], [])->willReturn($request); 100 | $this->deleteVideos('TEST_TOKEN', ['123', '321'])->shouldBe($response); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/ScheduleApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_channel_stream_schedule(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'schedule', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getChannelStreamSchedule('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_channel_stream_schedule_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'schedule', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'start_time', 'value' => '2021-06-15T23:08:20+00:00'], ['key' => 'utc_offset', 'value' => '240'], ['key' => 'first', 'value' => 25], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 28 | $this->getChannelStreamSchedule('TEST_TOKEN', '123', [], '2021-06-15T23:08:20+00:00', '240', 25, 'abc')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_a_channel_stream_schedule(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'schedule', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456']], [])->willReturn($request); 34 | $this->getChannelStreamSchedule('TEST_TOKEN', '123', ['456'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_multiple_channel_stream_schedules(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'schedule', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456'], ['key' => 'id', 'value' => '789']], [])->willReturn($request); 40 | $this->getChannelStreamSchedule('TEST_TOKEN', '123', ['456', '789'])->shouldBe($response); 41 | } 42 | 43 | function it_should_get_channel_icalendar_with_no_auth(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'schedule/icalendar', null, [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 46 | $this->getChanneliCalendar(null, '123')->shouldBe($response); 47 | } 48 | 49 | function it_should_get_channel_icalendar_with_auth(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'schedule/icalendar', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 52 | $this->getChanneliCalendar('TEST_TOKEN', '123')->shouldBe($response); 53 | } 54 | 55 | function it_should_update_channel_stream_schedule(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('PATCH', 'schedule/settings', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'is_vacation_enabled', 'value' => true], ['key' => 'vacation_start_time', 'value' => '2021-06-15T23:08:20+00:00'], ['key' => 'vacation_end_time', 'value' => '2021-06-22T23:08:20+00:00'], ['key' => 'timezone', 'value' => 'America/New_York']], [])->willReturn($request); 58 | $this->updateChannelStreamSchedule('TEST_TOKEN', '123', true, '2021-06-15T23:08:20+00:00', '2021-06-22T23:08:20+00:00', 'America/New_York')->shouldBe($response); 59 | } 60 | 61 | function it_should_create_channel_stream_schedule_segment(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('POST', 'schedule/segment', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'start_time', 'value' => '2021-06-15T23:08:20+00:00'], ['key' => 'timezone', 'value' => 'America/New_York'], ['key' => 'is_recurring', 'value' => true]])->willReturn($request); 64 | $this->createChannelStreamScheduleSegment('TEST_TOKEN', '123', '2021-06-15T23:08:20+00:00', 'America/New_York', true)->shouldBe($response); 65 | } 66 | 67 | function it_should_create_channel_stream_schedule_segment_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('POST', 'schedule/segment', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [['key' => 'start_time', 'value' => '2021-06-15T23:08:20+00:00'], ['key' => 'timezone', 'value' => 'America/New_York'], ['key' => 'is_recurring', 'value' => true], ['key' => 'duration', 'value' => '240']])->willReturn($request); 70 | $this->createChannelStreamScheduleSegment('TEST_TOKEN', '123', '2021-06-15T23:08:20+00:00', 'America/New_York', true, ['duration' => '240'])->shouldBe($response); 71 | } 72 | 73 | function it_should_update_channel_stream_schedule_segment(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('PATCH', 'schedule/segment', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456']], [['key' => 'start_time', 'value' => '2021-06-15T23:08:20+00:00'], ['key' => 'timezone', 'value' => 'America/New_York'], ['key' => 'is_canceled', 'value' => true], ['key' => 'duration', 'value' => '240']])->willReturn($request); 76 | $this->updateChannelStreamScheduleSegment('TEST_TOKEN', '123', '456', ['start_time' => '2021-06-15T23:08:20+00:00', 'timezone' => 'America/New_York', 'is_canceled' => true, 'duration' => '240'])->shouldBe($response); 77 | } 78 | 79 | function it_should_delete_channel_stream_schedule_segment(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('DELETE', 'schedule/segment', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'id', 'value' => '456']], [])->willReturn($request); 82 | $this->deleteChannelStreamScheduleSegment('TEST_TOKEN', '123', '456')->shouldBe($response); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/EntitlementsApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_create_entitlement_grants_upload_url(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('POST', 'entitlements/upload', 'TEST_TOKEN', [['key' => 'manifest_id', 'value' => '123'], ['key' => 'type', 'value' => 'bulk_drops_grant']], [])->willReturn($request); 22 | $this->createEntitlementGrantsUploadURL('TEST_TOKEN', '123', 'bulk_drops_grant')->shouldBe($response); 23 | } 24 | 25 | function it_should_create_entitlement_grants_upload_url_shorthand(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('POST', 'entitlements/upload', 'TEST_TOKEN', [['key' => 'manifest_id', 'value' => '123'], ['key' => 'type', 'value' => 'bulk_drops_grant']], [])->willReturn($request); 28 | $this->createEntitlementGrantsUploadURL('TEST_TOKEN', '123')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_code_status(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'entitlements/codes', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'code', 'value' => 'abc']], [])->willReturn($request); 34 | $this->getCodeStatus('TEST_TOKEN', '123', ['abc'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_codes_status(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'entitlements/codes', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'code', 'value' => 'abc'], ['key' => 'code', 'value' => 'def']], [])->willReturn($request); 40 | $this->getCodeStatus('TEST_TOKEN', '123', ['abc', 'def'])->shouldBe($response); 41 | } 42 | 43 | function it_should_get_drop_entitlements_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'id', 'value' => '123']], [])->willReturn($request); 46 | $this->getDropsEntitlements('TEST_TOKEN', '123')->shouldBe($response); 47 | } 48 | 49 | function it_should_get_drop_entitlements_by_user_id(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123']], [])->willReturn($request); 52 | $this->getDropsEntitlements('TEST_TOKEN', null, '123')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_drop_entitlements_by_user_id_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'after', 'value' => 'abc'], ['key' => 'first', 'value' => 100]], [])->willReturn($request); 58 | $this->getDropsEntitlements('TEST_TOKEN', null, '123', null, 'abc', 100)->shouldBe($response); 59 | } 60 | 61 | function it_should_get_drop_entitlements_by_game_id(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '123']], [])->willReturn($request); 64 | $this->getDropsEntitlements('TEST_TOKEN', null, null, '123')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_drop_entitlements_by_game_id_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'game_id', 'value' => '123'], ['key' => 'after', 'value' => 'abc'], ['key' => 'first', 'value' => 100]], [])->willReturn($request); 70 | $this->getDropsEntitlements('TEST_TOKEN', null, null, '123', 'abc', 100)->shouldBe($response); 71 | } 72 | 73 | function it_should_get_drop_entitlements_by_status(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('GET', 'entitlements/drops', 'TEST_TOKEN', [['key' => 'fulfillment_status', 'value' => 'CLAIMED']], [])->willReturn($request); 76 | $this->getDropsEntitlements('TEST_TOKEN', null, null, null, null, null, 'CLAIMED')->shouldBe($response); 77 | } 78 | 79 | function it_should_redeem_code(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('POST', 'entitlements/code', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'code', 'value' => 'abc']], [])->willReturn($request); 82 | $this->redeemCode('TEST_TOKEN', '123', ['abc'])->shouldBe($response); 83 | } 84 | 85 | function it_should_redeem_codes(RequestGenerator $requestGenerator, Request $request, Response $response) 86 | { 87 | $requestGenerator->generate('POST', 'entitlements/code', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'code', 'value' => 'abc'], ['key' => 'code', 'value' => 'def']], [])->willReturn($request); 88 | $this->redeemCode('TEST_TOKEN', '123', ['abc', 'def'])->shouldBe($response); 89 | } 90 | 91 | function it_should_update_drop_entitlements(RequestGenerator $requestGenerator, Request $request, Response $response) 92 | { 93 | $requestGenerator->generate('PATCH', 'entitlements/drops', 'TEST_TOKEN', [], [])->willReturn($request); 94 | $this->updateDropsEntitlements('TEST_TOKEN')->shouldBe($response); 95 | } 96 | 97 | function it_should_update_one_drop_entitlements(RequestGenerator $requestGenerator, Request $request, Response $response) 98 | { 99 | $requestGenerator->generate('PATCH', 'entitlements/drops', 'TEST_TOKEN', [], [['key' => 'entitlement_ids', 'value' => ['123']], ['key' => 'fulfillment_status', 'value' => 'FULFILLED']])->willReturn($request); 100 | $this->updateDropsEntitlements('TEST_TOKEN', ['123'], 'FULFILLED')->shouldBe($response); 101 | } 102 | 103 | function it_should_update_multiple_drop_entitlements(RequestGenerator $requestGenerator, Request $request, Response $response) 104 | { 105 | $requestGenerator->generate('PATCH', 'entitlements/drops', 'TEST_TOKEN', [], [['key' => 'entitlement_ids', 'value' => ['123', '456']], ['key' => 'fulfillment_status', 'value' => 'FULFILLED']])->willReturn($request); 106 | $this->updateDropsEntitlements('TEST_TOKEN', ['123', '456'], 'FULFILLED')->shouldBe($response); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Resources/ChatApi.php: -------------------------------------------------------------------------------- 1 | 'broadcaster_id', 'value' => $broadcasterId]; 20 | 21 | return $this->getApi('chat/emotes', $bearer, $queryParamsMap); 22 | } 23 | 24 | /** 25 | * @throws GuzzleException 26 | * @link https://dev.twitch.tv/docs/api/reference#get-global-emotes 27 | */ 28 | public function getGlobalEmotes(string $bearer): ResponseInterface 29 | { 30 | return $this->getApi('chat/emotes/global', $bearer); 31 | } 32 | 33 | /** 34 | * @throws GuzzleException 35 | * @link https://dev.twitch.tv/docs/api/reference#get-emote-sets 36 | */ 37 | public function getEmoteSets(string $bearer, array $emoteSetIds = []): ResponseInterface 38 | { 39 | $queryParamsMap = []; 40 | 41 | foreach ($emoteSetIds as $emoteSetId) { 42 | $queryParamsMap[] = ['key' => 'emote_set_id', 'value' => $emoteSetId]; 43 | } 44 | 45 | return $this->getApi('chat/emotes/set', $bearer, $queryParamsMap); 46 | } 47 | 48 | public function getEmoteSet(string $bearer, string $emoteSetId): ResponseInterface 49 | { 50 | $queryParamsMap = []; 51 | $queryParamsMap[] = ['key' => 'emote_set_id', 'value' => $emoteSetId]; 52 | 53 | return $this->getApi('chat/emotes/set', $bearer, $queryParamsMap); 54 | } 55 | 56 | /** 57 | * @throws GuzzleException 58 | * @link https://dev.twitch.tv/docs/api/reference#get-channel-chat-badges 59 | */ 60 | public function getChannelChatBadges(string $bearer, string $broadcasterId): ResponseInterface 61 | { 62 | $queryParamsMap = []; 63 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 64 | 65 | return $this->getApi('chat/badges', $bearer, $queryParamsMap); 66 | } 67 | 68 | /** 69 | * @throws GuzzleException 70 | * @link https://dev.twitch.tv/docs/api/reference#get-global-chat-badges 71 | */ 72 | public function getGlobalChatBadges(string $bearer): ResponseInterface 73 | { 74 | return $this->getApi('chat/badges/global', $bearer); 75 | } 76 | 77 | /** 78 | * @throws GuzzleException 79 | * @link https://dev.twitch.tv/docs/api/reference#get-chat-settings 80 | */ 81 | public function getChatSettings(string $bearer, string $broadcasterId, string $moderatorId = null): ResponseInterface 82 | { 83 | $queryParamsMap = []; 84 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 85 | 86 | if ($moderatorId) { 87 | $queryParamsMap[] = ['key' => 'moderator_id', 'value' => $moderatorId]; 88 | } 89 | 90 | return $this->getApi('chat/settings', $bearer, $queryParamsMap); 91 | } 92 | 93 | /** 94 | * @throws GuzzleException 95 | * @link https://dev.twitch.tv/docs/api/reference#update-chat-settings 96 | */ 97 | public function updateChatSettings(string $bearer, string $broadcasterId, string $moderatorId, array $chatSettings): ResponseInterface 98 | { 99 | $queryParamsMap = $bodyParamsMap = []; 100 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 101 | 102 | $queryParamsMap[] = ['key' => 'moderator_id', 'value' => $moderatorId]; 103 | 104 | foreach ($chatSettings as $key => $value) { 105 | $bodyParamsMap[] = ['key' => $key, 'value' => $value]; 106 | } 107 | 108 | return $this->patchApi('chat/settings', $bearer, $queryParamsMap, $bodyParamsMap); 109 | } 110 | 111 | /** 112 | * @throws GuzzleException 113 | * @link https://dev.twitch.tv/docs/api/reference#send-chat-announcement 114 | */ 115 | public function sendChatAnnouncement(string $bearer, string $broadcasterId, string $moderatorId, string $message, string $color = null): ResponseInterface 116 | { 117 | $queryParamsMap = $bodyParamsMap = []; 118 | 119 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 120 | 121 | $queryParamsMap[] = ['key' => 'moderator_id', 'value' => $moderatorId]; 122 | 123 | $bodyParamsMap[] = ['key' => 'message', 'value' => $message]; 124 | 125 | if ($color) { 126 | $bodyParamsMap[] = ['key' => 'color', 'value' => $color]; 127 | } 128 | 129 | return $this->postApi('chat/announcements', $bearer, $queryParamsMap, $bodyParamsMap); 130 | } 131 | 132 | /** 133 | * @throws GuzzleException 134 | * @link https://dev.twitch.tv/docs/api/reference#get-user-chat-color 135 | */ 136 | public function getUserChatColor(string $bearer, string $userId): ResponseInterface 137 | { 138 | $queryParamsMap = []; 139 | 140 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 141 | 142 | return $this->getApi('chat/color', $bearer, $queryParamsMap); 143 | } 144 | 145 | /** 146 | * @throws GuzzleException 147 | * @link https://dev.twitch.tv/docs/api/reference#update-user-chat-color 148 | */ 149 | public function updateUserChatColor(string $bearer, string $userId, string $color): ResponseInterface 150 | { 151 | $queryParamsMap = []; 152 | 153 | $queryParamsMap[] = ['key' => 'user_id', 'value' => $userId]; 154 | 155 | $queryParamsMap[] = ['key' => 'color', 'value' => $color]; 156 | 157 | return $this->putApi('chat/color', $bearer, $queryParamsMap); 158 | } 159 | 160 | /** 161 | * @throws GuzzleException 162 | * @link https://dev.twitch.tv/docs/api/reference#get-chatters 163 | */ 164 | public function getChatters(string $bearer, string $broadcasterId, string $moderatorId, int $first = null, string $after = null): ResponseInterface 165 | { 166 | $queryParamsMap = []; 167 | 168 | $queryParamsMap[] = ['key' => 'broadcaster_id', 'value' => $broadcasterId]; 169 | 170 | $queryParamsMap[] = ['key' => 'moderator_id', 'value' => $moderatorId]; 171 | 172 | if ($first) { 173 | $queryParamsMap[] = ['key' => 'first', 'value' => $first]; 174 | } 175 | 176 | if ($after) { 177 | $queryParamsMap[] = ['key' => 'after', 'value' => $after]; 178 | } 179 | 180 | return $this->getApi('chat/chatters', $bearer, $queryParamsMap); 181 | } 182 | 183 | /** 184 | * @throws GuzzleException 185 | * @link https://dev.twitch.tv/docs/api/reference/#send-a-shoutout 186 | */ 187 | public function sendShoutout(string $bearer, string $fromBroadcasterId, string $toBroadcasterId, string $moderatorId): ResponseInterface 188 | { 189 | $queryParamsMap = []; 190 | 191 | $queryParamsMap[] = ['key' => 'from_broadcaster_id', 'value' => $fromBroadcasterId]; 192 | 193 | $queryParamsMap[] = ['key' => 'to_broadcaster_id', 'value' => $toBroadcasterId]; 194 | 195 | $queryParamsMap[] = ['key' => 'moderator_id', 'value' => $moderatorId]; 196 | 197 | return $this->postApi('chat/shoutouts', $bearer, $queryParamsMap); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/ChatApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_channel_emotes(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'chat/emotes', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 22 | $this->getChannelEmotes('TEST_TOKEN', '123')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_global_emotes(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'chat/emotes/global', 'TEST_TOKEN', [], [])->willReturn($request); 28 | $this->getGlobalEmotes('TEST_TOKEN')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_one_emote_set(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'chat/emotes/set', 'TEST_TOKEN', [['key' => 'emote_set_id', 'value' => '123']], [])->willReturn($request); 34 | $this->getEmoteSets('TEST_TOKEN', ['123'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_one_emote_set_with_helper_function(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'chat/emotes/set', 'TEST_TOKEN', [['key' => 'emote_set_id', 'value' => '123']], [])->willReturn($request); 40 | $this->getEmoteSet('TEST_TOKEN', '123')->shouldBe($response); 41 | } 42 | 43 | function it_should_get_multiple_emote_sets(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'chat/emotes/set', 'TEST_TOKEN', [['key' => 'emote_set_id', 'value' => '123'], ['key' => 'emote_set_id', 'value' => '456']], [])->willReturn($request); 46 | $this->getEmoteSets('TEST_TOKEN', ['123', '456'])->shouldBe($response); 47 | } 48 | 49 | function it_should_get_channel_chat_badges(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'chat/badges', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 52 | $this->getChannelChatBadges('TEST_TOKEN', '123')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_global_chat_badges(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'chat/badges/global', 'TEST_TOKEN', [], [])->willReturn($request); 58 | $this->getGlobalChatBadges('TEST_TOKEN')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_chat_settings(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'chat/settings', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 64 | $this->getChatSettings('TEST_TOKEN', '123')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_chat_settings_with_moderator_id(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'chat/settings', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [])->willReturn($request); 70 | $this->getChatSettings('TEST_TOKEN', '123', '456')->shouldBe($response); 71 | } 72 | 73 | function it_should_update_chat_settings_with_one_setting(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('PATCH', 'chat/settings', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [['key' => 'emote_mode', 'value' => true]])->willReturn($request); 76 | $this->updateChatSettings('TEST_TOKEN', '123', '456', ['emote_mode' => true])->shouldBe($response); 77 | } 78 | 79 | function it_should_update_chat_settings_with_multiple_settings(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('PATCH', 'chat/settings', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [['key' => 'emote_mode', 'value' => true], ['key' => 'slow_mode_wait_time', 'value' => 10]])->willReturn($request); 82 | $this->updateChatSettings('TEST_TOKEN', '123', '456', ['emote_mode' => true, 'slow_mode_wait_time' => 10])->shouldBe($response); 83 | } 84 | 85 | function it_should_send_a_chat_announcement(RequestGenerator $requestGenerator, Request $request, Response $response) 86 | { 87 | $requestGenerator->generate('POST', 'chat/announcements', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [['key' => 'message', 'value' => 'Hello World']])->willReturn($request); 88 | $this->sendChatAnnouncement('TEST_TOKEN', '123', '456', 'Hello World')->shouldBe($response); 89 | } 90 | 91 | function it_should_send_a_chat_announcement_with_a_color(RequestGenerator $requestGenerator, Request $request, Response $response) 92 | { 93 | $requestGenerator->generate('POST', 'chat/announcements', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [['key' => 'message', 'value' => 'Hello World'], ['key' => 'color', 'value' => 'red']])->willReturn($request); 94 | $this->sendChatAnnouncement('TEST_TOKEN', '123', '456', 'Hello World', 'red')->shouldBe($response); 95 | } 96 | 97 | function it_should_get_a_users_chat_color(RequestGenerator $requestGenerator, Request $request, Response $response) 98 | { 99 | $requestGenerator->generate('GET', 'chat/color', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123']], [])->willReturn($request); 100 | $this->getUserChatColor('TEST_TOKEN', '123')->shouldBe($response); 101 | } 102 | 103 | function it_should_update_a_users_chat_color(RequestGenerator $requestGenerator, Request $request, Response $response) 104 | { 105 | $requestGenerator->generate('PUT', 'chat/color', 'TEST_TOKEN', [['key' => 'user_id', 'value' => '123'], ['key' => 'color', 'value' => 'red']], [])->willReturn($request); 106 | $this->updateUserChatColor('TEST_TOKEN', '123', 'red')->shouldBe($response); 107 | } 108 | 109 | function it_should_get_chatters(RequestGenerator $requestGenerator, Request $request, Response $response) 110 | { 111 | $requestGenerator->generate('GET', 'chat/chatters', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456']], [])->willReturn($request); 112 | $this->getChatters('TEST_TOKEN', '123', '456')->shouldBe($response); 113 | } 114 | 115 | function it_should_get_chatters_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 116 | { 117 | $requestGenerator->generate('GET', 'chat/chatters', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'moderator_id', 'value' => '456'],['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 118 | $this->getChatters('TEST_TOKEN', '123', '456', 100, 'abc')->shouldBe($response); 119 | } 120 | 121 | function it_should_send_a_shoutout(RequestGenerator $requestGenerator, Request $request, Response $response) 122 | { 123 | $requestGenerator->generate('POST', 'chat/shoutouts', 'TEST_TOKEN', [['key' => 'from_broadcaster_id', 'value' => '123'], ['key' => 'to_broadcaster_id', 'value' => '456'], ['key' => 'moderator_id', 'value' => '789']], [])->willReturn($request); 124 | $this->sendShoutout('TEST_TOKEN', '123', '456', '789')->shouldBe($response); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/TwitchApi.php: -------------------------------------------------------------------------------- 1 | oauthApi = new OauthApi($clientId, $clientSecret, $authGuzzleClient); 74 | $this->adsApi = new AdsApi($helixGuzzleClient, $requestGenerator); 75 | $this->analyticsApi = new AnalyticsApi($helixGuzzleClient, $requestGenerator); 76 | $this->bitsApi = new BitsApi($helixGuzzleClient, $requestGenerator); 77 | $this->channelPointsApi = new ChannelPointsApi($helixGuzzleClient, $requestGenerator); 78 | $this->channelsApi = new ChannelsApi($helixGuzzleClient, $requestGenerator); 79 | $this->charityApi = new CharityApi($helixGuzzleClient, $requestGenerator); 80 | $this->chatApi = new ChatApi($helixGuzzleClient, $requestGenerator); 81 | $this->clipsApi = new ClipsApi($helixGuzzleClient, $requestGenerator); 82 | $this->entitlementsApi = new EntitlementsApi($helixGuzzleClient, $requestGenerator); 83 | $this->eventSubApi = new EventSubApi($helixGuzzleClient, $requestGenerator); 84 | $this->gamesApi = new GamesApi($helixGuzzleClient, $requestGenerator); 85 | $this->goalsApi = new GoalsApi($helixGuzzleClient, $requestGenerator); 86 | $this->hypeTrainApi = new HypeTrainApi($helixGuzzleClient, $requestGenerator); 87 | $this->moderationApi = new ModerationApi($helixGuzzleClient, $requestGenerator); 88 | $this->pollsApi = new PollsApi($helixGuzzleClient, $requestGenerator); 89 | $this->predictionsApi = new PredictionsApi($helixGuzzleClient, $requestGenerator); 90 | $this->raidsApi = new RaidsApi($helixGuzzleClient, $requestGenerator); 91 | $this->scheduleApi = new ScheduleApi($helixGuzzleClient, $requestGenerator); 92 | $this->searchApi = new SearchApi($helixGuzzleClient, $requestGenerator); 93 | $this->streamsApi = new StreamsApi($helixGuzzleClient, $requestGenerator); 94 | $this->subscriptionsApi = new SubscriptionsApi($helixGuzzleClient, $requestGenerator); 95 | $this->tagsApi = new TagsApi($helixGuzzleClient, $requestGenerator); 96 | $this->teamsApi = new TeamsApi($helixGuzzleClient, $requestGenerator); 97 | $this->usersApi = new UsersApi($helixGuzzleClient, $requestGenerator); 98 | $this->videosApi = new VideosApi($helixGuzzleClient, $requestGenerator); 99 | $this->webhooksApi = new WebhooksApi($helixGuzzleClient, $requestGenerator); 100 | $this->whispersApi = new WhispersApi($helixGuzzleClient, $requestGenerator); 101 | $this->webhooksSubscriptionApi = new WebhooksSubscriptionApi($clientId, $clientSecret, $helixGuzzleClient); 102 | } 103 | 104 | public function getOauthApi(): OauthApi 105 | { 106 | return $this->oauthApi; 107 | } 108 | 109 | public function getAdsApi(): AdsApi 110 | { 111 | return $this->adsApi; 112 | } 113 | 114 | public function getAnalyticsApi(): AnalyticsApi 115 | { 116 | return $this->analyticsApi; 117 | } 118 | 119 | public function getBitsApi(): BitsApi 120 | { 121 | return $this->bitsApi; 122 | } 123 | 124 | public function getChannelPointsApi(): ChannelPointsApi 125 | { 126 | return $this->channelPointsApi; 127 | } 128 | 129 | public function getChannelsApi(): ChannelsApi 130 | { 131 | return $this->channelsApi; 132 | } 133 | 134 | public function getCharityApi(): CharityApi 135 | { 136 | return $this->charityApi; 137 | } 138 | 139 | public function getChatApi(): ChatApi 140 | { 141 | return $this->chatApi; 142 | } 143 | 144 | public function getClipsApi(): ClipsApi 145 | { 146 | return $this->clipsApi; 147 | } 148 | 149 | public function getEntitlementsApi(): EntitlementsApi 150 | { 151 | return $this->entitlementsApi; 152 | } 153 | 154 | public function getEventSubApi(): EventSubApi 155 | { 156 | return $this->eventSubApi; 157 | } 158 | 159 | public function getGamesApi(): GamesApi 160 | { 161 | return $this->gamesApi; 162 | } 163 | 164 | public function getGoalsApi(): GoalsApi 165 | { 166 | return $this->goalsApi; 167 | } 168 | 169 | public function getHypeTrainApi(): HypeTrainApi 170 | { 171 | return $this->hypeTrainApi; 172 | } 173 | 174 | public function getModerationApi(): ModerationApi 175 | { 176 | return $this->moderationApi; 177 | } 178 | 179 | public function getPollsApi(): PollsApi 180 | { 181 | return $this->pollsApi; 182 | } 183 | 184 | public function getPredictionsApi(): PredictionsApi 185 | { 186 | return $this->predictionsApi; 187 | } 188 | 189 | public function getRaidsApi(): RaidsApi 190 | { 191 | return $this->raidsApi; 192 | } 193 | 194 | public function getScheduleApi(): ScheduleApi 195 | { 196 | return $this->scheduleApi; 197 | } 198 | 199 | public function getSearchApi(): SearchApi 200 | { 201 | return $this->searchApi; 202 | } 203 | 204 | public function getStreamsApi(): StreamsApi 205 | { 206 | return $this->streamsApi; 207 | } 208 | 209 | public function getSubscriptionsApi(): SubscriptionsApi 210 | { 211 | return $this->subscriptionsApi; 212 | } 213 | 214 | public function getTagsApi(): TagsApi 215 | { 216 | return $this->tagsApi; 217 | } 218 | 219 | public function getTeamsApi(): TeamsApi 220 | { 221 | return $this->teamsApi; 222 | } 223 | 224 | public function getUsersApi(): UsersApi 225 | { 226 | return $this->usersApi; 227 | } 228 | 229 | public function getVideosApi(): VideosApi 230 | { 231 | return $this->videosApi; 232 | } 233 | 234 | public function getWebhooksApi(): WebhooksApi 235 | { 236 | return $this->webhooksApi; 237 | } 238 | 239 | public function getWhispersApi(): WhispersApi 240 | { 241 | return $this->whispersApi; 242 | } 243 | 244 | public function getWebhooksSubscriptionApi(): WebhooksSubscriptionApi 245 | { 246 | return $this->webhooksSubscriptionApi; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /spec/TwitchApi/Resources/UsersApiSpec.php: -------------------------------------------------------------------------------- 1 | beConstructedWith($guzzleClient, $requestGenerator); 16 | $guzzleClient->send($request)->willReturn($response); 17 | } 18 | 19 | function it_should_get_user_with_access_token(RequestGenerator $requestGenerator, Request $request, Response $response) 20 | { 21 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [], [])->willReturn($request); 22 | $this->getUsers('TEST_TOKEN')->shouldBe($response); 23 | } 24 | 25 | function it_should_get_user_with_access_token_convenience_method(RequestGenerator $requestGenerator, Request $request, Response $response) 26 | { 27 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [], [])->willReturn($request); 28 | $this->getUserByAccessToken('TEST_TOKEN')->shouldBe($response); 29 | } 30 | 31 | function it_should_get_users_by_ids(RequestGenerator $requestGenerator, Request $request, Response $response) 32 | { 33 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [['key' => 'id', 'value' => '12345'], ['key' => 'id', 'value' => '98765']], [])->willReturn($request); 34 | $this->getUsers('TEST_TOKEN', ['12345', '98765'])->shouldBe($response); 35 | } 36 | 37 | function it_should_get_users_by_usernames(RequestGenerator $requestGenerator, Request $request, Response $response) 38 | { 39 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [['key' => 'login', 'value' => 'twitchuser'], ['key' => 'login', 'value' => 'anotheruser']], [])->willReturn($request); 40 | $this->getUsers('TEST_TOKEN', [], ['twitchuser', 'anotheruser'])->shouldBe($response); 41 | } 42 | 43 | function it_should_get_users_by_id_and_username(RequestGenerator $requestGenerator, Request $request, Response $response) 44 | { 45 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [['key' => 'id', 'value' => '12345'], ['key' => 'id', 'value' => '98765'], ['key' => 'login', 'value' => 'twitchuser'], ['key' => 'login', 'value' => 'anotheruser']], [])->willReturn($request); 46 | $this->getUsers('TEST_TOKEN', ['12345', '98765'], ['twitchuser', 'anotheruser'])->shouldBe($response); 47 | } 48 | 49 | function it_should_get_a_single_user_by_id(RequestGenerator $requestGenerator, Request $request, Response $response) 50 | { 51 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [['key' => 'id', 'value' => '12345']], [])->willReturn($request); 52 | $this->getUserById('TEST_TOKEN', '12345')->shouldBe($response); 53 | } 54 | 55 | function it_should_get_a_single_user_by_username(RequestGenerator $requestGenerator, Request $request, Response $response) 56 | { 57 | $requestGenerator->generate('GET', 'users', 'TEST_TOKEN', [['key' => 'login', 'value' => 'twitchuser']], [])->willReturn($request); 58 | $this->getUserByUsername('TEST_TOKEN', 'twitchuser')->shouldBe($response); 59 | } 60 | 61 | function it_should_get_users_follows_by_follower_id(RequestGenerator $requestGenerator, Request $request, Response $response) 62 | { 63 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'from_id', 'value' => '12345']], [])->willReturn($request); 64 | $this->getUsersFollows('TEST_TOKEN', '12345')->shouldBe($response); 65 | } 66 | 67 | function it_should_get_users_follows_by_followed_id(RequestGenerator $requestGenerator, Request $request, Response $response) 68 | { 69 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'to_id', 'value' => '12345']], [])->willReturn($request); 70 | $this->getUsersFollows('TEST_TOKEN', null, '12345')->shouldBe($response); 71 | } 72 | 73 | function it_should_get_users_follows_by_follower_id_and_followed_id(RequestGenerator $requestGenerator, Request $request, Response $response) 74 | { 75 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'from_id', 'value' => '12345'], ['key' => 'to_id', 'value' => '98765']], [])->willReturn($request); 76 | $this->getUsersFollows('TEST_TOKEN', '12345', '98765')->shouldBe($response); 77 | } 78 | 79 | function it_should_get_users_follows_page_by_first(RequestGenerator $requestGenerator, Request $request, Response $response) 80 | { 81 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'first', 'value' => 42]], [])->willReturn($request); 82 | $this->getUsersFollows('TEST_TOKEN', null, null, 42)->shouldBe($response); 83 | } 84 | 85 | function it_should_get_users_follows_page_by_after(RequestGenerator $requestGenerator, Request $request, Response $response) 86 | { 87 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'after', 'value' => '42']], [])->willReturn($request); 88 | $this->getUsersFollows('TEST_TOKEN', null, null, null, '42')->shouldBe($response); 89 | } 90 | 91 | function it_should_get_users_follows_by_everything(RequestGenerator $requestGenerator, Request $request, Response $response) 92 | { 93 | $requestGenerator->generate('GET', 'users/follows', 'TEST_TOKEN', [['key' => 'from_id', 'value' => '12345'], ['key' => 'to_id', 'value' => '98765'], ['key' => 'first', 'value' => 42], ['key' => 'after', 'value' => '99']], [])->willReturn($request); 94 | $this->getUsersFollows('TEST_TOKEN', '12345', '98765', 42, '99')->shouldBe($response); 95 | } 96 | 97 | function it_should_update_user(RequestGenerator $requestGenerator, Request $request, Response $response) 98 | { 99 | $requestGenerator->generate('PUT', 'users', 'TEST_TOKEN', [], [])->willReturn($request); 100 | $this->updateUser('TEST_TOKEN')->shouldBe($response); 101 | } 102 | 103 | function it_should_update_user_description(RequestGenerator $requestGenerator, Request $request, Response $response) 104 | { 105 | $requestGenerator->generate('PUT', 'users', 'TEST_TOKEN', [['key' => 'description', 'value' => 'test']], [])->willReturn($request); 106 | $this->updateUser('TEST_TOKEN', 'test')->shouldBe($response); 107 | } 108 | 109 | function it_should_get_user_block_list(RequestGenerator $requestGenerator, Request $request, Response $response) 110 | { 111 | $requestGenerator->generate('GET', 'users/blocks', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123']], [])->willReturn($request); 112 | $this->getUserBlockList('TEST_TOKEN', '123')->shouldBe($response); 113 | } 114 | 115 | function it_should_get_user_block_list_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 116 | { 117 | $requestGenerator->generate('GET', 'users/blocks', 'TEST_TOKEN', [['key' => 'broadcaster_id', 'value' => '123'], ['key' => 'first', 'value' => 100], ['key' => 'after', 'value' => 'abc']], [])->willReturn($request); 118 | $this->getUserBlockList('TEST_TOKEN', '123', 100, 'abc')->shouldBe($response); 119 | } 120 | 121 | function it_should_block_user(RequestGenerator $requestGenerator, Request $request, Response $response) 122 | { 123 | $requestGenerator->generate('PUT', 'users/blocks', 'TEST_TOKEN', [['key' => 'target_user_id', 'value' => '123']], [])->willReturn($request); 124 | $this->blockUser('TEST_TOKEN', '123')->shouldBe($response); 125 | } 126 | 127 | function it_should_block_user_with_opts(RequestGenerator $requestGenerator, Request $request, Response $response) 128 | { 129 | $requestGenerator->generate('PUT', 'users/blocks', 'TEST_TOKEN', [['key' => 'target_user_id', 'value' => '123'], ['key' => 'source_context', 'value' => 'chat'], ['key' => 'reason', 'value' => 'spam']], [])->willReturn($request); 130 | $this->blockUser('TEST_TOKEN', '123', 'chat', 'spam')->shouldBe($response); 131 | } 132 | 133 | function it_should_unblock_user(RequestGenerator $requestGenerator, Request $request, Response $response) 134 | { 135 | $requestGenerator->generate('DELETE', 'users/blocks', 'TEST_TOKEN', [['key' => 'target_user_id', 'value' => '123']], [])->willReturn($request); 136 | $this->unblockUser('TEST_TOKEN', '123')->shouldBe($response); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Twitch API PHP Library 2 | 3 | ![Packagist Version](https://img.shields.io/packagist/v/nicklaw5/twitch-api-php) 4 | ![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/nicklaw5/twitch-api-php) 5 | ![Packagist Downloads](https://img.shields.io/packagist/dt/nicklaw5/twitch-api-php) 6 | ![Packagist License](https://img.shields.io/packagist/l/nicklaw5/twitch-api-php) 7 | 8 | The Twitch API PHP Library allows you to interact through HTTP to a number of [Twitch API](https://dev.twitch.tv/docs/api/) endpoints. The library does not format the repsonses of your request so you have full flexability in how to handle the data that is returned from the API. 9 | 10 | ## Documentation & Links 11 | 12 | - [Twitch API Documentation](https://dev.twitch.tv/docs/api/) 13 | - [TwitchDev Discord](https://link.twitch.tv/devchat) 14 | - [Twitch API Community Discord](https://discord.gg/PKE8cPA3zb) 15 | 16 | ## Getting Started 17 | 18 | ### Requirements 19 | 20 | - PHP 7.4 - The library has been shown to work on earlier versions but we encourage you to use the latest versions of PHP that are tested with our library. - The requirement will be increased to PHP 8.0 in the future, so you should develop for the latest version of PHP. 21 | - Composer 22 | - `ext-json: *` 23 | - [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) `~6.0|~7.0` 24 | 25 | ### Installation 26 | 27 | The recommended way to install the Twitch API PHP Library is through [Composer](https://getcomposer.org/). 28 | 29 | ```bash 30 | composer require nicklaw5/twitch-api-php 31 | 32 | ``` 33 | 34 | ### Example Usage 35 | 36 | All calls to the Twitch API require bearer tokens that can be retrieved through the `OauthApi` class. You can review the [types of tokens](https://dev.twitch.tv/docs/authentication/#types-of-tokens) in the Twitch API docs. The below examples store the Client ID, Secret and Scopes directly in the example, but you should not do this. Store your IDs, Secret, and Scopes in a secure place such as your database or environment variables or alternate settings storage. Security of this information is important. Here is an example of how you can retrieve a token for your application: 37 | 38 | ```php 39 | $twitch_client_id = 'TWITCH_CLIENT_ID'; 40 | $twitch_client_secret = 'TWITCH_CLIENT_SECRET'; 41 | $twitch_scopes = ''; 42 | 43 | $helixGuzzleClient = new \TwitchApi\HelixGuzzleClient($twitch_client_id); 44 | $twitchApi = new \TwitchApi\TwitchApi($helixGuzzleClient, $twitch_client_id, $twitch_client_secret); 45 | $oauth = $twitchApi->getOauthApi(); 46 | 47 | try { 48 | $token = $oauth->getAppAccessToken($twitch_scopes ?? ''); 49 | $data = json_decode($token->getBody()->getContents()); 50 | 51 | // Your bearer token 52 | $twitch_access_token = $data->access_token ?? null; 53 | } catch (Exception $e) { 54 | //TODO: Handle Error 55 | } 56 | ``` 57 | 58 | Here is an example of how you retrieve a users token: 59 | 60 | ```php 61 | $twitch_client_id = 'TWITCH_CLIENT_ID'; 62 | $twitch_client_secret = 'TWITCH_CLIENT_SECRET'; 63 | $twitch_scopes = ''; 64 | 65 | $helixGuzzleClient = new \TwitchApi\HelixGuzzleClient($twitch_client_id); 66 | $twitchApi = new \TwitchApi\TwitchApi($helixGuzzleClient, $twitch_client_id, $twitch_client_secret); 67 | $oauth = $twitchApi->getOauthApi(); 68 | 69 | // Get the code from URI 70 | $code = $_GET['code']; 71 | 72 | // Get the current URL, we'll use this to redirect them back to exactly where they came from 73 | $currentUri = explode('?', 'https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])[0]; 74 | 75 | if ($code == '') { 76 | // Generate the Oauth Uri 77 | $oauthUri = $oauth->getAuthUrl($currentUri, 'code', $twitch_scopes); 78 | // Redirect them as there was no auth code 79 | header("Location: {$oauthUri}"); 80 | } else { 81 | try { 82 | $token = $oauth->getUserAccessToken($code, $currentUri); 83 | // It is a good practice to check the status code when they've responded, this really is optional though 84 | if ($token->getStatusCode() == 200) { 85 | // Below is the returned token data 86 | $data = json_decode($token->getBody()->getContents()); 87 | 88 | // Your bearer token 89 | $twitch_access_token = $data->access_token ?? null; 90 | } else { 91 | //TODO: Handle Error 92 | } 93 | } catch (Exception $e) { 94 | //TODO: Handle Error 95 | } 96 | } 97 | ``` 98 | 99 | When you have a user token that is expired, you're able to refresh it instead of requiring them to authenticate again. Here is an example of how you refresh a users token: 100 | 101 | ```php 102 | $twitch_client_id = 'TWITCH_CLIENT_ID'; 103 | $twitch_client_secret = 'TWITCH_CLIENT_SECRET'; 104 | $twitch_scopes = ''; 105 | $user_refresh_token = 'REFRESH_TOKEN'; 106 | 107 | $helixGuzzleClient = new \TwitchApi\HelixGuzzleClient($twitch_client_id); 108 | $twitchApi = new \TwitchApi\TwitchApi($helixGuzzleClient, $twitch_client_id, $twitch_client_secret); 109 | $oauth = $twitchApi->getOauthApi(); 110 | 111 | try { 112 | $token = $oauth->getAppAccessToken($twitch_scopes ?? ''); 113 | $data = json_decode($token->getBody()->getContents()); 114 | 115 | // Your bearer token 116 | $twitch_access_token = $data->access_token ?? null; 117 | 118 | // The scopes from the API 119 | $twitch_scopes = $data->scope; 120 | } catch (Exception $e) { 121 | //TODO: Handle Error 122 | } 123 | ``` 124 | 125 | ### Usage of the API Classes 126 | 127 | Everything stems from the `TwitchApi` class. However, if you want to individually instantiate `UsersApi`, `OauthApi`, etc. you are free to do so. 128 | 129 | The API calls generally return an object implementing `ResponseInterface`. Since you are getting the full `Response` object, you'll need to handle its contents, e.g. by decoding then into an object with `json_decode()`. This library does not assume this is what you want to do, so it does not do this for you automatically. This library simply acts as a middleman between your code and Twitch, providing you with the raw responses the Twitch API returns. 130 | 131 | The individual API classes that can be called from `TwitchApi` correspond to the [Twitch API documentation](https://dev.twitch.tv/docs/api/). The rest of the API classes are based on the resources listed [here](https://dev.twitch.tv/docs/api/reference/). The methods in the classes generally correspond to the endpoints for each resource. The naming convention was chosen to try and match the Twitch documentation. Each primary endpoint method (not convenience or helper methods) should have an `@link` annotation with a URL to that endpoint's specific documentation. 132 | 133 | Here is a sample of retrieving a users table from their access token: 134 | 135 | ```php 136 | $twitch_client_id = 'TWITCH_CLIENT_ID'; 137 | $twitch_client_secret = 'TWITCH_CLIENT_SECRET'; 138 | // Assuming you already have the access token - see above 139 | $twitch_access_token = 'the token'; 140 | 141 | // The Guzzle client used can be the included `HelixGuzzleClient` class, for convenience. 142 | // You can also use a mock, fake, or other double for testing, of course. 143 | $helixGuzzleClient = new \TwitchApi\HelixGuzzleClient($twitch_client_id); 144 | 145 | // Instantiate TwitchApi. Can be done in a service layer and injected as well. 146 | $twitchApi = new TwitchApi($helixGuzzleClient, $twitch_client_id, $twitch_client_secret); 147 | 148 | try { 149 | // Make the API call. A ResponseInterface object is returned. 150 | $response = $twitchApi->getUsersApi()->getUserByAccessToken($twitch_access_token); 151 | 152 | // Get and decode the actual content sent by Twitch. 153 | $responseContent = json_decode($response->getBody()->getContents()); 154 | 155 | // Return the first (or only) user. 156 | return $responseContent->data[0]; 157 | } catch (GuzzleException $e) { 158 | //TODO: Handle Error 159 | } 160 | ``` 161 | 162 | ## Developer Tools 163 | 164 | ### PHP Coding Standards Fixer 165 | 166 | [PHP Coding Standards Fixer](https://cs.sensiolabs.org/) (`php-cs-fixer`) has been added, specifically for the New Twitch API code. A configuration file for it can be found in `.php_cs.dist`. The ruleset is left at default (PSR-2 at this time). The configuration file mostly just limits it's scope to only the New Twitch API code. 167 | 168 | You can run the fixer with `vendor/bin/php-cs-fixer fix`. However, the easiest way to run the fixer is with the provided git hook. 169 | 170 | ### Git pre-commit Hook 171 | 172 | In `bin/git/hooks`, you'll find a `pre-commit` hook that you can add to git that will automatically run the `php-cs-fixer` everytime you commit. The result is that, after the commit is made, any changes that fixer has made are left as unstaged changes. You can review them, then add and commit them. 173 | 174 | To install the hook, go to `.git/hooks` and `ln -s ../../bin/git/hooks/pre-commit`. 175 | 176 | ## License 177 | 178 | Distributed under the [MIT](LICENSE) license. 179 | --------------------------------------------------------------------------------