Skip to content

Commit

Permalink
replaced guzzlehttp with illuminate support http
Browse files Browse the repository at this point in the history
  • Loading branch information
msonowal committed Nov 12, 2020
1 parent 2531480 commit 72c10db
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 86 deletions.
33 changes: 19 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ in your `.env` file set these values from your app
`SHOPIFY_APIKEY=your-api-key`
`SHOPIFY_SECRET=your-secret-key`

## Optional Configuration
## Optional Configuration (publishing)

Laravel Shopify requires api key configuration. You will need to publish configs assets

Expand Down Expand Up @@ -95,6 +95,8 @@ Route::get("process_oauth_result",function(\Illuminate\Http\Request $request)
$token = $shopifyApi
->setShopDomain($myShopifyDomain)
->getAccessToken($code);
//this gets access token from shopify and set it to the current instance which will be passed in further api calls


dd($accessToken);
//store the access token for future api calls on behalf of the shop
Expand All @@ -105,11 +107,13 @@ Route::get("process_oauth_result",function(\Illuminate\Http\Request $request)
To verify request(hmac)

```php5
use ClarityTech\Shopify\Facades\Shopify;

public function verifyRequest(Request $request)
{
$queryString = $request->getQueryString();
$params = $request->all();

if(Shopify::verifyRequest($queryString)){
if (Shopify::verifyRequest($params)){
logger("verification passed");
}else{
logger("verification failed");
Expand All @@ -121,11 +125,12 @@ public function verifyRequest(Request $request)
To verify webhook(hmac)

```php5
use ClarityTech\Shopify\Facades\Shopify;

public function verifyWebhook(Request $request)
{
$data = $request->getContent();
$hmacHeader = $request->server('HTTP_X_SHOPIFY_HMAC_SHA256');
$hmacHeader = $request->header('x-shopify-hmac-sha256');

if (Shopify::verifyWebHook($data, $hmacHeader)) {
logger("verification passed");
Expand All @@ -150,17 +155,19 @@ Let use our access token to get products from shopify.
**NB:** You can use this to access any resource on shopify (be it Product, Shop, Order, etc)

```php5
use ClarityTech\Shopify\Facades\Shopify;

$shopUrl = "example.myshopify.com";
$accessToken = "xxxxxxxxxxxxxxxxxxxxx";
$products = Shopify::setShopUrl($shopUrl)->setAccessToken($accessToken)->get("admin/products.json");
$accessToken = "xxxxxxxxxxxxxxxxxxxxx"; //retrieve from your storage(db)
$products = Shopify::setShop($myShopifyDomain, $accessToken)->get("admin/products.json");
```

To pass query params

```php5
// returns Collection
$shopify = Shopify::setShopUrl($shopUrl)->setAccessToken($accessToken);
$products = $shopify->get("admin/products.json", ["limit"=>20, "page" => 1]);
Shopify::setShop($myShopifyDomain, $accessToken);
$products = Shopify::get('admin/products.json', ["limit"=>20, "page" => 1]);
```

## Controller Example
Expand All @@ -181,17 +188,15 @@ class Foo
}

/*
* returns Collection
* returns products
*/
public function getProducts(Request $request)
{
$products = $this->shopify->setShopUrl($shopUrl)
->setAccessToken($accessToken)
$accessToken = 'xxxxxxxxxxxxxxxxxxxxx';//retrieve from your storage(db)
$products = $this->shopify->setShop($request->shop, $accessToken)
->get('admin/products.json');

$products->each(function($product){
\Log::info($product->title);
});
dump($products);
}
}
```
Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
],
"require": {
"php": ">=7.3.0",
"guzzlehttp/guzzle": "^7.0.1",
"illuminate/support": "^7.0|^8.0"
"illuminate/support": "^7.0|^8.0",
"psr/http-message": "^1.0"
},
"autoload": {
"psr-4": {
Expand All @@ -28,6 +28,9 @@
}
}
},
"suggest": {
"guzzlehttp/guzzle": "Must Required to use the HTTP Client."
},
"config": {
"preferred-install": "dist"
}
Expand Down
2 changes: 2 additions & 0 deletions src/Shopify/Api/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ protected function request(string $method, $entityUrl, array $params = [])

$response = Shopify::$method($url, $params);

//$response = $response->json();

return static::buildEntity($response);
}

Expand Down
164 changes: 96 additions & 68 deletions src/Shopify/Shopify.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,43 @@

namespace ClarityTech\Shopify;

use GuzzleHttp\Client;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use ClarityTech\Shopify\Exceptions\ShopifyApiException;
use ClarityTech\Shopify\Exceptions\ShopifyApiResourceNotFoundException;
use Psr\Http\Message\ResponseInterface;

class Shopify
{
protected Client $client;

protected static ?string $key = null;
protected static ?string $secret = null;
protected static ?string $shopDomain = null;
protected static ?string $accessToken = null;

public const VERSION = '2020-01';
public const PREFIX = 'admin/api/';

public bool $debug = false;

protected array $requestHeaders = [];
protected array $responseHeaders = [];
protected $responseStatusCode;
protected $reasonPhrase;

public function __construct(Client $client)
// public function __construct(Client $client)
// {
// $this->client = $client;
// self::$key = Config::get('shopify.key');
// self::$secret = Config::get('shopify.secret');
// }
public function __construct()
{
$this->client = $client;
self::$key = Config::get('shopify.key');
self::$secret = Config::get('shopify.secret');
}

//use Illuminate\Support\Facades\Http;

public function api()
{
return $this;
Expand Down Expand Up @@ -133,9 +141,13 @@ public function getAccessToken(string $code)

$response = $this->makeRequest('POST', $uri, $payload);

$this->setAccessToken($response);
$response = $response->json();

$accessToken = $response['access_token'] ?? null;

$this->setAccessToken($accessToken);

return $response ?? '';
return $accessToken ?? '';
}

public function setAccessToken($accessToken)
Expand All @@ -152,7 +164,12 @@ public function setShop(string $domain, string $accessToken)
return $this;
}

protected function getXShopifyAccessToken() : array
public function isTokenSet() : bool
{
return !is_null(self::$accessToken);
}

protected function getXShopifyAccessTokenHeader() : array
{
return ['X-Shopify-Access-Token' => self::$accessToken];
}
Expand All @@ -171,78 +188,94 @@ public function removeHeaders() : self
return $this;
}

public function setDebug(bool $status = true)
{
$this->debug = $status;

return $this;
}

/*
* $args[0] is for route uri and $args[1] is either request body or query strings
*/
public function __call($method, $args)
{
list($uri, $params) = [ltrim($args[0], "/"), $args[1] ?? []];
$response = $this->makeRequest($method, $uri, $params, $this->getXShopifyAccessToken());
list($uri, $params) = [ltrim($args[0], '/'), $args[1] ?? []];
$response = $this->makeRequest($method, $uri, $params);

if (is_array($array = $response->json()) && count($array) == 1) {
return array_shift($array);
}

//return (is_array($response)) ? $this->convertResponseToCollection($response) : $response;
return $response;
}

public function makeRequest(string $method, string $path, array $params = [], array $headers = [])
public function getHeadersForSend() : array
{
$query = in_array($method, ['get','delete']) ? 'query' : 'json';
$headers = [];

$rateLimit = explode('/', $this->getHeader('X-Shopify-Shop-Api-Call-Limit'));

if ($rateLimit[0] >= 38) {
sleep(15);
if ($this->isTokenSet()) {
$headers = $this->getXShopifyAccessTokenHeader();
}
return array_merge($headers, $this->requestHeaders);
}

public function makeRequest(string $method, string $path, array $params = [])
{
//TODO apply ratelimit or handle it outside from caller function
// aso that we can have more control when we can retry etc

$url = self::getBaseUrl() . $path;

$response = $this->client
->request(strtoupper($method), $url, [
'headers' => array_merge($headers, $this->requestHeaders),
$query => $params,
'timeout' => 120.0,
'connect_timeout' => 120.0,
'http_errors' => false,
"verify" => false
]);

$this->parseResponse($response);
$responseBody = $this->responseBody($response);

logger('shopify request ENDPOINT '. $url);
logger('shopify request params ', (array) $params);
logger('shopify request requestHeaders ', (array) array_merge($headers, $this->requestHeaders));

if (isset($responseBody['errors']) || $response->getStatusCode() >= 400) {
logger('shopify error responseheaders ', (array) $this->responseHeaders);
logger('shopify error response ', (array) $responseBody);

if (! is_null($responseBody)) {
$errors = is_array($responseBody['errors'])
? json_encode($responseBody['errors'])
: $responseBody['errors'];

if ($response->getStatusCode() == 404) {
throw new ShopifyApiResourceNotFoundException(
$errors ?? $response->getReasonPhrase(),
$response->getStatusCode()
);
}
}
$method = strtolower($method);

throw new ShopifyApiException(
$errors ?? $response->getReasonPhrase(),
$response->getStatusCode()
);
$response = Http::withOptions(['debug' => $this->debug,])
->withHeaders($this->getHeadersForSend())
->$method($url, $params);

$this->parseResponse($response->toPsrResponse());

if ($response->successful()) {
return $response;
}

return (is_array($responseBody) && (count($responseBody) > 0)) ? array_shift($responseBody) : $responseBody;
return $this->throwErrors($response);
}

protected function parseResponse(ResponseInterface $response)
{
$this
->setResponseHeaders($response->getHeaders())
->setStatusCode($response->getStatusCode())
->setReasonPhrase($response->getReasonPhrase());
}

private function parseResponse($response)
protected function throwErrors($httpResponse)
{
$this->parseHeaders($response->getHeaders());
$this->setStatusCode($response->getStatusCode());
$this->setReasonPhrase($response->getReasonPhrase());
$response = $httpResponse->json();
$psrResponse = $httpResponse->toPsrResponse();

$statusCode = $psrResponse->getStatusCode();

if (isset($response['errors']) || $statusCode >= 400) {
$errorString = null;

if (!is_null($response)) {
$errorString = is_array($response['errors']) ? json_encode($response['errors']) : $response['errors'];
}

if ($statusCode == 404) {
throw new ShopifyApiResourceNotFoundException(
$errorString ?? $psrResponse->getReasonPhrase(),
$statusCode
);
}

throw new ShopifyApiException(
$errorString ?? $psrResponse->getReasonPhrase(),
$statusCode
);
}
}

public function verifyRequest($queryParams)
Expand Down Expand Up @@ -287,6 +320,7 @@ public function verifyWebHook($data, $hmacHeader) : bool
private function setStatusCode($code)
{
$this->responseStatusCode = $code;
return $this;
}

public function getStatusCode()
Expand All @@ -304,11 +338,10 @@ public function getReasonPhrase()
return $this->reasonPhrase;
}

private function parseHeaders($headers)
private function setResponseHeaders($headers)
{
foreach ($headers as $name => $values) {
$this->responseHeaders = array_merge($this->responseHeaders, [$name => implode(', ', $values)]);
}
$this->responseHeaders = $headers;
return $this;
}

public function getHeaders()
Expand All @@ -325,9 +358,4 @@ public function hasHeader($header)
{
return array_key_exists($header, $this->responseHeaders);
}

private function responseBody($response)
{
return json_decode($response->getBody(), true);
}
}
3 changes: 1 addition & 2 deletions src/Shopify/ShopifyServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace ClarityTech\Shopify;

use GuzzleHttp\Client;
use Illuminate\Support\ServiceProvider;

class ShopifyServiceProvider extends ServiceProvider
Expand Down Expand Up @@ -41,7 +40,7 @@ public function register()
$this->mergeConfigFrom(__DIR__.'/../config/shopify.php', 'shopify');

$this->app->singleton('shopify', function ($app) {
return new Shopify(new Client);
return new Shopify();
});
}

Expand Down

0 comments on commit 72c10db

Please sign in to comment.