40 Commits

Author SHA1 Message Date
6f5cd028b9 Minor fix for return type alignment
make sure string returned is set to string in config getter
2023-01-06 10:36:24 +09:00
3634c5bdfa Merge pull request #2 from kapierstau/fix/eu-region-for-eu-endpoint 2022-08-18 10:22:22 +09:00
kapierstau.io
37b4cbce40 Update AWS.php
Fixed region for EU endpoint
2022-08-17 13:54:10 +02:00
54a4d9e4c3 Remove composer.lock file 2022-06-14 09:16:14 +09:00
bd2a328956 Merge split git repositories into one agin 2022-06-14 09:15:37 +09:00
bcbf97b406 phpUnit tests updates and fixes
All gift card id checks are against string and not numeric.

Add missing checks for card status, card amount value, card amount
currency in any buy card checks.

Add epiration date regex check for buy card

Add request cancled card check.
2022-06-14 06:56:19 +09:00
422fc66137 phpUnit tests updates and fixes
All gift card id checks are against string and not numeric.

Add missing checks for card status, card amount value, card amount
currency in any buy card checks.

Add epiration date regex check for buy card

Add request cancled card check.
2022-06-14 06:55:38 +09:00
462d00cb42 Readme file update 2022-06-13 20:00:04 +09:00
308794488d Update Readme file with various fixes 2022-06-13 19:59:07 +09:00
96b24f9424 Add phpUnit testing and update test file.
Test file does not run any tests automatically but they need to be
triggered with the _GET parameters.

A full phpunit test has been added for the full functionality
2022-06-13 19:53:00 +09:00
d69781a709 Move decodeExceptionMessage to Exceptions class
The method "decodeExceptionMessage" previous located in the
AmazonIncentives\AmazonIncentives main class has been moved to the
AmazonIncentives\Exceptions\AmazonErrors where it logically belongs.

A deprecation phpdoc message has been added for the current version.

Update error messages in curl error part and remove double spaces.
2022-06-13 19:52:34 +09:00
2bcd42f4a5 Add phpUnit testing for Amazon Incentives class 2022-06-13 18:09:52 +09:00
05b33ac157 Move decode error method, minor text update for error strings
the method "decodeExceptionMessage" has moved from
AmazonIncentives\AmazonIncentives to
AmazonIncentives\Exceptions\AmazonErrors

The old method is currently tagged deprecated internal via @deprecated
PHPdoc entry
2022-06-13 18:06:16 +09:00
4f072d2226 Merge branch 'development' Wrapper method additions 2022-06-10 14:51:22 +09:00
774e553d90 Add new class create methods for proper phpunit testing
Instead of direct calling Client class and AWS class add a wrapper
method to call those so we can quicker replace under elements and
also do proper testing

Turn on mock tests on AWS side in normal test file
2022-06-10 14:50:32 +09:00
fd5477269b Turn on mock tests on AWS side in normal test file 2022-06-10 14:49:32 +09:00
afb11a6797 Add new class create methods for proper phpunit testing
instead of direct calling Client class and AWS class add a wrapper
method to call those so we can quicker replace under elements and also
do proper testing
2022-06-10 14:40:40 +09:00
d6382960bf Merge branch 'development' with phpDoc changes 2022-06-10 14:38:15 +09:00
b26cc82055 Add PHPdoc to all methods, minor code reorder
Move some methods around to have them together by call order logic.

Also update current test methods with composer based .env reader.
2022-06-10 14:37:07 +09:00
6f177986f9 Update PHPdoc in AmazonIncentive and Config class
Missing documentation for methods/class constructors
2022-06-10 14:30:20 +09:00
e1b5dc1bab Add PHPdoc to all methods, minor code reorder
Move some methods around to have them together by call order logic
2022-06-09 16:02:25 +09:00
7cb5e00a5f Add base phpUnit file 2022-06-09 09:26:42 +09:00
a51f4df53e Update core git config files, vendor installs for unit testing
Update .gitattributes with more files to ignore
Add .gitignore for php unit test cache
Install dotenv file parser for unit testing
Update current test pages with dotenv file parser (replaces function
call)

Documentation PHPdoc update for checkMe method call
2022-06-09 09:25:08 +09:00
42087a64fa Add .gitignore file for not needed files 2022-06-08 16:45:43 +09:00
ab95e1c21b Remove not needed files and folders for composer publish 2022-06-08 15:21:58 +09:00
1e836e9a2b Update to static checker file, add phpunit xml, update composer json 2022-06-08 15:04:59 +09:00
b1079e1d24 Install composer phpunit v9 for development testing 2022-06-08 06:34:47 +09:00
5b99da616b Just rename the readEnvFile function for testing
Until I find out how I can exclude folders from beeing deployed
Update composer ingore list
Add .gitattributes for ignore list
2022-03-18 09:24:27 +09:00
f60aa3e1bc Merge branch 'development'
PHPstan config updates, test file update
2021-11-25 17:45:13 +09:00
b041720a18 phpstan config updates, test code update 2021-11-25 17:44:04 +09:00
be6b2be55d Merge pull request #1 from arif-rh/minor-fix
Minor fix for README type on composer command and trailing , in config class
2021-11-25 17:42:33 +09:00
Arif RH
6163d26f50 minor fix Config 2021-11-25 14:55:55 +07:00
Arif RH
a4c06b9a36 minor fix README 2021-11-25 14:55:09 +07:00
24dc8426de Remove space from client interface 2021-10-27 17:55:29 +09:00
7ef4133537 Update composer json file to exclude test and static test files 2021-10-21 15:51:05 +09:00
4f90f2d916 Update test with simpl .env variables and include example file 2021-10-21 15:00:45 +09:00
192e4e54e1 Add psalm to level 3 and clean up more code 2021-10-21 14:57:29 +09:00
d0b676f8ce Add phan checks at max level 2021-10-21 13:37:59 +09:00
c2721cb8d4 Add PHPstan and fix all checks for max level 2021-10-21 13:31:18 +09:00
18cf3330df Change license to MIT 2021-10-21 10:31:08 +09:00
34 changed files with 2113 additions and 1373 deletions

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
test/ export-ignore
phpstan.neon export-ignore
phpunit.xml export-ignore
psalm.xml export-ignore
.phan/ export-ignore
.* export-ignore

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
vendor
.phpunit.result.cache
composer.lock

98
.phan/config.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
/**
* This configuration will be read and overlaid on top of the
* default configuration. Command line arguments will be applied
* after this file is read.
*
* @see src/Phan/Config.php
* See Config for all configurable options.
*
* A Note About Paths
* ==================
*
* Files referenced from this file should be defined as
*
* ```
* Config::projectPath('relative_path/to/file')
* ```
*
* where the relative path is relative to the root of the
* project which is defined as either the working directory
* of the phan executable or a path passed in via the CLI
* '-d' flag.
*/
// use Phan\Config;
return [
// If true, missing properties will be created when
// they are first seen. If false, we'll report an
// error message.
"allow_missing_properties" => false,
// Allow null to be cast as any type and for any
// type to be cast to null.
"null_casts_as_any_type" => false,
// Backwards Compatibility Checking
'backward_compatibility_checks' => true,
// Run a quick version of checks that takes less
// time
"quick_mode" => false,
// Only emit critical issues to start with
// (0 is low severity, 5 is normal severity, 10 is critical)
"minimum_severity" => 10,
// default false for include path check
"enable_include_path_checks" => true,
"include_paths" => [
],
'ignore_undeclared_variables_in_global_scope' => true,
"file_list" => [
],
// A list of directories that should be parsed for class and
// method information. After excluding the directories
// defined in exclude_analysis_directory_list, the remaining
// files will be statically analyzed for errors.
//
// Thus, both first-party and third-party code being used by
// your application should be included in this list.
'directory_list' => [
// Change this to include the folders you wish to analyze
// (and the folders of their dependencies)
'.'
// 'www',
// To speed up analysis, we recommend going back later and
// limiting this to only the vendor/ subdirectories your
// project depends on.
// `phan --init` will generate a list of folders for you
//'www/vendor',
],
// A list of directories holding code that we want
// to parse, but not analyze
"exclude_analysis_directory_list" => [
'vendor',
'test',
],
'exclude_file_list' => [
],
// what not to show as problem
'suppress_issue_types' => [
// 'PhanUndeclaredMethod',
'PhanEmptyFile',
],
// Override to hardcode existence and types of (non-builtin) globals in the global scope.
// Class names should be prefixed with `\`.
//
// (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
'globals_type_map' => [],
];

View File

@@ -1,12 +1,14 @@
# Amazon Incentives - Gift Codes on Demand stand alone class # Amazon Incentives - Gift Codes on Demand stand alone class
This is a abastract from (https://github.com/kamerk22/AmazonGiftCode) to be not dependend on Laravel base code. This is a abastract from [https://github.com/kamerk22/AmazonGiftCod](https://github.com/kamerk22/AmazonGiftCode) to be not dependend on Laravel base code.
Amazon Gift Codes On Demand (AGCOD). Integration for Amazon Incentive API. Amazon Gift Codes On Demand (AGCOD). Integration for Amazon Incentive API.
[General Amazon Incentives Documentation](https://developer.amazon.com/docs/incentives-api/digital-gift-cards.html)
## How to install ## How to install
`composer request gullevek/amazon-incentives` `composer require gullevek/amazon-incentives`
## _ENV variables needed ## _ENV variables needed
@@ -82,10 +84,13 @@ The error code is the curl handler error code.
The error message is json encoded array with the layout The error message is json encoded array with the layout
Use Use
```php ```php
$exception_array = gullevek\AmazonIncentives\AmazonIncentives::decodeExceptionMessage($exception_message); $exception_array = gullevek\AmazonIncentives\AmazonIncentives::decodeExceptionMessage($exception_message);
``` ```
to extract the below array from the thrown exception to extract the below array from the thrown exception
```php ```php
[ [
'status' => 'AWS Status FAILURE or RESEND', 'status' => 'AWS Status FAILURE or RESEND',
@@ -99,16 +104,32 @@ to extract the below array from the thrown exception
`status`, `code` and `type` must be checked on a failure. `status`, `code` and `type` must be checked on a failure.
**NOTE**: if code is T001 then this is a request flood error: ## Other Errors from exceptions
### T001
if code is T001 then this is a request flood error:
In this case the request has to be resend after a certain waiting period. In this case the request has to be resend after a certain waiting period.
**NOTE**: if code is E999 some other critical error has happened ### E999
**NOTE**: if code is E001 if the return create/cancel/check calls is not an array if code is E999 some other critical error has happened
**NOTE**: if code is C001 a curl error has happened ### E001
**NOTE**: any other NON amazon error will have only 'message' set if run through decode if code is E001 if the return create/cancel/check calls is not an array
### C001
fif code is C001 curl failed to init
### C002
if code is C002 a curl error has happened
### empty error code
any other NON amazon error will have only 'message' set if run through decode
## Debugging ## Debugging
@@ -117,6 +138,7 @@ If AWS_DEBUG is set to 1 and internal array will be written with debug info.
The gulleek\AmazonIncentives\Debug\AmazonDebug class handles all this. The gulleek\AmazonIncentives\Debug\AmazonDebug class handles all this.
In the gulleek\AmazonIncentives\AmazonIncentives main class the debugger gets set In the gulleek\AmazonIncentives\AmazonIncentives main class the debugger gets set
* setDebug that turns debugger on/off and if on sets unique id (getId to check) * setDebug that turns debugger on/off and if on sets unique id (getId to check)
New entries can be written with New entries can be written with

View File

@@ -3,7 +3,7 @@
"description": "Amazon Gift Codes, Gift on Demand, Incentives", "description": "Amazon Gift Codes, Gift on Demand, Incentives",
"keywords": ["AmazonGiftCode", "Amazon", "GiftCard", "AGCOD", "Incentives API", "Amazon Incentives API"], "keywords": ["AmazonGiftCode", "Amazon", "GiftCard", "AGCOD", "Incentives API", "Amazon Incentives API"],
"type": "library", "type": "library",
"license": "help", "license": "MIT",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"gullevek\\AmazonIncentives\\": "src/" "gullevek\\AmazonIncentives\\": "src/"
@@ -20,5 +20,13 @@
"minimum-stability": "dev", "minimum-stability": "dev",
"require": { "require": {
"php": ">=7.4.0" "php": ">=7.4.0"
},
"archive": {
"exclude": ["/test/", "/test/*", "/phpstan.neon", "/psalm.xml", "/.phan/", "/.vscode/", "/phpunit.xml"]
},
"require-dev": {
"phpunit/phpunit": "^9",
"gullevek/dotenv": "dev-master",
"dg/bypass-finals": "dev-master"
} }
} }

11
phpstan.neon Normal file
View File

@@ -0,0 +1,11 @@
# PHP Stan Config
parameters:
tmpDir: /tmp/phpstan-codeblocks-amazon-incentives
level: 8
paths:
- %currentWorkingDirectory%
excludePaths:
# ignore composer
- vendor
- test

9
phpunit.xml Normal file
View File

@@ -0,0 +1,9 @@
<phpunit
colors="true"
verbose="true"
>
<!-- Below removes final from classes for mock tests -->
<extensions>
<extension class="test\phpUnit\Hook\BypassFinalHook" file="test/phpUnit/Hook/BypassFinalHook.php" />
</extensions>
</phpunit>

16
psalm.xml Normal file
View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<psalm
errorLevel="8"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="." />
<ignoreFiles>
<directory name="vendor" />
<directory name="test" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@@ -12,23 +12,40 @@ use gullevek\AmazonIncentives\Response\CreateResponse;
class AWS class AWS
{ {
/** @var string What AWS Service to use: Gift Card on Demand (GCOD) */
public const SERVICE_NAME = 'AGCODService'; public const SERVICE_NAME = 'AGCODService';
/** @var string */
public const ACCEPT_HEADER = 'accept'; public const ACCEPT_HEADER = 'accept';
/** @var string content-type */
public const CONTENT_HEADER = 'content-type'; public const CONTENT_HEADER = 'content-type';
/** @var string */
public const HOST_HEADER = 'host'; public const HOST_HEADER = 'host';
/** @var string */
public const X_AMZ_DATE_HEADER = 'x-amz-date'; public const X_AMZ_DATE_HEADER = 'x-amz-date';
/** @var string */
public const X_AMZ_TARGET_HEADER = 'x-amz-target'; public const X_AMZ_TARGET_HEADER = 'x-amz-target';
/** @var string */
public const AUTHORIZATION_HEADER = 'Authorization'; public const AUTHORIZATION_HEADER = 'Authorization';
/** @var string type of encryption type */
public const AWS_SHA256_ALGORITHM = 'AWS4-HMAC-SHA256'; public const AWS_SHA256_ALGORITHM = 'AWS4-HMAC-SHA256';
/** @var string key type to use */
public const KEY_QUALIFIER = 'AWS4'; public const KEY_QUALIFIER = 'AWS4';
/** @var string */
public const TERMINATION_STRING = 'aws4_request'; public const TERMINATION_STRING = 'aws4_request';
/** @var string Service to use: Create Gift Card */
public const CREATE_GIFT_CARD_SERVICE = 'CreateGiftCard'; public const CREATE_GIFT_CARD_SERVICE = 'CreateGiftCard';
/** @var string Service to use: Cancle Gift Card */
public const CANCEL_GIFT_CARD_SERVICE = 'CancelGiftCard'; public const CANCEL_GIFT_CARD_SERVICE = 'CancelGiftCard';
/** @var string Service to use: Get Available Funds */
public const GET_AVAILABLE_FUNDS_SERVICE = 'GetAvailableFunds'; public const GET_AVAILABLE_FUNDS_SERVICE = 'GetAvailableFunds';
/** @var Config Configuration class with all settings */
private $config; private $config;
/** /**
* Initialize the main AWS class. This class prepares and sends all the actions
* and returns reponses as defined in in the CreateResponse class
*
* @param Config $config * @param Config $config
*/ */
public function __construct(Config $config) public function __construct(Config $config)
@@ -38,9 +55,13 @@ class AWS
} }
/** /**
* @param float $amount * Bug a gift card
* @param string|null $creation_id *
* @return CreateResponse * @param float $amount Amount to buy a gifr card in set currencty
* @param string|null $creation_id Override creation id, if not set will
* be created automatically. If not valid error
* will be thrown
* @return CreateResponse Object with AWS response data
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
@@ -61,9 +82,11 @@ class AWS
} }
/** /**
* @param string $creation_request_id * Cancle an ordered gift card, only possible within the the time limit
* @param string $gift_card_id *
* @return CancelResponse * @param string $creation_request_id Previously created creation request id
* @param string $gift_card_id Previously created gift card id
* @return CancelResponse Object with AWS response data
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
@@ -84,7 +107,9 @@ class AWS
} }
/** /**
* @return CreateBalanceResponse * Get current account funds
*
* @return CreateBalanceResponse Object with AWS response data
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
@@ -105,11 +130,27 @@ class AWS
} }
/** /**
* @param string $payload * return a new curl connection client class
* @param string $canonical_request *
* @param string $service_operation * @return Client Curl connection Client
* @param string $date_time_string */
* @return string public function newClient(): Client
{
return new Client();
}
/**
* General request method for all actions
* Calls the Client class that actually runs the json request
* For service_operation valid data see AWS GCOD documentation
*
* @param string $payload The data needed for this request
* @param string $canonical_request Header data to send for this request
* @param string $service_operation Service operation. CREATE_GIFT_CARD_SERVICE,
* CANCEL_GIFT_CARD_SERVICE or
* GET_AVAILABLE_FUNDS_SERVICE constant values
* @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp()
* @return string Request result as string, json data
*/ */
public function makeRequest( public function makeRequest(
string $payload, string $payload,
@@ -152,17 +193,26 @@ class AWS
'Service' => $k_service_hexis, 'Service' => $k_service_hexis,
]]); ]]);
$url = 'https://' . (string)$endpoint . '/' . $service_operation; $url = 'https://' . $endpoint . '/' . $service_operation;
$headers = $this->buildHeaders($payload, $authorization_value, $date_time_string, $service_target); $headers = $this->buildHeaders(
return (new Client())->request($url, $headers, $payload); $payload,
$authorization_value,
$date_time_string,
$service_target
);
return ($this->newClient())->request($url, $headers, $payload);
} }
/** /**
* @param string $payload * Build the headers used in the makeRequest method.
* @param string $authorization_value * These are the HTML headers used with curl
* @param string $date_time_string *
* @param string $service_target * @param string $payload Paylout to create this header for
* @return array * @param string $authorization_value Auth string
* @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp()
* @param string $service_target Target service in the agcod string:
* Value like com.amazonaws.agcod.<sn>.<so>
* @return array<mixed> Header data as array for curl request
*/ */
public function buildHeaders( public function buildHeaders(
string $payload, string $payload,
@@ -185,8 +235,33 @@ class AWS
} }
/** /**
* @param string $string_to_sign * The request string build with the actauly request data created by
* @return string * getCanonicalRequest(). This string is used in the auth signature call
*
* @param string $canonical_request_hash sha256 hash to build from
* @return string String to send to buildAuthSignature()
*/
public function buildStringToSign($canonical_request_hash): string
{
$AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM;
$TERMINATION_STRING = self::TERMINATION_STRING;
$SERVICE_NAME = self::SERVICE_NAME;
$region_name = $this->getRegion();
$date_time_string = $this->getTimestamp();
$date_string = $this->getDateString();
$string_to_sign = "$AWS_SHA256_ALGORITHM\n"
. "$date_time_string\n"
. "$date_string/$region_name/$SERVICE_NAME/$TERMINATION_STRING\n"
. "$canonical_request_hash";
return $string_to_sign;
}
/**
* Build the authentication signature used in the buildHeaders method
*
* @param string $string_to_sign Data to sign, buildStringToSign()
* @return string Authorized value as string
*/ */
public function buildAuthSignature(string $string_to_sign): string public function buildAuthSignature(string $string_to_sign): string
{ {
@@ -221,28 +296,12 @@ class AWS
} }
/** /**
* @param string $canonical_request_hash * Build the derived key to build the final hmac signature string
* @return string *
*/ * @param bool $rawOutput Set to true to create the hash based message
public function buildStringToSign($canonical_request_hash): string * authenticator string as normal text string or
{ * lowercase hexbits
$AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM; * @return string Derived key (hmac type)
$TERMINATION_STRING = self::TERMINATION_STRING;
$SERVICE_NAME = self::SERVICE_NAME;
$region_name = $this->getRegion();
$date_time_string = $this->getTimestamp();
$date_string = $this->getDateString();
$string_to_sign = "$AWS_SHA256_ALGORITHM\n"
. "$date_time_string\n"
. "$date_string/$region_name/$SERVICE_NAME/$TERMINATION_STRING\n"
. "$canonical_request_hash";
return $string_to_sign;
}
/**
* @param bool $rawOutput
* @return string
*/ */
public function buildDerivedKey(bool $rawOutput = true): string public function buildDerivedKey(bool $rawOutput = true): string
{ {
@@ -290,7 +349,7 @@ class AWS
* MXN for MX * MXN for MX
* GBP for UK * GBP for UK
* *
* @return string * @return string Region string depending on given endpoint url
*/ */
public function getRegion(): string public function getRegion(): string
{ {
@@ -305,7 +364,7 @@ class AWS
break; break;
case 'agcod-v2-eu.amazon.com': case 'agcod-v2-eu.amazon.com':
case 'agcod-v2-eu-gamma.amazon.com': case 'agcod-v2-eu-gamma.amazon.com':
$region_name = 'us-west-1'; $region_name = 'eu-west-1';
break; break;
case 'agcod-v2-fe.amazon.com': case 'agcod-v2-fe.amazon.com':
case 'agcod-v2-fe-gamma.amazon.com': case 'agcod-v2-fe-gamma.amazon.com':
@@ -317,56 +376,91 @@ class AWS
/** /**
* @param float $amount * The actual data to send as json encoded string for creating a gift card.
* @param string $creation_id * The creation request id must be in the format:
* @return string * <partner_id>_<unique id 13 characters>
*
* @param float $amount Amount of currencty to create the gift card
* request for
* @param string|null $creation_id The creation id, if not set will be created here
* @return string JSON encoded array to be used as payload
* in get gift card call
*/ */
public function getGiftCardPayload(float $amount, ?string $creation_id = null): string public function getGiftCardPayload(float $amount, ?string $creation_id = null): string
{ {
$amount = trim($amount);
$payload = [ $payload = [
'creationRequestId' => $creation_id ?: uniqid($this->config->getPartner() . '_'), 'creationRequestId' => $creation_id ?: uniqid($this->config->getPartner() . '_'),
'partnerId' => $this->config->getPartner(), 'partnerId' => $this->config->getPartner(),
'value' => 'value' =>
[ [
'currencyCode' => $this->config->getCurrency(), 'currencyCode' => $this->config->getCurrency(),
'amount' => (float)$amount 'amount' => $amount
] ]
]; ];
return json_encode($payload); return (json_encode($payload)) ?: '';
} }
/** /**
* @param string $creation_request_id * The actual data to send as json encoded string to cancel a created gift card
* @param string $gift_card_id *
* @return string * @param string $creation_request_id Creation request id from previous get gift card
* @param string $gift_card_id Gift card id from previous get gift card
* @return string JSON encoded array to be used as payload
* in cancle gift card call
*/ */
public function getCancelGiftCardPayload(string $creation_request_id, string $gift_card_id): string public function getCancelGiftCardPayload(string $creation_request_id, string $gift_card_id): string
{ {
$gift_card_response_id = trim($gift_card_id);
$payload = [ $payload = [
'creationRequestId' => $creation_request_id, 'creationRequestId' => $creation_request_id,
'partnerId' => $this->config->getPartner(), 'partnerId' => $this->config->getPartner(),
'gcId' => $gift_card_response_id 'gcId' => $gift_card_id
]; ];
return json_encode($payload); return (json_encode($payload)) ?: '';
} }
/** /**
* @return string * The actualy data to send as json encoded string for getting the current
* account funds
*
* @return string JSON encoded array to be used as payload in funds call
*/ */
public function getAvailableFundsPayload(): string public function getAvailableFundsPayload(): string
{ {
$payload = [ $payload = [
'partnerId' => $this->config->getPartner(), 'partnerId' => $this->config->getPartner(),
]; ];
return json_encode($payload); return (json_encode($payload)) ?: '';
} }
/** /**
* @param string $service_operation * Heeders used in the getCanonicalRequest()
* @param string $payload *
* @return string * @param string $service_operation Service operation code in the service string request
* Value is: com.amazonaws.agcod.AGCODService.<so>
* @return string Header string to be used
*/
public function buildCanonicalHeaders(string $service_operation): string
{
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$HOST_HEADER = self::HOST_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$date_time_string = $this->getTimestamp();
$endpoint = $this->config->getEndpoint();
$content_type = $this->getContentType();
return "$ACCEPT_HEADER:$content_type\n"
. "$HOST_HEADER:$endpoint\n"
. "$X_AMZ_DATE_HEADER:$date_time_string\n"
. "$X_AMZ_TARGET_HEADER:com.amazonaws.agcod.AGCODService.$service_operation";
}
/**
* Headers used in the get/cancel/funds requests
*
* @param string $service_operation Service operation code to be used in header request
* and main request call
* @param string $payload Payload from get/cancle Code or funds call
* @return string Full POST service request code
*/ */
public function getCanonicalRequest(string $service_operation, string $payload): string public function getCanonicalRequest(string $service_operation, string $payload): string
{ {
@@ -385,8 +479,10 @@ class AWS
} }
/** /**
* @param string $data * Build sha256 hash from given data
* @return string *
* @param string $data Data to be hashed with sha256
* @return string sha256 hash
*/ */
public function buildHash(string $data): string public function buildHash(string $data): string
{ {
@@ -394,18 +490,13 @@ class AWS
} }
/** /**
* @return false|string * Create a sha256 based Hash-Based Message Authentication Code
*/ * with the given key and data
public function getTimestamp() *
{ * @param string $data Data to be hashed with key below
return gmdate('Ymd\THis\Z'); * @param string $key Key to be used for creating the hash
} * @param bool $raw Returning data as ascii string or hexibits
* @return string Hash-Based Message Authentication Code
/**
* @param string $data
* @param string $key
* @param bool $raw
* @return string
*/ */
public function hmac(string $data, string $key, bool $raw = true): string public function hmac(string $data, string $key, bool $raw = true): string
{ {
@@ -413,7 +504,21 @@ class AWS
} }
/** /**
* @return bool|string * Build timestamp in the format used by AWS services
* eg 20211009\T102030\Z
*
* @return string date string based on current time. Ymd\THis\Z
*/
public function getTimestamp()
{
return gmdate('Ymd\THis\Z');
}
/**
* Get only the date string from the getTimestamp
* eg 20211009
*
* @return string Date string YYYYmmdd extracted from getTimestamp()
*/ */
public function getDateString() public function getDateString()
{ {
@@ -421,31 +526,14 @@ class AWS
} }
/** /**
* @return string * Fixed content type for submission, is json
*
* @return string 'application/json' string
*/ */
public function getContentType(): string public function getContentType(): string
{ {
return 'application/json'; return 'application/json';
} }
/**
* @param string $service_operation
* @return string
*/
public function buildCanonicalHeaders(string $service_operation): string
{
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$HOST_HEADER = self::HOST_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$date_time_string = $this->getTimestamp();
$endpoint = $this->config->getEndpoint();
$content_type = $this->getContentType();
return "$ACCEPT_HEADER:$content_type\n"
. "$HOST_HEADER:$endpoint\n"
. "$X_AMZ_DATE_HEADER:$date_time_string\n"
. "$X_AMZ_TARGET_HEADER:com.amazonaws.agcod.AGCODService.$service_operation";
}
} }
// __END__ // __END__

View File

@@ -2,36 +2,7 @@
/* /*
* Amazon Incentive Code * Amazon Incentive Code
* * Amazon Gift Code on Demand
* # settings:
* aws endpoint (also sets region)
* aws key
* aws secret
* aws partner id
* money type (set as default, override in call)
* money value (set as default, override in call)
*
* # checks
* endpoint + region must match
*
* # calls:
* create gift card: CreateGiftCard
* cancel gift card: CancelGiftCard
*
* activate gift card: ActivateGiftCard
* deactivate gift card: DeactivateGiftCard
*
* gift card status: ActivationStatusCheck
*
* check available funds: GetAvailablefunds
*
* api server health check
*
* # sub classes
* config reader/checker
* API v4 encrypter
* submitter/data getter
* error handler/retry
*/ */
namespace gullevek\AmazonIncentives; namespace gullevek\AmazonIncentives;
@@ -41,19 +12,22 @@ use gullevek\AmazonIncentives\Config\Config;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors; use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class AmazonIncentives final class AmazonIncentives
{ {
/**
* @var Config
*/
private $config; private $config;
/** /**
* AmazonGiftCode constructor. * AmazonGiftCode constructor.
* *
* @param string|null $key * @param string|null $key Account key
* @param string|null $secret * @param string|null $secret Secret key
* @param string|null $partner * @param string|null $partner Partner ID
* @param string|null $endpoint * @param string|null $endpoint Endpoint URL including https://
* @param string|null $currency * @param string|null $currency Currency type. Eg USD, JPY, etc
* @param bool|null $debug * @param bool|null $debug Debug flag
*/ */
public function __construct( public function __construct(
string $key = null, string $key = null,
@@ -79,48 +53,60 @@ class AmazonIncentives
// ********************************************************************* // *********************************************************************
/** /**
* @param float $value * Buy a gift card
* @param string $creation_request_id AWS creationRequestId *
* @return Response\CreateResponse * @param float $value Amount to purchase a gift card
* in currency value
* @param string|null $creation_request_id Override automatically created request id
* If not set will create a new one, or
* return data for created one
* @return Response\CreateResponse Returns new created response object or
* previous created if creation_request_id was used
* *
* @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 (new AWS($this->config))->getCode($value, $creation_request_id); return ($this->newAWS())->getCode($value, $creation_request_id);
} }
/** /**
* @param string $creation_request_id AWS creationRequestId * Cancel a previous created gift card, if within the time frame
* @param string $gift_card_id AWS gcId *
* @return Response\CancelResponse * @param string $creation_request_id Previous created request id from buyGiftCard
* @param string $gift_card_id Previous gift card id from buyGiftCard (gcId)
* @return Response\CancelResponse Returns the cancled request object
*
* @throws AmazonErrors
*/ */
public function cancelGiftCard(string $creation_request_id, string $gift_card_id): Response\CancelResponse public function cancelGiftCard(string $creation_request_id, string $gift_card_id): Response\CancelResponse
{ {
return (new AWS($this->config))->cancelCode($creation_request_id, $gift_card_id); return ($this->newAWS())->cancelCode($creation_request_id, $gift_card_id);
} }
/** /**
* @return Response\CreateBalanceResponse * Gets the current funds in this account
*
* @return Response\CreateBalanceResponse Returns the account funds object
* *
* @throws AmazonErrors * @throws AmazonErrors
*/ */
public function getAvailableFunds(): Response\CreateBalanceResponse public function getAvailableFunds(): Response\CreateBalanceResponse
{ {
return (new AWS($this->config))->getBalance(); return ($this->newAWS())->getBalance();
} }
/** /**
* AmazonGiftCode make own client. * AmazonIncentives creates own client and returns it as static object
* *
* @param string|null $key * @param string|null $key Account key
* @param string|null $secret * @param string|null $secret Secret key
* @param string|null $partner * @param string|null $partner Partner ID
* @param string|null $endpoint * @param string|null $endpoint Endpoint URL including https://
* @param string|null $currency * @param string|null $currency Currency type. Eg USD, JPY, etc
* @param bool|null $debug * @param bool|null $debug Debug flag
* @return AmazonGiftCode * @return AmazonIncentives self class
*/ */
public static function make( public static function make(
string $key = null, string $key = null,
@@ -133,35 +119,43 @@ class AmazonIncentives
return new static($key, $secret, $partner, $endpoint, $currency, $debug); return new static($key, $secret, $partner, $endpoint, $currency, $debug);
} }
/**
* wrapper to create new AWS class.
* used in all buy/cancel/get calss
*
* @return AWS Main AWS worker class
*/
public function newAWS(): AWS
{
return new AWS($this->config);
}
/** /**
* Decodes the Exception message body * Decodes the Exception message body
* Returns an array with code (Amazon error codes), type (Amazon error info) * Returns an array with code (Amazon error codes), type (Amazon error info)
* message (Amazon returned error message string) * message (Amazon returned error message string)
* *
* @param string $message Exception message json string * @param string $message Exception message json string
* @return array Decoded with code, type, message fields * @return array<mixed> Decoded with code, type, message fields
*
* @deprecated use \gullevek\AmazonIncentives\Exceptions\AmazonErrors::decodeExceptionMessage()
*/ */
public static function decodeExceptionMessage(string $message): array public static function decodeExceptionMessage(string $message): array
{ {
$message_ar = json_decode($message, true); return AmazonErrors::decodeExceptionMessage($message);
// if we have an error, build empty block and only fill message
if (json_last_error()) {
$message_ar = [
'status' => '',
'code' => '',
'type' => '',
'message' => $message,
'log_id' => '',
'log' => []
];
}
return $message_ar;
} }
// ********************************************************************* // *********************************************************************
// PUBLIC TEST METHODS // PUBLIC TEST METHODS
// ********************************************************************* // *********************************************************************
/**
* Prints out ENV, CONFIG and KEY data
* This is for debug only, this will print out secrets.
* Use with care
*
* @return array<mixed>
*/
public function checkMe(): array public function checkMe(): array
{ {
$data = []; $data = [];

View File

@@ -7,21 +7,32 @@ use gullevek\AmazonIncentives\Debug\AmazonDebug;
class Client implements ClientInterface class Client implements ClientInterface
{ {
// instead of JsonResponse::HTTP_OK /** @var int instead of JsonResponse::HTTP_OK */
private const HTTP_OK = 200; private const HTTP_OK = 200;
/** /**
* Makes an request to the target url via curl
* Returns result as string (json)
* *
* @param string $url The URL being requested, including domain and protocol * @param string $url The URL being requested,
* @param array $headers Headers to be used in the request * including domain and protocol
* @param array|string $params Can be nested for arrays and hashes * @param array<mixed> $headers Headers to be used in the request
* * @param array<mixed>|string $params Can be nested for arrays and hashes
* * @return string Result as json string
* @return String
*/ */
public function request(string $url, array $headers, $params): string public function request(string $url, array $headers, $params): string
{ {
$handle = curl_init($url); $handle = curl_init($url);
if ($handle === false) {
// throw Error here with all codes
throw AmazonErrors::getError(
'FAILURE',
'C001',
'CurlInitError',
'Failed to init curl with url: ' . $url,
0
);
}
curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
// curl_setopt($handle, CURLOPT_FAILONERROR, true); // curl_setopt($handle, CURLOPT_FAILONERROR, true);
@@ -39,13 +50,13 @@ 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($result, true); $result_ar = json_decode((string)$result, true);
// 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';
$error_code = 'T001'; $error_code = 'T001';
$error_type = 'RateExceeded'; $error_type = 'RateExceeded';
$message = $result_ar['message']; $message = $result_ar['message'] ?? 'Rate exceeded';
} else { } else {
// for all other error messages // for all other error messages
$error_status = $result_ar['agcodResponse']['status'] ?? 'FAILURE'; $error_status = $result_ar['agcodResponse']['status'] ?? 'FAILURE';
@@ -62,15 +73,16 @@ class Client implements ClientInterface
$err $err
); );
} }
return $result; return (string)$result;
} }
/** /**
* Undocumented function * handles any CURL errors and throws an error with the correct
* error message
* *
* @param string $url * @param string $url The url that was originaly used
* @param string $errno * @param int $errno Error number from curl handler
* @param string $message * @param string $message The error message string from curl
* @return void * @return void
*/ */
private function handleCurlError(string $url, int $errno, string $message): void private function handleCurlError(string $url, int $errno, string $message): void
@@ -82,7 +94,6 @@ class Client implements ClientInterface
$message = 'Could not connect to AWS (' . $url . '). Please check your ' $message = 'Could not connect to AWS (' . $url . '). Please check your '
. 'internet connection and try again. [' . $message . ']'; . 'internet connection and try again. [' . $message . ']';
break; break;
case CURLE_SSL_CACERT:
case CURLE_SSL_PEER_CERTIFICATE: case CURLE_SSL_PEER_CERTIFICATE:
$message = 'Could not verify AWS SSL certificate. Please make sure ' $message = 'Could not verify AWS SSL certificate. Please make sure '
. 'that your network is not intercepting certificates. ' . 'that your network is not intercepting certificates. '
@@ -97,7 +108,7 @@ class Client implements ClientInterface
// throw an error like in the normal reqeust, but set to CURL error // throw an error like in the normal reqeust, but set to CURL error
throw AmazonErrors::getError( throw AmazonErrors::getError(
'FAILURE', 'FAILURE',
'C001', 'C002',
'CurlError', 'CurlError',
$message, $message,
$errno $errno

View File

@@ -5,13 +5,13 @@ namespace gullevek\AmazonIncentives\Client;
interface ClientInterface interface ClientInterface
{ {
/** /**
* @param string $url The URL being requested, including domain and protocol * @param string $url The URL being requested,
* @param array $headers Headers to be used in the request * including domain and protocol
* @param array|string $params Can be nested for arrays and hashes * @param array<mixed> $headers Headers to be used in the request
* @param array<mixed>|string $params Can be nested for arrays and hashes
* *
* @return String * @return String
*/ */
public function request(string $url, array $headers, $params): string; public function request(string $url, array $headers, $params): string;
} }

View File

@@ -4,37 +4,27 @@ namespace gullevek\AmazonIncentives\Config;
class Config implements ConfigInterface class Config implements ConfigInterface
{ {
/** /** @var string Endpoint URL without https:// */
* @var string private $endpoint = '';
*/ /** @var string Access Key */
private $endpoint; private $access_key = '';
/** /** @var string Secret Key */
* @var string private $secret_key = '';
*/ /** @var string Partner ID */
private $access_key; private $partner_id = '';
/** /** @var string Currency type as USD, JPY, etc */
* @var string private $currency = '';
*/ /** @var bool Debug flag on or off */
private $secret_key; private $debug = false;
/**
* @var string
*/
private $partner_id;
/**
* @var string
*/
private $currency;
/**
* @var bool
*/
private $debug;
/** /**
* @param string|null $key * @param string|null $key Access key
* @param string|null $secret * @param string|null $secret Secret Key
* @param string|null $partner * @param string|null $partner Partner ID
* @param string|null $endpoint * @param string|null $endpoint Endpoing URL including https://
* @param string|null $currency * @param string|null $currency Currency to use, see valid list on AWS documentation.
* valid names are like USD, JPY, etc
* @param bool|null $debug Debug flag
*/ */
public function __construct( public function __construct(
?string $key, ?string $key,
@@ -42,14 +32,38 @@ class Config implements ConfigInterface
?string $partner, ?string $partner,
?string $endpoint, ?string $endpoint,
?string $currency, ?string $currency,
?bool $debug, ?bool $debug
) { ) {
$this->setAccessKey($key ?: $this->parseEnv('AWS_GIFT_CARD_KEY')); /**
$this->setSecret($secret ?: $this->parseEnv('AWS_GIFT_CARD_SECRET')); * @psalm-suppress InvalidScalarArgument
$this->setPartner($partner ?: $this->parseEnv('AWS_GIFT_CARD_PARTNER_ID')); * @phpstan-ignore-next-line
$this->setEndpoint($endpoint ?: $this->parseEnv('AWS_GIFT_CARD_ENDPOINT')); */
$this->setCurrency($currency ?: $this->parseEnv('AWS_GIFT_CARD_CURRENCY')); $this->setAccessKey(($key) ?: $this->parseEnv('AWS_GIFT_CARD_KEY'));
$this->setDebug($debug ?: $this->parseEnv('AWS_DEBUG')); /**
* @psalm-suppress InvalidScalarArgument
* @phpstan-ignore-next-line
*/
$this->setSecret(($secret) ?: $this->parseEnv('AWS_GIFT_CARD_SECRET'));
/**
* @psalm-suppress InvalidScalarArgument
* @phpstan-ignore-next-line
*/
$this->setPartner(($partner) ?: $this->parseEnv('AWS_GIFT_CARD_PARTNER_ID'));
/**
* @psalm-suppress InvalidScalarArgument
* @phpstan-ignore-next-line
*/
$this->setEndpoint(($endpoint) ?: $this->parseEnv('AWS_GIFT_CARD_ENDPOINT'));
/**
* @psalm-suppress InvalidScalarArgument
* @phpstan-ignore-next-line
*/
$this->setCurrency(($currency) ?: $this->parseEnv('AWS_GIFT_CARD_CURRENCY'));
/**
* @psalm-suppress InvalidScalarArgument
* @phpstan-ignore-next-line
*/
$this->setDebug(($debug) ?: $this->parseEnv('AWS_DEBUG'));
} }
/** /**
@@ -71,7 +85,7 @@ 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 = $_ENV[$key] ?? ''; $return = (string)($_ENV[$key] ?? '');
break; break;
default: default:
break; break;
@@ -80,36 +94,36 @@ class Config implements ConfigInterface
} }
/** /**
* @return string|null * @return string Returns current set endpoint, without https://
*/ */
public function getEndpoint(): ?string public function getEndpoint(): string
{ {
return $this->endpoint; return $this->endpoint;
} }
/** /**
* @param string $endpoint * @param string $endpoint Full endpoint url with https://
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setEndpoint(string $endpoint): ConfigInterface public function setEndpoint(string $endpoint): ConfigInterface
{ {
// TODO: check valid endpoint + set region // TODO: check valid endpoint + set region
$this->endpoint = parse_url($endpoint, PHP_URL_HOST); $this->endpoint = (parse_url($endpoint, PHP_URL_HOST)) ?: '';
return $this; return $this;
} }
/** /**
* @return string|null * @return string Current access key
*/ */
public function getAccessKey(): ?string public function getAccessKey(): string
{ {
return $this->access_key; return $this->access_key;
} }
/** /**
* @param string $key * @param string $key Access Key to set
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setAccessKey(string $key): ConfigInterface public function setAccessKey(string $key): ConfigInterface
{ {
@@ -119,16 +133,16 @@ class Config implements ConfigInterface
} }
/** /**
* @return string|null * @return string Current secret key
*/ */
public function getSecret(): ?string public function getSecret(): string
{ {
return $this->secret_key; return $this->secret_key;
} }
/** /**
* @param string $secret * @param string $secret Secret key to set
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setSecret(string $secret): ConfigInterface public function setSecret(string $secret): ConfigInterface
{ {
@@ -138,16 +152,16 @@ class Config implements ConfigInterface
} }
/** /**
* @return string|null * @return string Current set currency
*/ */
public function getCurrency(): ?string public function getCurrency(): string
{ {
return $this->currency; return $this->currency;
} }
/** /**
* @param string $currency * @param string $currency Currency to set (eg USD, JPY, etc)
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setCurrency(string $currency): ConfigInterface public function setCurrency(string $currency): ConfigInterface
{ {
@@ -158,16 +172,16 @@ class Config implements ConfigInterface
} }
/** /**
* @return string|null * @return string Current set partner id
*/ */
public function getPartner(): ?string public function getPartner(): string
{ {
return $this->partner_id; return $this->partner_id;
} }
/** /**
* @param string $partner * @param string $partner Partner id to set
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setPartner(string $partner): ConfigInterface public function setPartner(string $partner): ConfigInterface
{ {
@@ -177,16 +191,16 @@ class Config implements ConfigInterface
} }
/** /**
* @return bool|null * @return bool Current set debug flag as bool
*/ */
public function getDebug(): ?bool public function getDebug(): bool
{ {
return $this->debug; return $this->debug;
} }
/** /**
* @param bool $debug * @param bool $debug Set debug flag as bool
* @return ConfigInterface * @return ConfigInterface Class interface (self)
*/ */
public function setDebug(bool $debug): ConfigInterface public function setDebug(bool $debug): ConfigInterface
{ {

View File

@@ -5,68 +5,68 @@ namespace gullevek\AmazonIncentives\Config;
interface ConfigInterface interface ConfigInterface
{ {
/** /**
* @return string|null * @return string Returns current set endpoint, without https://
*/ */
public function getEndpoint(): ?string; public function getEndpoint(): string;
/** /**
* @param string $endpoint * @param string $endpoint Full endpoint url with https://
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setEndpoint(string $endpoint): ConfigInterface; public function setEndpoint(string $endpoint): ConfigInterface;
/** /**
* @return string|null * @return string Current access key
*/ */
public function getAccessKey(): ?string; public function getAccessKey(): string;
/** /**
* @param string $key * @param string $key Access Key to set
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setAccessKey(string $key): ConfigInterface; public function setAccessKey(string $key): ConfigInterface;
/** /**
* @return string|null * @return string Current secret key
*/ */
public function getSecret(): ?string; public function getSecret(): string;
/** /**
* @param string $secret * @param string $secret Secret key to set
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setSecret(string $secret): ConfigInterface; public function setSecret(string $secret): ConfigInterface;
/** /**
* @return string|null * @return string Current set currency
*/ */
public function getCurrency(): ?string; public function getCurrency(): string;
/** /**
* @param string $currency * @param string $currency Currency to set (eg USD, JPY, etc)
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setCurrency(string $currency): ConfigInterface; public function setCurrency(string $currency): ConfigInterface;
/** /**
* @return string|null * @return string Current set partner id
*/ */
public function getPartner(): ?string; public function getPartner(): string;
/** /**
* @param string $partner * @param string $partner Partner id to set
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setPartner(string $partner): ConfigInterface; public function setPartner(string $partner): ConfigInterface;
/** /**
* @return bool|null * @return bool Current set debug flag as bool
*/ */
public function getDebug(): ?bool; public function getDebug(): bool;
/** /**
* @param bool $debug * @param bool $debug Set debug flag as bool
* @return $this * @return ConfigInterface Class interface (self)
*/ */
public function setDebug(bool $debug): ConfigInterface; public function setDebug(bool $debug): ConfigInterface;
} }

View File

@@ -7,8 +7,11 @@ namespace gullevek\AmazonIncentives\Debug;
class AmazonDebug class AmazonDebug
{ {
/** @var array<mixed> Log data array log id -> array of log entries */
private static $log = []; private static $log = [];
/** @var bool debug flag */
private static $debug = false; private static $debug = false;
/** @var string|null Last set internal log array id */
private static $id = null; private static $id = null;
/** /**
@@ -74,7 +77,7 @@ class AmazonDebug
* Will be pushed as new array entry int log * Will be pushed as new array entry int log
* Main key is the set Id for this run * Main key is the set Id for this run
* *
* @param array $data Any array data to store in the log * @param array<mixed> $data Any array data to store in the log
* @return void * @return void
*/ */
public static function writeLog(array $data): void public static function writeLog(array $data): void
@@ -82,7 +85,7 @@ class AmazonDebug
if (self::$debug === false) { if (self::$debug === false) {
return; return;
} }
self::$log[self::getId()][] = $data; self::$log[self::getId() ?? ''][] = $data;
} }
/** /**
@@ -91,7 +94,7 @@ class AmazonDebug
* *
* @param string|null $id If set returns only this id logs * @param string|null $id If set returns only this id logs
* or empty array if not found * or empty array if not found
* @return array Always array, empty if not data or not found * @return array<mixed> Always array, empty if not data or not found
*/ */
public static function getLog(?string $id = null): array public static function getLog(?string $id = null): array
{ {

View File

@@ -5,26 +5,29 @@ namespace gullevek\AmazonIncentives\Exceptions;
use RuntimeException; use RuntimeException;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class AmazonErrors extends RuntimeException final class AmazonErrors extends RuntimeException
{ {
/** /**
* Returns an Runtime exception including a json encoded string with all
* parameters including last log id and log
*
* @param string $error_status agcodResponse->status from Amazon * @param string $error_status agcodResponse->status from Amazon
* @param string $error_code errorCode from Amazon * @param string $error_code errorCode from Amazon
* @param string $error_type errorType from Amazon * @param string $error_type errorType from Amazon
* @param string $message * @param string $message Message string to ad
* @param string $_error_code * @param int $_error_code Error code to set
* @return AmazonErrors * @return AmazonErrors Exception Class
*/ */
public static function getError( public static function getError(
string $error_status, string $error_status,
string $error_code, string $error_code,
string $error_type, string $error_type,
string $message, string $message,
string $_error_code int $_error_code
): self { ): self {
// NOTE: if xdebug.show_exception_trace is set to 1 this will print ERRORS // NOTE: if xdebug.show_exception_trace is set to 1 this will print ERRORS
return new static( return new static(
json_encode([ (json_encode([
'status' => $error_status, 'status' => $error_status,
'code' => $error_code, 'code' => $error_code,
'type' => $error_type, 'type' => $error_type,
@@ -32,10 +35,35 @@ class AmazonErrors extends RuntimeException
// atach log data if exists // atach log data if exists
'log_id' => AmazonDebug::getId(), 'log_id' => AmazonDebug::getId(),
'log' => AmazonDebug::getLog(), 'log' => AmazonDebug::getLog(),
]), ])) ?: 'AmazonErrors: json encode problem: ' . $message,
$_error_code $_error_code
); );
} }
/**
* Decodes the Exception message body
* Returns an array with code (Amazon error codes), type (Amazon error info)
* message (Amazon returned error message string)
*
* @param string $message Exception message json string
* @return array<mixed> Decoded with code, type, message fields
*/
public static function decodeExceptionMessage(string $message): array
{
$message_ar = json_decode($message, true);
// if we have an error, build empty block and only fill message
if (json_last_error()) {
$message_ar = [
'status' => '',
'code' => '',
'type' => '',
'message' => $message,
'log_id' => '',
'log' => []
];
}
return $message_ar;
}
} }
// __END__ // __END__

View File

@@ -2,61 +2,44 @@
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class CancelResponse class CancelResponse
{ {
/** /** @var string Amazon Gift Card gcId (gift card id). */
* Amazon Gift Card gcId. protected $id = '';
* /** @var string Amazon Gift Card creationRequestId (creation request id) */
* @var string protected $creation_request_id = '';
*/ /** @var string Amazon Gift Card status */
protected $id; protected $status = '';
/** /** @var array<mixed> Amazon Gift Card Raw JSON */
* Amazon Gift Card creationRequestId protected $raw_json = [];
*
* @var string
*/
protected $creation_request_id;
/**
* Amazon Gift Card status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/** /**
* Response constructor. * Response constructor for canceling gitf cards
* @param array $json_response *
* @param array<mixed> $json_response JSON response from web request to AWS
*/ */
public function __construct(array $json_response) public function __construct(array $json_response)
{ {
$this->raw_json = $json_response; $this->raw_json = $json_response;
$this->log = AmazonDebug::getLog(AmazonDebug::getId());
$this->parseJsonResponse($json_response); $this->parseJsonResponse($json_response);
} }
/** /**
* @return array * Get log entry with current set log id
*
* @return array<mixed> Log array
*/ */
public function getLog(): array public function getLog(): array
{ {
return $this->log; return AmazonDebug::getLog(AmazonDebug::getId());
} }
/** /**
* @return string * The gift card id as created by the previous get code call
*
* @return string Gift card id
*/ */
public function getId(): string public function getId(): string
{ {
@@ -64,7 +47,9 @@ class CancelResponse
} }
/** /**
* @return string * Creation Request id from original get code call
*
* @return string Creation request id
*/ */
public function getCreationRequestId(): string public function getCreationRequestId(): string
{ {
@@ -72,7 +57,9 @@ class CancelResponse
} }
/** /**
* @return string * Request status
*
* @return string Request status as string: SUCCESS, FAILURE, RESEND
*/ */
public function getStatus(): string public function getStatus(): string
{ {
@@ -80,28 +67,24 @@ class CancelResponse
} }
/** /**
* @return string * Returns the request data as json string. This is a re-encode from decoded
* makeRequest call
*
* @return string JSON encoded string from the return values
*/ */
public function getRawJson(): string public function getRawJson(): string
{ {
return json_encode($this->raw_json); return (json_encode($this->raw_json)) ?: '';
} }
/** /**
* @param array $json_response * Set class variables with response data from makeRequest and return self
* @return CancelResponse *
* @param array<mixed> $json_response JSON response as array
* @return CancelResponse Return self object
*/ */
public function parseJsonResponse(array $json_response): self public function parseJsonResponse(array $json_response): self
{ {
if (!is_array($json_response)) {
throw AmazonErrors::getError(
'FAILURE',
'E001',
'NonScalarValue',
'Response must be a scalar value',
0
);
}
if (array_key_exists('gcId', $json_response)) { if (array_key_exists('gcId', $json_response)) {
$this->id = $json_response['gcId']; $this->id = $json_response['gcId'];
} }

View File

@@ -2,68 +2,46 @@
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class CreateBalanceResponse class CreateBalanceResponse
{ {
/** /** @var string Amazon Gift Card Balance Amount */
* Amazon Gift Card Balance Amount protected $amount = '';
* /** @var string Amazon Gift Card Balance Currency */
* @var string protected $currency = '';
*/ /** @var string Amazon Gift Card Balance Status */
protected $amount; protected $status = '';
/** /** @var string Amazon Gift Card Balance Timestamp */
* Amazon Gift Card Balance Currency protected $timestamp = '';
* /** @var array<mixed> Amazon Gift Card Raw JSON */
* @var string protected $raw_json = [];
*/
protected $currency;
/**
* Amazon Gift Card Balance Status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Balance Timestamp
*
* @var string
*/
protected $timestamp;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/** /**
* Response constructor. * Response constructor for requesting account funds status
* *
* @param array $json_response * @param array<mixed> $json_response JSON response from web request to AWS
*/ */
public function __construct(array $json_response) public function __construct(array $json_response)
{ {
$this->raw_json = $json_response; $this->raw_json = $json_response;
$this->log = AmazonDebug::getLog(AmazonDebug::getId());
$this->parseJsonResponse($json_response); $this->parseJsonResponse($json_response);
} }
/** /**
* @return array * Get log entry with current set log id
*
* @return array<mixed> Log array
*/ */
public function getLog(): array public function getLog(): array
{ {
return $this->log; return AmazonDebug::getLog(AmazonDebug::getId());
} }
/** /**
* @return string * Return the current available funds amount
*
* @return string Funds amount in set currency
*/ */
public function getAmount(): string public function getAmount(): string
{ {
@@ -71,7 +49,9 @@ class CreateBalanceResponse
} }
/** /**
* @return string * Get the set currency type
*
* @return string Currency type. Eg USD, JPY, etc
*/ */
public function getCurrency(): string public function getCurrency(): string
{ {
@@ -79,15 +59,10 @@ class CreateBalanceResponse
} }
/** /**
* @return string * Get timestamp as set.
*/ * eg 20220609T061446Z
public function getStatus(): string *
{ * @return string Timestamp string. Ymd\THis\Z
return $this->status;
}
/**
* @return string
*/ */
public function getTimestamp(): string public function getTimestamp(): string
{ {
@@ -95,30 +70,34 @@ class CreateBalanceResponse
} }
/** /**
* @return string * Request status
*
* @return string Request status as string: SUCCESS, FAILURE, RESEND
*/ */
public function getRawJson(): string public function getStatus(): string
{ {
return json_encode($this->raw_json); return $this->status;
} }
/** /**
* Undocumented function * Returns the request data as json string. This is a re-encode from decoded
* makeRequest call
* *
* @param array $json_response * @return string JSON encoded string from the return values
* @return CreateBalanceResponse */
public function getRawJson(): string
{
return (json_encode($this->raw_json)) ?: '';
}
/**
* Set class variables with response data from makeRequest and return self
*
* @param array<mixed> $json_response JSON response as array
* @return CreateBalanceResponse Return self object
*/ */
public function parseJsonResponse(array $json_response): self public function parseJsonResponse(array $json_response): self
{ {
if (!is_array($json_response)) {
throw AmazonErrors::getError(
'FAILURE',
'E001',
'NonScalarValue',
'Response must be a scalar value',
0
);
}
if (array_key_exists('amount', $json_response['availableFunds'])) { if (array_key_exists('amount', $json_response['availableFunds'])) {
$this->amount = $json_response['availableFunds']['amount']; $this->amount = $json_response['availableFunds']['amount'];
} }

View File

@@ -2,95 +2,54 @@
namespace gullevek\AmazonIncentives\Response; namespace gullevek\AmazonIncentives\Response;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\AmazonIncentives\Debug\AmazonDebug; use gullevek\AmazonIncentives\Debug\AmazonDebug;
class CreateResponse class CreateResponse
{ {
/** /** @var string Amazon Gift Card gcId */
* Amazon Gift Card gcId. protected $id = '';
* /** @var string Amazon Gift Card creationRequestId */
* @var string protected $creation_request_id = '';
*/ /** @var string Amazon Gift Card gcClaimCode */
protected $id; protected $claim_code = '';
/** @var float Amazon Gift Card amount */
protected $value = 0;
/** @var string Amazon Gift Card currency */
protected $currency = '';
/** @var string Amazon Gift Card status */
protected $status = '';
/** @var string Amazon Gift Card Expiration Date */
protected $expiration_date = '';
/** @var string Amazon Gift Card Expiration Date */
protected $card_status = '';
/** @var array<mixed> Amazon Gift Card Raw JSON as array */
protected $raw_json = [];
/** /**
* Amazon Gift Card creationRequestId * Response constructor for creating gift cards
* *
* @var string * @param array<mixed> $json_response JSON response from web request to AWS
*/
protected $creation_request_id;
/**
* Amazon Gift Card gcClaimCode
*
* @var string
*/
protected $claim_code;
/**
* Amazon Gift Card amount
*
* @var float
*/
protected $value;
/**
* Amazon Gift Card currency
*
* @var string
*/
protected $currency;
/**
* Amazon Gift Card status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Expiration Date
*
* @var string
*/
protected $expiration_date;
/**
* Amazon Gift Card Expiration Date
*
* @var string
*/
protected $card_status;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/**
* Response constructor.
* @param array $json_response
*/ */
public function __construct(array $json_response) public function __construct(array $json_response)
{ {
$this->raw_json = $json_response; $this->raw_json = $json_response;
$this->log = AmazonDebug::getLog(AmazonDebug::getId());
$this->parseJsonResponse($json_response); $this->parseJsonResponse($json_response);
} }
/** /**
* @return array * Get log entry with current set log id
*
* @return array<mixed> Log array
*/ */
public function getLog(): array public function getLog(): array
{ {
return $this->log; return AmazonDebug::getLog(AmazonDebug::getId());
} }
/** /**
* @return string * Gift Card ID returned from AWS. Can be used in the cancel request
*
* @return string Gift card id
*/ */
public function getId(): string public function getId(): string
{ {
@@ -98,7 +57,10 @@ class CreateResponse
} }
/** /**
* @return string * Either the one set with the method parameter, or automatically created
* during get code request
*
* @return string Creation request id
*/ */
public function getCreationRequestId(): string public function getCreationRequestId(): string
{ {
@@ -106,7 +68,10 @@ class CreateResponse
} }
/** /**
* @return string * The actual gift code, recommended not to be stored anywhere and only shown
* to user
*
* @return string Gift order claim code on AWS
*/ */
public function getClaimCode(): string public function getClaimCode(): string
{ {
@@ -114,15 +79,19 @@ class CreateResponse
} }
/** /**
* @return string * The ordered gift code value in given currency
*
* @return float Gift order value in currency
*/ */
public function getValue(): string public function getValue(): float
{ {
return $this->value; return $this->value;
} }
/** /**
* @return string * The currently set currency
*
* @return string Currency type. Eg USD, JPY, etc
*/ */
public function getCurrency(): string public function getCurrency(): string
{ {
@@ -130,15 +99,10 @@ class CreateResponse
} }
/** /**
* @return string * Expiration date for the ordered gift code.
*/ * eg 20220609T061446Z
public function getStatus(): string *
{ * @return string Timestamp until when the gift code is valid. Ymd\THis\Z
return $this->status;
}
/**
* @return string
*/ */
public function getExpirationDate(): string public function getExpirationDate(): string
{ {
@@ -146,37 +110,45 @@ class CreateResponse
} }
/** /**
* @return string * Gift card status. If the same creation request id is sent again and the
* gift card got cancled, this is reflected here
*
* @return string Gift card status
*/ */
public function getCardStatus(): string public function getCardStatus(): string
{ {
return $this->card_status; return $this->card_status;
} }
/**
* Request status
*
* @return string Request status as string: SUCCESS, FAILURE, RESEND
*/
public function getStatus(): string
{
return $this->status;
}
/** /**
* @return string * @Returns the request data as json string. This is a re-encode from decoded
* makeRequest call
*
* @return string JSON encoded string from the return values
*/ */
public function getRawJson(): string public function getRawJson(): string
{ {
return json_encode($this->raw_json); return (json_encode($this->raw_json)) ?: '';
} }
/** /**
* @param array $json_response * Set class variables with response data from makeRequest and return self
* @return CreateResponse *
* @param array<mixed> $json_response JSON response as array
* @return CreateResponse Return self object
*/ */
public function parseJsonResponse(array $json_response): self public function parseJsonResponse(array $json_response): self
{ {
if (!is_array($json_response)) {
throw AmazonErrors::getError(
'FAILURE',
'E001',
'NonScalarValue',
'Response must be a scalar value',
0
);
}
if (array_key_exists('gcId', $json_response)) { if (array_key_exists('gcId', $json_response)) {
$this->id = $json_response['gcId']; $this->id = $json_response['gcId'];
} }

7
test/.env.example Normal file
View File

@@ -0,0 +1,7 @@
# for AWS gift card testing
AWS_GIFT_CARD_ENDPOINT=
AWS_GIFT_CARD_KEY=
AWS_GIFT_CARD_SECRET=
AWS_GIFT_CARD_PARTNER_ID=
AWS_GIFT_CARD_CURRENCY=
AWS_DEBUG=

View File

@@ -0,0 +1,140 @@
# Return data from AWS as json string
## Mock tests self
Tests run in local mock tests without connection to AWS
### funds
```json
{"availableFunds":{"amount":0.0,"currencyCode":"JPY"},"status":"SUCCESS","timestamp":"20220610T085450Z"}
```
### buy
```json
{"cardInfo":{"cardNumber":null,"cardStatus":"Fulfilled","expirationDate":null,"value":{"amount":1000.0,"currencyCode":"JPY"}},"creationRequestId":"PartnerId_62a309167e7a4","gcClaimCode":"LJ49-AKDUV6-UYCP","gcExpirationDate":"Thu Jun 10 14:59:59 UTC 2032","gcId":"5535125272070255","status":"SUCCESS"}
```
### cancel
```json
{"creationRequestId":"EG3bd_62a309167e7a4","gcId":"5535125272070255","status":"SUCCESS"}
```
### buy other 1
```json
{"cardInfo":{"cardNumber":null,"cardStatus":"RefundedToPurchaser","expirationDate":null,"value":{"amount":1000.0,"currencyCode":"JPY"}},"creationRequestId":"PartnerId_62a309167e7a4","gcClaimCode":"LJ49-AKDUV6-UYCP","gcExpirationDate":"Thu Jun 10 14:59:59 UTC 2032","gcId":"5535125272070255","status":"SUCCESS"}
```
### buy aother 2
```json
{"cardInfo":{"cardNumber":null,"cardStatus":"Fulfilled","expirationDate":null,"value":{"amount":1000.0,"currencyCode":"JPY"}},"creationRequestId":"PartnerId_62a30923e9705","gcClaimCode":"UM97-FD5QKK-WKCT","gcExpirationDate":"Thu Jun 10 14:59:59 UTC 2032","gcId":"5540334324324221","status":"SUCCESS"}
```
### buy other 2 (same create request id)
```json
{"cardInfo":{"cardNumber":null,"cardStatus":"Fulfilled","expirationDate":null,"value":{"amount":1000.0,"currencyCode":"JPY"}},"creationRequestId":"PartnerId_62a30923e9705","gcClaimCode":"UM97-FD5QKK-WKCT","gcExpirationDate":"Thu Jun 10 14:59:59 UTC 2032","gcId":"5540334324324221","status":"SUCCESS"}
```
## AWS GCOD Mocks
Mocking on AWS side, these will be returned if given request ID codes are sent.
A working test account must exist for this
## success
### buy gift card F0000
```json
{"cardInfo":{"cardNumber":null,"cardStatus":"Fulfilled","expirationDate":null,"value":{"amount":500.0,"currencyCode":"JPY"}},"creationRequestId":"F0000","gcClaimCode":"ZYXW-VUTS-RQPO","gcExpirationDate":null,"gcId":"ABC123ZYX987","status":"SUCCESS"}
```
## errors
### F1000 -> F100
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F100","errorType":"GeneralError","message":"General Error"}
```
### F2003 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"InvalidAmountInput","message":"Amount can't be null"}
```
### F2004 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"InvalidAmountValue","message":"Amount must be larger than 0"}
```
### F2005 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"InvalidCurrencyCodeInput","message":"Currency Code can't be null or empty"}
```
### F2010 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"CardAlreadyActivatedWithDifferentRequestId","message":"The card was already activated with a different request id"}
```
### F2015 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"MaxAmountExceeded","message":"Max Amount Exceeded"}
```
### F2016 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"CurrencyCodeMismatch","message":"Currency Code Mismatch"}
```
### F2017 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"FractionalAmountNotAllowed","message":"Fractional Amount Not Allowed"}
```
### F2047 -> F200
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F200","errorType":"CancelRequestArrivedAfterTimeLimit","message":"Cancellation cannot be processed as too much time has elapsed since creation"}
```
### F3003 -> F300
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F300","errorType":"InsufficientFunds","message":"Insufficient Funds"}
```
### F3005 -> F300
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F300","errorType":"GeneralError","message":"General Error"}
```
### F3010 -> F300
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F300","errorType":"CustomerSurpassedDailyVelocityLimit","message":"Customer has exceeded daily velocity limit"}
```
### F4000 -> F400
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"RESEND"},"errorCode":"F400","errorType":"SystemTemporarilyUnavailable","message":"System Temporarily Unavailable"}
```
### F5000 -> F500
```json
{"agcodResponse":{"__type":"CreateGiftCardResponse:http://internal.amazon.com/coral/com.amazonaws.agcod/","cardInfo":null,"creationRequestId":null,"gcClaimCode":null,"gcExpirationDate":null,"gcId":null,"status":"FAILURE"},"errorCode":"F500","errorType":"GeneralError","message":"General Error"}
```

View File

@@ -6,7 +6,7 @@
* write log as string from array data * write log as string from array data
* includes timestamp * includes timestamp
* *
* @param array $data Debug log array data to add to the json string * @param array<mixed> $data Debug log array data to add to the json string
* @return string * @return string
*/ */
function writeLog(array $data): string function writeLog(array $data): string
@@ -25,7 +25,7 @@ function writeLog(array $data): string
*/ */
function dateTr(string $date): string function dateTr(string $date): string
{ {
return date('Y-m-d H:i:s', strtotime($date)); return date('Y-m-d H:i:s', (strtotime($date)) ?: null);
} }
/** /**
@@ -33,7 +33,7 @@ function dateTr(string $date): string
* *
* @param string $call_request Call request, eg buyGiftCard * @param string $call_request Call request, eg buyGiftCard
* @param integer $error_code $e Exception error code * @param integer $error_code $e Exception error code
* @param array $error Array from the Exception message json string * @param array<mixed> $error Array from the Exception message json string
* @param boolean $debug_print If we should show the debug log * @param boolean $debug_print If we should show the debug log
* @return void * @return void
*/ */
@@ -57,13 +57,13 @@ $loader = require '../vendor/autoload.php';
// need to add this or it will not load here // need to add this or it will not load here
$loader->addPsr4('gullevek\\', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src'); $loader->addPsr4('gullevek\\', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src');
// print "LOADER: <pre>" . print_r($loader, true) . "</pre>"; // print "LOADER: <pre>" . print_r($loader, true) . "</pre>";
// env file loader (simple)
require 'read_env_file.php';
use gullevek\AmazonIncentives\AmazonIncentives; use gullevek\AmazonIncentives\AmazonIncentives;
use gullevek\AmazonIncentives\Exceptions\AmazonErrors;
use gullevek\dotEnv\DotEnv;
// load env data with dotenv // load env data with dotenv
readEnvFile(__DIR__); DotEnv::readEnvFile(__DIR__);
print "<h1>Amazon Gift Card Incentives</h1><br>"; print "<h1>Amazon Gift Card Incentives</h1><br>";
@@ -76,46 +76,39 @@ print "<h1>Amazon Gift Card Incentives</h1><br>";
// optional // optional
// debug: AWS_DEBUG (if not set: off) // debug: AWS_DEBUG (if not set: off)
// as in .env // run info test (prints ENV vars)
// AWS_GIFT_CARD_ENDPOINT.TEST $run_info_test = !empty($_GET['info']) ? true : false;
// AWS_GIFT_CARD_ENDPOINT.LIVE // run test to get funds info
$run_fund_test = !empty($_GET['fund']) ? true : false;
// run the normal get/cancel gift card tests
$run_gift_tests = !empty($_GET['gift']) ? true : false;
// run mock error check tests
$run_mocks = !empty($_GET['mocks']) ? true : false;
define('LOCATION', 'test'); // should we print debug info
foreach ( $debug_print = !empty($_GET['debug']) ? true : false;
[ // how long to wait between each call
'AWS_GIFT_CARD_KEY', 'AWS_GIFT_CARD_SECRET', 'AWS_GIFT_CARD_PARTNER_ID', $debug_wait = 2;
'AWS_GIFT_CARD_ENDPOINT', 'AWS_GIFT_CARD_CURRENCY', 'AWS_DEBUG' // if set to true will print all the debug logs too
] as $key $mock_debug = !empty($_GET['debug_mock']) ? true : false;
) { // wait in seconds between mock tests
// $mock_wait = 2;
$_ENV[$key] = $_ENV[$key . '.' . strtoupper((LOCATION))] ?? $_ENV[$key] ?? '';
if (empty($_GET)) {
print "<b>Use _GET parameters to start tests</b>";
} }
// open debug file output // open debug file output
$fp = fopen('log/debug.' . date('YmdHis') . '.log', 'w'); $fp = fopen('log/debug.' . date('YmdHis') . '.log', 'w');
if (!is_resource($fp)) {
// run info test (prints ENV vars) die("Cannot open log debug file");
$run_info_test = false; }
// run test to get funds info
$run_fund_test = true;
// run the normal get/cancel gift card tests
$run_gift_tests = true;
// run mock error check tests
$run_mocks = false;
// should we print debug info
$debug_print = false;
// how long to wait between each call
$debug_wait = 2;
// if set to true will print all the debug logs too
$mock_debug = false;
// wait in seconds between mock tests
$mock_wait = 2;
if ($run_info_test === true) { if ($run_info_test === true) {
$aws = new AmazonIncentives(); $aws = new AmazonIncentives();
print "checkMe: <pre>" . print_r($aws->checkMe(), true) . "</pre>"; $aws_check_me = $aws->checkMe();
fwrite($fp, writeLog($aws->checkMe())); print "checkMe: <pre>" . print_r($aws_check_me, true) . "</pre>";
fwrite($fp, writeLog($aws_check_me));
print "<hr>"; print "<hr>";
} }
@@ -132,7 +125,7 @@ if ($run_fund_test === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (Exception $e) { } catch (Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
printException('getAvailableFunds', $e->getCode(), $error, $debug_print); printException('getAvailableFunds', $e->getCode(), $error, $debug_print);
fwrite($fp, writeLog($error)); fwrite($fp, writeLog($error));
}; };
@@ -164,7 +157,7 @@ if ($run_gift_tests === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (\Exception $e) { } catch (\Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
printException('buyGiftCard', $e->getCode(), $error, $debug_print); printException('buyGiftCard', $e->getCode(), $error, $debug_print);
fwrite($fp, writeLog($error)); fwrite($fp, writeLog($error));
} }
@@ -181,7 +174,7 @@ if ($run_gift_tests === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (\Exception $e) { } catch (\Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
print "AWS: cancelGiftCard: " . $error['status'] print "AWS: cancelGiftCard: " . $error['status']
. " [" . $e->getCode() . "]: " . " [" . $e->getCode() . "]: "
. $error['code'] . " | " . $error['type'] . $error['code'] . " | " . $error['type']
@@ -193,6 +186,28 @@ if ($run_gift_tests === true) {
} }
print "<br>"; print "<br>";
sleep($debug_wait); sleep($debug_wait);
// request same card again and get error
try {
$aws_test = AmazonIncentives::make()->buyGiftCard((float)$value, $creation_request_id);
$request_status = $aws_test->getStatus();
// same?
$claim_code = $aws_test->getClaimCode();
$expiration_date = $aws_test->getExpirationDate();
print "AWS: buyGiftCard: CANCLED SAME CODE AGAIN: " . $request_status . ": "
. "creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . ", "
. "EXPIRE DATE: <b>" . dateTr($expiration_date) . "</b>, "
. "CLAIM CODE: <b>" . $claim_code . "</b>";
if ($debug_print === true) {
print "<pre>" . print_r($aws_test, true) . "</pre>";
}
fwrite($fp, writeLog((array)$aws_test));
} catch (\Exception $e) {
$error = AmazonErrors::decodeExceptionMessage($e->getMessage());
printException('buyGiftCard', $e->getCode(), $error, $debug_print);
fwrite($fp, writeLog($error));
}
print "<br>";
sleep($debug_wait);
// set same request ID twice to get same response test // set same request ID twice to get same response test
try { try {
@@ -211,7 +226,7 @@ if ($run_gift_tests === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (\Exception $e) { } catch (\Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
printException('cancelGiftCard', $e->getCode(), $error, $debug_print); printException('cancelGiftCard', $e->getCode(), $error, $debug_print);
fwrite($fp, writeLog($error)); fwrite($fp, writeLog($error));
} }
@@ -221,6 +236,7 @@ if ($run_gift_tests === true) {
$aws_test = AmazonIncentives::make()->buyGiftCard((float)$value, $creation_request_id); $aws_test = AmazonIncentives::make()->buyGiftCard((float)$value, $creation_request_id);
$request_status = $aws_test->getStatus(); $request_status = $aws_test->getStatus();
// same? // same?
$claim_code = $aws_test->getClaimCode();
$expiration_date = $aws_test->getExpirationDate(); $expiration_date = $aws_test->getExpirationDate();
print "AWS: buyGiftCard: SAME CODE A AGAIN: " . $request_status . ": " print "AWS: buyGiftCard: SAME CODE A AGAIN: " . $request_status . ": "
. "creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . ", " . "creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . ", "
@@ -231,7 +247,7 @@ if ($run_gift_tests === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (\Exception $e) { } catch (\Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
printException('buyGiftCard', $e->getCode(), $error, $debug_print); printException('buyGiftCard', $e->getCode(), $error, $debug_print);
fwrite($fp, writeLog($error)); fwrite($fp, writeLog($error));
} }
@@ -241,10 +257,11 @@ if ($run_gift_tests === true) {
} }
// MOCK TEST // MOCK TEST
if ($mock_debug === true) { if ($run_mocks === true) {
$mock_ok = '<span style="color:green;">MOCK OK</span>'; $mock_ok = '<span style="color:green;">MOCK OK</span>';
$mock_failure = '<span style="color:red;">MOCK FAILURE</span>'; $mock_failure = '<span style="color:red;">MOCK FAILURE</span>';
$mock_value = 500; $mock_value = 500;
$mock = [];
$mock['F0000'] = [ 'ret' => '', 'st' => 'SUCCESS']; // success mock $mock['F0000'] = [ 'ret' => '', 'st' => 'SUCCESS']; // success mock
$mock['F1000'] = [ 'ret' => 'F100', 'st' => 'FAILURE']; // SimpleAmountIsNull, etc $mock['F1000'] = [ 'ret' => 'F100', 'st' => 'FAILURE']; // SimpleAmountIsNull, etc
@@ -283,7 +300,7 @@ if ($mock_debug === true) {
} }
fwrite($fp, writeLog((array)$aws_test)); fwrite($fp, writeLog((array)$aws_test));
} catch (Exception $e) { } catch (Exception $e) {
$error = AmazonIncentives::decodeExceptionMessage($e->getMessage()); $error = AmazonErrors::decodeExceptionMessage($e->getMessage());
print "AWS: MOCK: " . $creation_id . ": buyGiftCard: " . $error['status'] print "AWS: MOCK: " . $creation_id . ": buyGiftCard: " . $error['status']
. " [" . $e->getCode() . "]: " . " [" . $e->getCode() . "]: "
. $error['code'] . " | " . $error['type'] . $error['code'] . " | " . $error['type']

View File

@@ -0,0 +1,23 @@
<?php
// just print out env data nd connect data
// checkMe from AmazonIntentives call is requal to
// run_info_test === true in aws_gift_card_tests.php
$loader = require '../vendor/autoload.php';
// need to add this or it will not load here
$loader->addPsr4('gullevek\\', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src');
// print "LOADER: <pre>" . print_r($loader, true) . "</pre>";
use gullevek\AmazonIncentives\AmazonIncentives;
use gullevek\dotEnv\DotEnv;
// load env data with dotenv
DotEnv::readEnvFile(__DIR__);
print "_ENV: <pre>" . print_r($_ENV, true) . "</pre>";
$aws = new AmazonIncentives();
print "checkMe: <pre>" . print_r($aws->checkMe(), true) . "</pre>";
// __END__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
<?php
// strip the final name from a to be mocked class
declare(strict_types=1);
namespace test\phpUnit\Hook;
use DG\BypassFinals;
use PHPUnit\Runner\BeforeFirstTestHook;
// only works if it is the FIRST load and not before EACH test
final class BypassFinalHook implements BeforeFirstTestHook
{
public function executeBeforeFirstTest(): void
{
BypassFinals::enable();
}
}
// __END__

View File

@@ -1,84 +0,0 @@
<?php
/**
* parses .env file
*
* Rules for .env file
* variable is any alphanumeric string followed by = on the same line
* content starts with the first non space part
* strings can be contained in "
* strings MUST be contained in " if they are multiline
* if string starts with " it will match until another " is found
* anything AFTER " is ignored
* if there are two variables with the same name only the first is used
* variables are case sensitive
*
* @param string $path Folder to file, default is __DIR__
* @param string $env_file What file to load, default is .env
* @return int -1 other error
* 0 for success full load
* 1 for file loadable, but no data inside
* 2 for file not readable
* 3 for file not found
*/
function readEnvFile(string $path = __DIR__, string $env_file = '.env'): int
{
// default -1;
$status = -1;
$env_file_target = $path . DIRECTORY_SEPARATOR . $env_file;
// this is not a file -> abort
if (!is_file($env_file_target)) {
$status = 3;
return $status;
}
// cannot open file -> abort
if (($fp = fopen($env_file_target, 'r')) === false) {
$status = 2;
return $status;
}
// set to readable but not yet any data loaded
$status = 1;
$block = false;
$var = '';
while ($line = fgets($fp)) {
// main match for variable = value part
if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
$var = $matches[1];
$value = $matches[2];
$quotes = $matches[3];
// wirte only if env is not set yet, and write only the first time
if (empty($_ENV[$var])) {
if (!empty($quotes)) {
// match greedy for first to last so we move any " if there are
if (preg_match('/^"(.*[^\\\])"/U', $value, $matches)) {
$value = $matches[1];
} else {
// this is a multi line
$block = true;
// first " in string remove
// add removed new line back because this is a multi line
$value = ltrim($value, '"') . PHP_EOL;
}
}
// if block is set, we strip line of slashes
$_ENV[$var] = $block === true ? stripslashes($value) : $value;
// set successful load
$status = 0;
}
} elseif ($block === true) {
// read line until there is a unescaped "
// this also strips everything after the last "
if (preg_match("/(.*[^\\\])\"/", $line, $matches)) {
$block = false;
// strip ending " and EVERYTHING that follows after that
$line = $matches[1];
}
// strip line of slashes
$_ENV[$var] .= stripslashes($line);
}
}
fclose($fp);
return $status;
}
// __END__

7
vendor/autoload.php vendored
View File

@@ -1,7 +0,0 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit0c8f6bec90a6d60040a922f19a1f0e64::getLoader();

View File

@@ -1,572 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

View File

@@ -1,21 +0,0 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,10 +0,0 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -1,9 +0,0 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -1,10 +0,0 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'gullevek\\AmazonIncentives\\' => array($baseDir . '/src'),
);

View File

@@ -1,55 +0,0 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit0c8f6bec90a6d60040a922f19a1f0e64
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit0c8f6bec90a6d60040a922f19a1f0e64', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit0c8f6bec90a6d60040a922f19a1f0e64', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit0c8f6bec90a6d60040a922f19a1f0e64::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
return $loader;
}
}

View File

@@ -1,36 +0,0 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit0c8f6bec90a6d60040a922f19a1f0e64
{
public static $prefixLengthsPsr4 = array (
'G' =>
array (
'gullevek\\AmazonIncentives\\' => 26,
),
);
public static $prefixDirsPsr4 = array (
'gullevek\\AmazonIncentives\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit0c8f6bec90a6d60040a922f19a1f0e64::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit0c8f6bec90a6d60040a922f19a1f0e64::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit0c8f6bec90a6d60040a922f19a1f0e64::$classMap;
}, null, ClassLoader::class);
}
}