Code clean up with declare strict and php stan level 9 checks

add "declare(strict_types=1);" to all pages

Add a json handler class to handle that json_decode always returns array<mixed> and throws error otherwise
On failure these will throw the normal JSON encoded error was FAILURE with code "J-" and the number is the json error
If 0 then the return was null or some other problem that did not return an array

amount is float and not string and checks are done that the returned value is a float

various updates for phpdoc array delcarations
- curl header is array<int, string>
- the log array is proper declared as array with string key and a list of mixed arrays
This commit is contained in:
2025-01-21 10:48:41 +09:00
parent a565d2899b
commit 28a9e390cc
16 changed files with 115 additions and 36 deletions

View File

@@ -26,6 +26,7 @@
// use Phan\Config; // use Phan\Config;
return [ return [
"minimum_target_php_version" => "7.4",
// If true, missing properties will be created when // If true, missing properties will be created when
// they are first seen. If false, we'll report an // they are first seen. If false, we'll report an
// error message. // error message.
@@ -65,7 +66,7 @@ return [
'directory_list' => [ 'directory_list' => [
// Change this to include the folders you wish to analyze // Change this to include the folders you wish to analyze
// (and the folders of their dependencies) // (and the folders of their dependencies)
'.' 'src/'
// 'www', // 'www',
// To speed up analysis, we recommend going back later and // To speed up analysis, we recommend going back later and
// limiting this to only the vendor/ subdirectories your // limiting this to only the vendor/ subdirectories your

View File

@@ -2,7 +2,7 @@
parameters: parameters:
tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-amazon-incentives tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-amazon-incentives
level: 8 level: 9
paths: paths:
- %currentWorkingDirectory%/src - %currentWorkingDirectory%/src
excludePaths: excludePaths:

View File

@@ -1,6 +1,6 @@
<phpunit <phpunit
colors="true" colors="true"
verbose="true" verbose="false"
> >
<!-- Below removes final from classes for mock tests --> <!-- Below removes final from classes for mock tests -->
<extensions> <extensions>

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\AWS; namespace gullevek\AmazonIncentives\AWS;
use gullevek\AmazonIncentives\Client\Client; use gullevek\AmazonIncentives\Client\Client;
@@ -9,6 +11,7 @@ use gullevek\AmazonIncentives\Debug\AmazonDebug;
use gullevek\AmazonIncentives\Response\CancelResponse; use gullevek\AmazonIncentives\Response\CancelResponse;
use gullevek\AmazonIncentives\Response\CreateBalanceResponse; use gullevek\AmazonIncentives\Response\CreateBalanceResponse;
use gullevek\AmazonIncentives\Response\CreateResponse; use gullevek\AmazonIncentives\Response\CreateResponse;
use gullevek\AmazonIncentives\Handle\Json;
class AWS class AWS
{ {
@@ -72,12 +75,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CreateResponse($result); return new CreateResponse($result);
} }
@@ -97,12 +100,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CancelResponse($result); return new CancelResponse($result);
} }
@@ -120,12 +123,12 @@ class AWS
$canonical_request = $this->getCanonicalRequest($service_operation, $payload); $canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp(); $date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]); AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest( $result = Json::jsonDecode($this->makeRequest(
$payload, $payload,
$canonical_request, $canonical_request,
$service_operation, $service_operation,
$date_time_string $date_time_string
), true); ));
return new CreateBalanceResponse($result); return new CreateBalanceResponse($result);
} }
@@ -212,7 +215,7 @@ class AWS
* @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp() * @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp()
* @param string $service_target Target service in the agcod string: * @param string $service_target Target service in the agcod string:
* Value like com.amazonaws.agcod.<sn>.<so> * Value like com.amazonaws.agcod.<sn>.<so>
* @return array<mixed> Header data as array for curl request * @return array<int,string> Header data as array for curl request
*/ */
public function buildHeaders( public function buildHeaders(
string $payload, string $payload,

View File

@@ -30,12 +30,12 @@ final class AmazonIncentives
* @param bool|null $debug Debug flag * @param bool|null $debug Debug flag
*/ */
public function __construct( public function __construct(
string $key = null, ?string $key = null,
string $secret = null, ?string $secret = null,
string $partner = null, ?string $partner = null,
string $endpoint = null, ?string $endpoint = null,
string $currency = null, ?string $currency = null,
bool $debug = null ?bool $debug = null
) { ) {
// load AWS settings // load AWS settings
// fail here if settings missing // fail here if settings missing
@@ -65,7 +65,7 @@ final class AmazonIncentives
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse public function buyGiftCard(float $value, ?string $creation_request_id = null): Response\CreateResponse
{ {
return ($this->newAWS())->getCode($value, $creation_request_id); return ($this->newAWS())->getCode($value, $creation_request_id);
} }
@@ -109,12 +109,12 @@ final class AmazonIncentives
* @return AmazonIncentives self class * @return AmazonIncentives self class
*/ */
public static function make( public static function make(
string $key = null, ?string $key = null,
string $secret = null, ?string $secret = null,
string $partner = null, ?string $partner = null,
string $endpoint = null, ?string $endpoint = null,
string $currency = null, ?string $currency = null,
bool $debug = null ?bool $debug = null
): AmazonIncentives { ): AmazonIncentives {
return new static($key, $secret, $partner, $endpoint, $currency, $debug); return new static($key, $secret, $partner, $endpoint, $currency, $debug);
} }

View File

@@ -1,9 +1,12 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Client; namespace gullevek\AmazonIncentives\Client;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors; use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
use gullevek\AmazonIncentives\Handle\Json;
class Client implements ClientInterface class Client implements ClientInterface
{ {
@@ -16,7 +19,7 @@ class Client implements ClientInterface
* *
* @param string $url The URL being requested, * @param string $url The URL being requested,
* including domain and protocol * including domain and protocol
* @param array<mixed> $headers Headers to be used in the request * @param array<int,string> $headers Headers to be used in the request
* @param array<mixed>|string $params Can be nested for arrays and hashes * @param array<mixed>|string $params Can be nested for arrays and hashes
* @return string Result as json string * @return string Result as json string
*/ */
@@ -50,7 +53,12 @@ class Client implements ClientInterface
$err = curl_errno($handle); $err = curl_errno($handle);
AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]); AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]);
// extract all the error codes from Amazon // extract all the error codes from Amazon
$result_ar = json_decode((string)$result, true); // note we do not care about result errors here, if json decode fails, just set to empty
try {
$result_ar = Json::jsonDecode((string)$result);
} catch (AmazonErrors $e) {
$result_ar = [];
}
// if message is 'Rate exceeded', set different error // if message is 'Rate exceeded', set different error
if (($result_ar['message'] ?? '') == 'Rate exceeded') { if (($result_ar['message'] ?? '') == 'Rate exceeded') {
$error_status = 'RESEND'; $error_status = 'RESEND';

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Client; namespace gullevek\AmazonIncentives\Client;
interface ClientInterface interface ClientInterface

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Config; namespace gullevek\AmazonIncentives\Config;
class Config implements ConfigInterface class Config implements ConfigInterface
@@ -85,7 +87,8 @@ class Config implements ConfigInterface
case 'AWS_GIFT_CARD_PARTNER_ID': case 'AWS_GIFT_CARD_PARTNER_ID':
case 'AWS_GIFT_CARD_ENDPOINT': case 'AWS_GIFT_CARD_ENDPOINT':
case 'AWS_GIFT_CARD_CURRENCY': case 'AWS_GIFT_CARD_CURRENCY':
$return = (string)($_ENV[$key] ?? ''); $return = !empty($_ENV[$key]) && is_string($_ENV[$key]) ?
$_ENV[$key] : '';
break; break;
default: default:
break; break;

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Config; namespace gullevek\AmazonIncentives\Config;
interface ConfigInterface interface ConfigInterface

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
// simple write all into an array that we can poll in the return group // simple write all into an array that we can poll in the return group
// to activate AmazonDebug::setDebug(true) must be called once // to activate AmazonDebug::setDebug(true) must be called once
@@ -7,7 +9,7 @@ namespace gullevek\AmazonIncentives\Debug;
class AmazonDebug class AmazonDebug
{ {
/** @var array<mixed> Log data array log id -> array of log entries */ /** @var array<string,array<array<mixed>>> Log data array log id -> array of log entries */
private static $log = []; private static $log = [];
/** @var bool debug flag */ /** @var bool debug flag */
private static $debug = false; private static $debug = false;

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Exceptions; namespace gullevek\AmazonIncentives\Exceptions;
use RuntimeException; use RuntimeException;
@@ -52,7 +54,7 @@ final class AmazonErrors extends RuntimeException
{ {
$message_ar = json_decode($message, true); $message_ar = json_decode($message, true);
// if we have an error, build empty block and only fill message // if we have an error, build empty block and only fill message
if (json_last_error()) { if (json_last_error() || $message_ar === null || !is_array($message_ar)) {
$message_ar = [ $message_ar = [
'status' => '', 'status' => '',
'code' => '', 'code' => '',

42
src/Handle/Json.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
/**
* Handle json conversions
*/
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Handle;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
class Json
{
/**
* decode json string
*
* @param string $json
* @return array<mixed>
* @throws AmazonErrors
*/
public static function jsonDecode(string $json): array
{
$result = json_decode($json, true);
if (
($json_last_error = json_last_error()) ||
$result === null ||
!is_array($result)
) {
throw AmazonErrors::getError(
'FAILURE',
'J-' . $json_last_error,
'jsonDecoreError',
'Failed to decode json data',
0
);
}
return $result;
}
}
// __END__

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;

View File

@@ -1,13 +1,15 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class CreateBalanceResponse class CreateBalanceResponse
{ {
/** @var string Amazon Gift Card Balance Amount */ /** @var float Amazon Gift Card Balance Amount */
protected $amount = ''; protected $amount = 0;
/** @var string Amazon Gift Card Balance Currency */ /** @var string Amazon Gift Card Balance Currency */
protected $currency = ''; protected $currency = '';
/** @var string Amazon Gift Card Balance Status */ /** @var string Amazon Gift Card Balance Status */
@@ -41,9 +43,9 @@ class CreateBalanceResponse
/** /**
* Return the current available funds amount * Return the current available funds amount
* *
* @return string Funds amount in set currency * @return float Funds amount in set currency
*/ */
public function getAmount(): string public function getAmount(): float
{ {
return $this->amount; return $this->amount;
} }
@@ -98,10 +100,18 @@ class CreateBalanceResponse
*/ */
public function parseJsonResponse(array $json_response): self public function parseJsonResponse(array $json_response): self
{ {
if (array_key_exists('amount', $json_response['availableFunds'])) { if (
$this->amount = $json_response['availableFunds']['amount']; is_array($json_response['availableFunds']) &&
array_key_exists('amount', $json_response['availableFunds']) &&
is_numeric($json_response['availableFunds']['amount'])
) {
$this->amount = (float)$json_response['availableFunds']['amount'];
} }
if (array_key_exists('currencyCode', $json_response['availableFunds'])) { if (
is_array($json_response['availableFunds']) &&
array_key_exists('currencyCode', $json_response['availableFunds']) &&
is_string($json_response['availableFunds']['currencyCode'])
) {
$this->currency = $json_response['availableFunds']['currencyCode']; $this->currency = $json_response['availableFunds']['currencyCode'];
} }
// SUCCESS, FAILURE, RESEND // SUCCESS, FAILURE, RESEND

View File

@@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;

View File

@@ -351,7 +351,7 @@ final class AmazonIncentivesTest extends TestCase
// numeric number // numeric number
$this->assertIsNumeric( $this->assertIsNumeric(
$funds->getAmount(), $funds->getAmount(),
'Assert amoount is numerc' 'Assert amoount is numeric'
); );
// USD, JPY, etc // USD, JPY, etc
$this->assertIsString( $this->assertIsString(