Skip to content

Commit

Permalink
Updates to guzzle 7 and adds phpstan for static analysis (#21)
Browse files Browse the repository at this point in the history
* Updates to guzzle 7 and adds phpstan for static analysis

* Fixes test failures due to phpstan "fixes"
  • Loading branch information
mradcliffe committed Apr 22, 2023
1 parent d729a5d commit 1221dd8
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 159 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
strategy:
matrix:
php-versions: [7.3, 7.4, 8.0, 8.1]
php-versions: [8.0, 8.1, 8.2]
experimental: [false]
steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -45,5 +45,8 @@ jobs:
- name: Run code sniffer
run: vendor/bin/phpcs --report-summary --report-gitblame .

- name: Run code static analysis
run: vendor/bin/phpstan analyse src tests

- name: Run tests
run: vendor/bin/phpunit --coverage-text
8 changes: 5 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
}
},
"require": {
"php": "^7 || ^8",
"php": "^8",
"league/oauth2-client": "^2.4",
"guzzlehttp/oauth-subscriber": "^0.3.0",
"ext-json": "*"
},
"require-dev": {
"ext-openssl": "*",
"phpunit/phpunit": "^8 || ^9",
"squizlabs/php_codesniffer": "~3.5",
"phpspec/prophecy-phpunit": "^2.0"
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/phpstan": "^1.10",
"squizlabs/php_codesniffer": "~3.5"
}
}
18 changes: 18 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
parameters:
level: 6
excludePaths:
- .github/
- coverage/
- vendor/
- tests/stubs
- tests/fixtures
ignoreErrors:
- '#Unsafe usage of new static\(\)#'
-
message: '#Call to an undefined method (PHPUnit|Prophecy)*#'
path: 'tests/src/*'
stubFiles:
- tests/stubs/AbstractProvider.stub
- tests/stubs/AccessToken.stub
- tests/stubs/ResourceOwnerInterface.stub
- tests/stubs/ResponseInterface.stub
26 changes: 14 additions & 12 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="Xero Client Test Suite">
<directory>tests</directory>
<exclude>vendor</exclude>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="tests/bootstrap.php"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory>src</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Xero Client Test Suite">
<directory>tests</directory>
<exclude>vendor</exclude>
</testsuite>
</testsuites>
</phpunit>
81 changes: 46 additions & 35 deletions src/XeroClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Radcliffe\Xero;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Subscriber\Oauth\Oauth1;
use League\OAuth2\Client\Token\AccessTokenInterface;
use Radcliffe\Xero\Exception\InvalidOptionsException;

class XeroClient extends Client implements XeroClientInterface
Expand All @@ -14,17 +16,17 @@ class XeroClient extends Client implements XeroClientInterface
*
* @var string[]
*/
protected $tenantIds = [];
protected array $tenantIds = [];

/**
* @var
* @var \League\OAuth2\Client\Token\AccessTokenInterface|null
*/
protected $refreshedToken = null;
protected ?AccessTokenInterface $refreshedToken = null;

/**
* {@inheritdoc}
*/
public static function getValidUrls()
public static function getValidUrls(): array
{
return [
'https://identity.xero.com/connect/token',
Expand All @@ -37,12 +39,18 @@ public static function getValidUrls()
}

/**
* {@inheritdoc}
* Initialization method.
*
* @param array<string,mixed> $config
* The guzzle options.
*
* @throws \Radcliffe\Xero\Exception\InvalidOptionsException
* @see \GuzzleHttp\Client::__construct().
*/
public function __construct(array $config)
public function __construct(array $config = [])
{
$options = isset($config['options']) ? $config['options'] : [];
$scheme = isset($config['scheme']) ? $config['scheme'] : 'oauth1';
$options = $config['options'] ?? [];
$scheme = $config['scheme'] ?? 'oauth1';
$auth = $scheme === 'oauth1' ? 'oauth' : null;

if (!isset($config['base_uri']) ||
Expand Down Expand Up @@ -114,15 +122,16 @@ public function __construct(array $config)
/**
* {@inheritdoc}
*/
public function isValidUrl($base_uri)
public function isValidUrl($base_uri): bool
{
return in_array($base_uri, $this->getValidUrls()) || strpos($base_uri, 'https://api.xero.com/oauth') === 0;
return in_array($base_uri, $this->getValidUrls()) ||
str_starts_with($base_uri, 'https://api.xero.com/oauth');
}

/**
* {@inheritdoc}
*/
public function isValidPrivateKey($filename)
public function isValidPrivateKey($filename): bool
{
if ($filename && realpath($filename) && !is_dir($filename) && is_readable($filename)) {
return true;
Expand All @@ -131,15 +140,15 @@ public function isValidPrivateKey($filename)
}

/**
* @param array $options
* @param array<string,mixed> $options
* The options passed into the constructor.
*
* @return \GuzzleHttp\Subscriber\Oauth\Oauth1
* OAuth1 middleware.
*
* @deprecated Deprecated since 0.2.0.
*/
protected function getPublicApplicationMiddleware($options)
protected function getPublicApplicationMiddleware(array $options): Oauth1
{
$oauth_options = [
'consumer_key' => $options['consumer_key'],
Expand All @@ -166,15 +175,15 @@ protected function getPublicApplicationMiddleware($options)
}

/**
* @param array $options
* @param array<string,mixed> $options
* The options passed into the constructor.
*
* @return \GuzzleHttp\Subscriber\Oauth\Oauth1
* OAuth1 middleware.
*
* @deprecated Deprecated since 0.2.0
*/
protected function getPrivateApplicationMiddleware($options)
protected function getPrivateApplicationMiddleware(array $options): Oauth1
{
return new Oauth1([
'consumer_key' => $options['consumer_key'],
Expand All @@ -189,8 +198,10 @@ protected function getPrivateApplicationMiddleware($options)

/**
* {@inheritdoc}
*
* @throws \Radcliffe\Xero\Exception\InvalidOptionsException
*/
public static function getRequestToken($consumer_key, $consumer_secret, $options = [])
public static function getRequestToken(string $consumer_key, string $consumer_secret, array $options = []): array
{
$config = [
'base_uri' => 'https://api.xero.com/oauth/',
Expand All @@ -201,7 +212,6 @@ public static function getRequestToken($consumer_key, $consumer_secret, $options
$client = new static($config);

$tokens = [];
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = $client->post('/RequestToken');
$pairs = explode('&', $response->getBody()->getContents());
foreach ($pairs as $pair) {
Expand All @@ -214,15 +224,17 @@ public static function getRequestToken($consumer_key, $consumer_secret, $options

/**
* {@inheritdoc}
*
* @throws \Radcliffe\Xero\Exception\InvalidOptionsException
*/
public static function getAccessToken(
$consumer_key,
$consumer_secret,
$token,
$token_secret,
$verifier,
$options = []
) {
string $consumer_key,
string $consumer_secret,
string $token,
string $token_secret,
string $verifier,
array $options = []
): array {
$config = [
'base_uri' => 'https://api.xero.com/oauth/',
'consumer_key' => $consumer_key,
Expand All @@ -236,7 +248,6 @@ public static function getAccessToken(
$client = new static($config);

$tokens = [];
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = $client->post('/AccessToken');
$pairs = explode('&', $response->getBody()->getContents());
foreach ($pairs as $pair) {
Expand All @@ -250,7 +261,7 @@ public static function getAccessToken(
/**
* {@inheritdoc}
*/
public function getConnections()
public function getConnections(): array
{
try {
$response = $this->get('https://api.xero.com/connections', ['Content-Type' => 'application/json']);
Expand All @@ -271,15 +282,15 @@ public function getConnections()
* @throws \GuzzleHttp\Exception\ClientException
*/
public static function createFromToken(
$id,
$secret,
$token,
$grant = null,
$api = 'accounting',
string $id,
string $secret,
string $token,
string $grant = null,
string $api = 'accounting',
array $options = [],
array $collaborators = [],
$redirectUri = ''
) {
string $redirectUri = ''
): static {
if ($grant !== null) {
// Fetch a new access token from a refresh token.
$provider = new XeroProvider([
Expand Down Expand Up @@ -324,7 +335,7 @@ public static function createFromToken(
*
* @return \League\OAuth2\Client\Token\AccessTokenInterface|null
*/
public function getRefreshedToken()
public function getRefreshedToken(): ?AccessTokenInterface
{
return $this->refreshedToken;
}
Expand All @@ -334,7 +345,7 @@ public function getRefreshedToken()
*
* @return string[]
*/
public function getTenantIds()
public function getTenantIds(): array
{
return $this->tenantIds;
}
Expand Down

0 comments on commit 1221dd8

Please sign in to comment.