Skip to content

Commit c892e77

Browse files
authored
app uninstall webhook support
* added webhook resource added a snippet for app uninstalled job * updated readme
1 parent 72c10db commit c892e77

15 files changed

+458
-9
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ Homestead.json
88
.idea/*
99
/.phpcomplete_extended
1010
tests/_output/*
11-
composer.lock
11+
composer.lock
12+
/**/*.DS_Store

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ in your `.env` file set these values from your app
4848

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

51-
`php artisan vendor:publish --tag=shopify-config`
51+
`php artisan vendor:publish --tag=shopify-config`
5252

5353
This will create a shopify.php file in the config directory. You will need to set your **API_KEY** and **SECRET**
5454
```
@@ -100,10 +100,21 @@ Route::get("process_oauth_result",function(\Illuminate\Http\Request $request)
100100

101101
dd($accessToken);
102102
//store the access token for future api calls on behalf of the shop
103+
103104
// redirect to success page or billing etc.
104105
});
105106
```
106107

108+
To make the code less verbose we have added a app uninstalled job which can be subscribed via the app uninstalled webhook from shopify that can be configured automatically from your shop
109+
110+
After installation dispatch this job
111+
112+
```php5
113+
SubscribeAppUninstalledWebhookJob::dispatch($shop);
114+
```
115+
which will subscribe to the `app/uninstalled` webhook
116+
under `/webhooks/shopify/uninstalled` route and will
117+
107118
To verify request(hmac)
108119

109120
```php5
@@ -227,14 +238,26 @@ Shopify::getStatusCode(); // 200
227238
Shopify::getReasonPhrase(); // ok
228239
```
229240

241+
Optional features
230242

243+
We also have a middleware for verifying the webhooks
244+
you can directly use it in your webhooks by the name `verify.webhook`
231245

232246

247+
We have also added a automatic app uninstalled job dispatch when app is uninstalled by subscribing to the webhook topic `app/uninstalled`.
248+
To configure this you need to implement the interface `Shopify/Contracts/ShopifyShop` in your shop model and then
233249

250+
```php5
251+
SubscribeAppUninstalledWebhookJob::dispatch($shop);
252+
```
234253

254+
To customize the AppUninstalled Job
255+
Publish it by
256+
`php artisan vendor:publish --tag=shopify-jobs`
235257

236-
237-
258+
You might not need this
259+
We also dispatch events for webhooks if it is not for uninstalled topic for the same webhook
260+
`ClarityTech\Shopify\Events\ShopifyWebhookRecieved`
238261

239262

240263

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
],
1111
"require": {
1212
"php": ">=7.3.0",
13-
"illuminate/support": "^7.0|^8.0",
13+
"laravel/framework": "^7.0|^8.0",
1414
"psr/http-message": "^1.0"
1515
},
1616
"autoload": {

src/Shopify/Api/CarrierService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class CarrierService extends Entity
88
/**
99
* @param array $params
1010
*
11-
* @return ClarityTech\Shopify\Api\Shop
11+
* @return ClarityTech\Shopify\Api\CarrierService
1212
*/
1313
public function fetch(array $params = [])
1414
{

src/Shopify/Api/Webhook.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace ClarityTech\Shopify\Api;
4+
5+
class Webhook extends Entity
6+
{
7+
8+
/**
9+
* Retrieve a single webhook
10+
* @param array $params
11+
*
12+
* @return ClarityTech\Shopify\Api\Webhook
13+
*/
14+
public function fetch(array $params = [])
15+
{
16+
return parent::fetch($params);
17+
}
18+
//GET https://shopify.dev/docs/admin-api/rest/reference/events/webhook#show-2020-10
19+
20+
/**
21+
* Retrieve a list of webhooks
22+
* @param array $params
23+
*
24+
* @return ClarityTech\Shopify\Api\Webhook
25+
*/
26+
public function all(array $params = [])
27+
{
28+
return parent::all($params);
29+
}
30+
31+
/**
32+
* @param $id Order id description
33+
*/
34+
public function create(array $attributes = [])
35+
{
36+
return parent::create($attributes);
37+
}
38+
//https://shopify.dev/docs/admin-api/rest/reference/events/webhook#create-2020-10
39+
}

src/Shopify/Contracts/ShopifyShop.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace ClarityTech\Shopify\Contracts;
4+
5+
interface ShopifyShop
6+
{
7+
public function getShopifyId() : int;
8+
9+
public function getShopToken() : string;
10+
11+
public function getShopifyDomain() : string;
12+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace ClarityTech\Shopify\Events;
4+
5+
use Illuminate\Broadcasting\InteractsWithSockets;
6+
use Illuminate\Foundation\Events\Dispatchable;
7+
use Illuminate\Queue\SerializesModels;
8+
9+
class ShopifyWebhookRecieved
10+
{
11+
use Dispatchable, InteractsWithSockets, SerializesModels;
12+
13+
14+
/**
15+
* The myshoipify domain.
16+
*
17+
*/
18+
public string $shopDomain;
19+
20+
/**
21+
* The shopify webhook topic.
22+
*
23+
*/
24+
public string $topic;
25+
26+
/**
27+
* The webhook payload.
28+
*
29+
*/
30+
public array $payload = [];
31+
32+
/**
33+
* Create a new event instance.
34+
*
35+
* @return void
36+
*/
37+
public function __construct(string $shopDomain, string $topic, array $payload)
38+
{
39+
$this->shopDomain = $shopDomain;
40+
$this->topic = $topic;
41+
$this->payload = $payload;
42+
}
43+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace ClarityTech\Shopify\Http\Controllers;
4+
5+
use ClarityTech\Shopify\Events\ShopifyWebhookRecieved;
6+
use ClarityTech\Shopify\Shopify;
7+
use Illuminate\Http\Request;
8+
use Illuminate\Http\Response;
9+
use Illuminate\Routing\Controller;
10+
11+
/**
12+
* Responsible for handling incoming webhook requests.
13+
*/
14+
class ShopifyWebhookController extends Controller
15+
{
16+
public function handle(Request $request) : Response
17+
{
18+
// validation
19+
$topic = $request->header('x-shopify-topic');
20+
$shopDomain = $request->header('x-shopify-shop-domain');
21+
$shopifyId = $request->get('id');
22+
23+
$payload = $request->all();
24+
25+
if ($topic == Shopify::UNINSTALL_TOPIC) {
26+
$jobClass = config('shopify.uninstall.job');
27+
// AppUninstalledJob::dispatch($shopifyId, $shopDomain, $payload);
28+
$jobClass::dispatch($shopifyId, $shopDomain, $payload);
29+
} else {
30+
ShopifyWebhookRecieved::dispatch($shopDomain, $topic, $payload);
31+
}
32+
33+
return new Response('', 200);
34+
}
35+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace ClarityTech\Shopify\Http\Middleware;
4+
5+
use ClarityTech\Shopify\Facades\Shopify;
6+
use Closure;
7+
use Illuminate\Http\Request;
8+
use Illuminate\Support\Facades\Response;
9+
10+
/**
11+
* Response for ensuring a proper webhook request.
12+
*/
13+
class VerifyShopifyWebhook
14+
{
15+
16+
/**
17+
* Handle an incoming request to ensure webhook is valid.
18+
*
19+
* @param Request $request The request object.
20+
* @param \Closure $next The next action.
21+
*
22+
* @return mixed
23+
*/
24+
public function handle(Request $request, Closure $next)
25+
{
26+
$hmac = $request->header('x-shopify-hmac-sha256') ?: '';
27+
$data = $request->getContent();
28+
29+
$result = Shopify::verifyWebHook($data, $hmac);
30+
31+
if ($result) {
32+
// All good, process webhook
33+
return $next($request);
34+
}
35+
36+
return Response::make('Invalid webhook signature.', 401);
37+
}
38+
}

src/Shopify/Http/routes.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
use ClarityTech\Shopify\Http\Controllers\ShopifyWebhookController;
4+
use Illuminate\Support\Facades\Route;
5+
6+
/*
7+
|--------------------------------------------------------------------------
8+
| Webhook Entries
9+
|--------------------------------------------------------------------------
10+
|
11+
| Handles incoming webhooks for now app uninstalled is automatically handled.
12+
|
13+
*/
14+
15+
16+
Route::post('/uninstalled', [ShopifyWebhookController::class, 'handle'])
17+
->middleware('verify.webhook')
18+
->name('shopify.uninstalled.webhook');

0 commit comments

Comments
 (0)