<?php namespace Xentral\Modules\AmazonVendorDF; use Aws\Credentials\Credentials; use Aws\Signature\SignatureV4; use GuzzleHttp\Client; use GuzzleHttp\ClientInterface; use GuzzleHttp\HandlerStack; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Xentral\Modules\AmazonVendorDF\Data\Token; use Xentral\Modules\AmazonVendorDF\Service\InventoryService; use Xentral\Modules\AmazonVendorDF\Service\InvoiceService; use Xentral\Modules\AmazonVendorDF\Service\PurchaseOrderService; use Xentral\Modules\AmazonVendorDF\Service\ShippingService; use Xentral\Modules\AmazonVendorDF\Service\TokenService; use Xentral\Modules\AmazonVendorDF\Service\TransactionService; class ServiceFactory { const API_BASE_URL = 'https://sellingpartnerapi-eu.amazon.com'; /** @var TokenService */ private $tokenService; /** @var Token */ private $token; /** @var string */ private $refreshToken; /** @var string */ private $clientId; /** @var string */ private $clientSecret; /** @var SignatureV4 */ private $signature; /** @var Credentials */ private $credentials; /** @var ClientInterface */ private $authenticatedClient; /** @var LoggerInterface */ private $logger; public function __construct( string $refreshToken, string $clientId, string $clientSecret, string $awsIamKey, string $awsIamSecret, LoggerInterface $logger ) { $this->tokenService = new TokenService(new Client()); $this->refreshToken = $refreshToken; $this->clientId = $clientId; $this->clientSecret = $clientSecret; $this->signature = new SignatureV4('execute-api', 'eu-west-1'); $this->credentials = new Credentials($awsIamKey, $awsIamSecret); $this->logger = $logger; } public function getShippingService(): ShippingService { return new ShippingService($this->getAuthenticatedClient()); } public function getInvoiceService(): InvoiceService { return new InvoiceService($this->getAuthenticatedClient()); } public function getInventoryService(): InventoryService { return new InventoryService($this->getAuthenticatedClient()); } public function getPurchaseOrderService(): PurchaseOrderService { return new PurchaseOrderService($this->getAuthenticatedClient()); } public function getTransactionService(): TransactionService { return new TransactionService($this->getAuthenticatedClient()); } private function getAuthenticatedClient(): ClientInterface { if (!$this->authenticatedClient || $this->getToken()->isExpired()) { $stack = HandlerStack::create(); $stack->push($this->getSignatureMiddleware()); $stack->push($this->getLoggingMiddleWare()); $this->authenticatedClient = new Client( [ 'handler' => $stack, 'base_uri' => self::API_BASE_URL, 'headers' => [ 'x-amz-access-token' => $this->getToken()->getAccessToken(), ], ] ); } return $this->authenticatedClient; } private function getSignatureMiddleware() { return function (callable $handler) { return function (RequestInterface $request, array $options) use ($handler) { return $handler($this->signature->signRequest($request, $this->credentials), $options); }; }; } private function getLoggingMiddleWare() { return function (callable $handler) { return function (RequestInterface $request, array $options) use ($handler) { $promise = $handler($request, $options); return $promise->then( function (ResponseInterface $response) use ($request) { $this->logRequestAndResponse($request, $response, LogLevel::DEBUG); return $response; }, function (ResponseInterface $response) use ($request) { $this->logRequestAndResponse($request, $response, LogLevel::ERROR); return $response; } ); }; }; } private function logRequestAndResponse(RequestInterface $request, ResponseInterface $response, string $level) { $request->getBody()->rewind(); $this->logger->log( $level, 'Amazon Vendor DF API request', [ 'request' => [ 'uri' => (string)$request->getUri(), 'method' => $request->getMethod(), 'body' => json_decode($request->getBody()->getContents(), true), ], 'response' => [ 'status_code' => $response->getStatusCode(), 'headers' => $response->getHeaders(), 'body' => json_decode($response->getBody()->getContents(), true), ], ] ); $response->getBody()->rewind(); } private function getToken() { if (!$this->token) { $this->token = $this->tokenService->requestToken($this->refreshToken, $this->clientId, $this->clientSecret); } return $this->token; } }