diff --git a/.gitattributes b/.gitattributes index cfad1e0..bdc74d0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,11 +2,10 @@ # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html # Ignore all test and documentation with "export-ignore". -/.github export-ignore -/tests export-ignore -/.editorconfig export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.php_cs.dist export-ignore -/.php_cs.dist export-ignore -/phpunit.xml.dist export-ignore +/.github export-ignore +/tests export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.php-cs-fixer.dist.php export-ignore +/phpunit.xml.dist export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75108e4..d81e0bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,31 +14,33 @@ jobs: strategy: fail-fast: false matrix: - php-version: [ '7.4', '8.0' ] + php-version: [ '8.1', '8.2' ] allow-failure: [ false ] coverage: [ false ] composer-flags: [ '' ] include: - - php-version: '7.3' - coverage: true - php-version: '8.1' + coverage: true + - php-version: '8.2' allow-failure: true composer-flags: '--ignore-platform-req php' steps: - - uses: actions/checkout@v2 + - name: checkout + uses: actions/checkout@v3 - name: php-setup uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} + coverage: xdebug - name: composer-validate run: composer validate - name: composer-cache id: composer-cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: vendor key: ${{ runner.os }}-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.lock') }} @@ -53,14 +55,16 @@ jobs: continue-on-error: ${{ matrix.allow-failure }} env: PHP_CS_FIXER_IGNORE_ENV: ${{ matrix.allow-failure }} - run: vendor/bin/php-cs-fixer fix --dry-run --diff --verbose --config=.php_cs.dist + run: vendor/bin/php-cs-fixer fix --dry-run --diff --verbose - name: phpunit + env: + XDEBUG_MODE: coverage run: composer run-script phpunit - name: coverage if: ${{ matrix.coverage }} - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} directory: ./build diff --git a/.gitignore b/.gitignore index ba9bc44..bfbafb6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -build/ -vendor/ +/build/ +/vendor/ composer.lock -.php_cs -.php_cs.cache +.php-cs-fixer.cache .phpunit.result.cache phpunit.xml diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..4e54172 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,15 @@ +in(__DIR__) +; + +return (new PhpCsFixer\Config()) + ->setRules([ + '@Symfony' => true, + '@Symfony:risky' => true, + 'declare_strict_types' => true, + ]) + ->setRiskyAllowed(true) + ->setFinder($finder) +; diff --git a/.php_cs.dist b/.php_cs.dist deleted file mode 100644 index e65f99b..0000000 --- a/.php_cs.dist +++ /dev/null @@ -1,37 +0,0 @@ -in(__DIR__ . '/src') - ->in(__DIR__ . '/tests') -; - -return PhpCsFixer\Config::create() - ->setRiskyAllowed(true) - ->setRules([ - '@Symfony' => true, - '@PHP71Migration' => true, - 'binary_operator_spaces' => array( - 'align_equals' => false, - 'align_double_arrow' => false, - ), - '@Symfony:risky' => true, - '@PHP71Migration:risky' => true, - 'array_syntax' => ['syntax' => 'short'], - 'linebreak_after_opening_tag' => true, - 'mb_str_functions' => true, - 'no_php4_constructor' => true, - 'no_unreachable_default_argument_value' => true, - 'no_useless_else' => true, - 'no_useless_return' => true, - 'ordered_imports' => true, - 'php_unit_strict' => true, - 'phpdoc_order' => true, - 'semicolon_after_instruction' => true, - 'strict_comparison' => true, - 'strict_param' => true, - 'concat_space' => ['spacing' => 'one'], - 'trailing_comma_in_multiline_array' => true, - 'yoda_style' => false - ]) - ->setFinder($finder) - ->setCacheFile(__DIR__.'/.php_cs.cache'); diff --git a/README.md b/README.md index 2c9101d..896f150 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Coverage - PHP Version + PHP Version Downloads @@ -52,7 +52,7 @@ if (!isset($_GET['code'])) { // If we don't have an authorization code then get one $authUrl = $provider->getAuthorizationUrl([ 'scope' => [ - Kerox\OAuth2\Client\Provider\Spotify::SCOPE_USER_READ_EMAIL, + Kerox\OAuth2\Client\Provider\SpotifyScope::USER_READ_EMAIL->value, ] ]); @@ -108,26 +108,35 @@ echo ''; ### Authorization Scopes -All scopes described in the [official documentation](https://developer.spotify.com/documentation/general/guides/scopes/) are available through public constants in `\Kerox\OAuth2\Client\Provider\Spotify`: - -* SCOPE_UGC_IMAGE_UPLOAD -* SCOPE_USER_MODIFY_PLAYBACK_STATE -* SCOPE_USER_READ_PLAYBACK_STATE -* SCOPE_USER_READ_CURRENTLY_PLAYING -* SCOPE_USER_TOP_READ -* SCOPE_USER_READ_RECENTLY_PLAYED -* SCOPE_USER_LIBRARY_MODIFY -* SCOPE_USER_LIBRARY_READ -* SCOPE_USER_FOLLOW_MODIFY -* SCOPE_USER_FOLLOW_READ -* SCOPE_PLAYLIST_READ_PRIVATE -* SCOPE_PLAYLIST_MODIFY_PUBLIC -* SCOPE_PLAYLIST_MODIFY_PRIVATE -* SCOPE_PLAYLIST_READ_COLLABORATIVE -* SCOPE_USER_READ_PRIVATE -* SCOPE_USER_READ_EMAIL -* SCOPE_APP_REMOTE_CONTROL -* SCOPE_STREAMING +All scopes described in the [official documentation](https://developer.spotify.com/documentation/general/guides/authorization/scopes/) are available through the `\Kerox\OAuth2\Client\Provider\SpotifyScope` enumeration: + +- Images + * UGC_IMAGE_UPLOAD +- Spotify Connect + * USER_READ_PLAYBACK_STATE + * USER_MODIFY_PLAYBACK_STATE + * USER_READ_CURRENTLY_PLAYING +- Playback + * APP_REMOTE_CONTROL + * STREAMING +- Playlists + * PLAYLIST_READ_PRIVATE + * PLAYLIST_READ_COLLABORATIVE + * PLAYLIST_MODIFY_PRIVATE + * PLAYLIST_MODIFY_PUBLIC +- Follow + * USER_FOLLOW_MODIFY + * USER_FOLLOW_READ +- Listening History + * USER_READ_PLAYBACK_POSITION + * USER_TOP_READ + * USER_READ_RECENTLY_PLAYED +- Library + * USER_LIBRARY_MODIFY + * USER_LIBRARY_READ +- Users + * USER_READ_PRIVATE + * USER_READ_EMAIL ## Contributing diff --git a/composer.json b/composer.json index d9f2b5d..3722db4 100644 --- a/composer.json +++ b/composer.json @@ -21,12 +21,12 @@ } ], "require": { - "php": ">=7.3", + "php": ">=8.1", "league/oauth2-client": "^2.6" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.17", - "phpunit/phpunit": "^9.0" + "friendsofphp/php-cs-fixer": "^3.0", + "phpunit/phpunit": "^9.5" }, "config": { "optimize-autoloader": true, @@ -43,7 +43,7 @@ } }, "scripts": { - "php-cs-fixer": "vendor/bin/php-cs-fixer fix --diff --verbose --config=.php_cs", + "php-cs-fixer": "vendor/bin/php-cs-fixer fix --diff --verbose", "phpunit": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml" } } diff --git a/src/Provider/Spotify.php b/src/Provider/Spotify.php index 1cdd629..1014dbd 100644 --- a/src/Provider/Spotify.php +++ b/src/Provider/Spotify.php @@ -19,45 +19,9 @@ class Spotify extends AbstractProvider public const BASE_SPOTIFY_URL = 'https://accounts.spotify.com/'; public const RESPONSE_TYPE = 'code'; - // Available scopes. - - // Images - public const SCOPE_UGC_IMAGE_UPLOAD = 'ugc-image-upload'; - - // Spotify Connect - public const SCOPE_USER_MODIFY_PLAYBACK_STATE = 'user-modify-playback-state'; - public const SCOPE_USER_READ_PLAYBACK_STATE = 'user-read-playback-state'; - public const SCOPE_USER_READ_CURRENTLY_PLAYING = 'user-read-currently-playing'; - - // Listening History - public const SCOPE_USER_TOP_READ = 'user-top-read'; - public const SCOPE_USER_READ_RECENTLY_PLAYED = 'user-read-recently-played'; - - // Library - public const SCOPE_USER_LIBRARY_MODIFY = 'user-library-modify'; - public const SCOPE_USER_LIBRARY_READ = 'user-library-read'; - - // Follow - public const SCOPE_USER_FOLLOW_MODIFY = 'user-follow-modify'; - public const SCOPE_USER_FOLLOW_READ = 'user-follow-read'; - - // Playlist - public const SCOPE_PLAYLIST_READ_PRIVATE = 'playlist-read-private'; - public const SCOPE_PLAYLIST_MODIFY_PUBLIC = 'playlist-modify-public'; - public const SCOPE_PLAYLIST_MODIFY_PRIVATE = 'playlist-modify-private'; - public const SCOPE_PLAYLIST_READ_COLLABORATIVE = 'playlist-read-collaborative'; - - // User - public const SCOPE_USER_READ_PRIVATE = 'user-read-private'; - public const SCOPE_USER_READ_EMAIL = 'user-read-email'; - - // Playback - public const SCOPE_APP_REMOTE_CONTROL = 'app-remote-control'; - public const SCOPE_STREAMING = 'streaming'; - public function __construct(array $options = [], array $collaborators = []) { - if (!isset($options['responseType']) || $options['responseType'] !== self::RESPONSE_TYPE) { + if (!isset($options['responseType']) || self::RESPONSE_TYPE !== $options['responseType']) { $options['responseType'] = self::RESPONSE_TYPE; } @@ -69,7 +33,7 @@ public function __construct(array $options = [], array $collaborators = []) */ public function getBaseAuthorizationUrl(): string { - return self::BASE_SPOTIFY_URL . 'authorize'; + return self::BASE_SPOTIFY_URL.'authorize'; } /** @@ -77,7 +41,7 @@ public function getBaseAuthorizationUrl(): string */ public function getBaseAccessTokenUrl(array $params): string { - return self::BASE_SPOTIFY_URL . 'api/token'; + return self::BASE_SPOTIFY_URL.'api/token'; } /** diff --git a/src/Provider/SpotifyResourceOwner.php b/src/Provider/SpotifyResourceOwner.php index 7a07db9..ad818c1 100644 --- a/src/Provider/SpotifyResourceOwner.php +++ b/src/Provider/SpotifyResourceOwner.php @@ -8,10 +8,7 @@ class SpotifyResourceOwner implements ResourceOwnerInterface { - /** - * @var array - */ - protected $data; + protected array $data; public function __construct(array $response) { @@ -79,7 +76,7 @@ public function getUri(): string } /** - * Return all of the owner details available as an array. + * Return all the owner details available as an array. */ public function toArray(): array { diff --git a/src/Provider/SpotifyScope.php b/src/Provider/SpotifyScope.php new file mode 100644 index 0000000..67634aa --- /dev/null +++ b/src/Provider/SpotifyScope.php @@ -0,0 +1,43 @@ +resourceOwner = new SpotifyResourceOwner($user); } @@ -45,7 +42,7 @@ public function testGetter(): void public function testToArray(): void { - $array = json_decode(file_get_contents(__DIR__ . '/../Mocks/user.json'), true, 512, \JSON_THROW_ON_ERROR); + $array = json_decode(file_get_contents(__DIR__.'/../Mocks/user.json'), true, 512, \JSON_THROW_ON_ERROR); self::assertSame($array, $this->resourceOwner->toArray()); } diff --git a/tests/Provider/SpotifyTest.php b/tests/Provider/SpotifyTest.php index 05c19c3..70f4c2f 100644 --- a/tests/Provider/SpotifyTest.php +++ b/tests/Provider/SpotifyTest.php @@ -15,16 +15,13 @@ class FooSpotifyProvider extends Spotify { protected function fetchResourceOwnerDetails(AccessToken $token) { - return json_decode(file_get_contents(__DIR__ . '/../Mocks/user.json'), true, 512, \JSON_THROW_ON_ERROR); + return json_decode(file_get_contents(__DIR__.'/../Mocks/user.json'), true, 512, \JSON_THROW_ON_ERROR); } } class SpotifyTest extends TestCase { - /** - * @var \Kerox\OAuth2\Client\Provider\Spotify - */ - protected $provider; + protected Spotify $provider; protected function setUp(): void { @@ -161,12 +158,7 @@ public function testCheckResponseFailureWithRegularError(): void $this->callMethod('checkResponse', [$response, $data]); } - /** - * @param $name - * - * @return mixed|null - */ - protected function callMethod($name, array $args = []) + protected function callMethod(string $name, array $args = []): mixed { try { $reflection = new \ReflectionMethod(\get_class($this->provider), $name);