Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Driver based webhook call storage #30

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,35 @@ This is the contents of the file that will be published at `config/webhook-clien

```php
return [
'storage' => [
/*
* Default webhook storage driver.
*/
'default' => env('WEBHOOK_CLIENT_STORAGE', 'eloquent'),

/*
* List of webhook storage drivers.
* Supported drivers: eloquent, memory, cache
*/
'config' => [
'eloquent' => [
'driver' => 'eloquent',
'model' => env('WEBHOOK_CLIENT_ELOQUENT_MODEL', Spatie\WebhookClient\Models\EloquentWebhookCall::class),
],

'memory' => [
'driver' => 'memory',
],

'cache' => [
'driver' => 'cache',
'store' => env('WEBHOOK_CLIENT_CACHE_STORE', 'file'),
'lifetime' => env('WEBHOOK_CLIENT_CACHE_LIFETIME', 60),
'prefix' => env('WEBHOOK_CLIENT_CACHE_PREFIX', 'webhook_call:'),
],
],
],

'configs' => [
[
/*
Expand Down Expand Up @@ -64,10 +93,9 @@ return [
'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,

/*
* The classname of the model to be used to store call. The class should be equal
* or extend Spatie\WebhookClient\Models\WebhookCall.
* One of configured webhook storage name.
*/
'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
'webhook_storage' => 'eloquent',

/*
* The class name of the job that will process the webhook request.
Expand Down Expand Up @@ -116,11 +144,11 @@ protected $except = [

## Usage

With the installation out of the way, let's take a look at how this package handles webhooks. First, it will verify if the signature of the request is valid. If it is not, we'll throw an exception and fire off the `InvalidSignatureEvent` event. Requests with invalid signatures will not be stored in the database.
With the installation out of the way, let's take a look at how this package handles webhooks. First, it will verify if the signature of the request is valid. If it is not, we'll throw an exception and fire off the `InvalidSignatureEvent` event. Requests with invalid signatures will not be stored in the storage.

Next, the request will be passed to a webhook profile. A webhook profile is a class that determines if a request should be stored and processed by your app. It allows you to filter out webhook requests that are of interest to your app. You can easily create [your own webhook profile](#determining-which-webhook-requests-should-be-stored-and-processed).

If the webhook profile determines that request should be stored and processed, we'll first store it in the `webhook_calls` table. After that, we'll pass that newly created `WebhookCall` model to a queued job. Most webhook sending apps expect you to respond very quickly. Offloading the real processing work allows for speedy responses. You can specify which job should process the webhook in the `process_webhook_job` in the `webhook-client` config file. Should an exception be thrown while queueing the job, the package will store that exception in the `exception` attribute on the `WebhookCall` model.
If the webhook profile determines that request should be stored and processed, we'll first store it in the configured storage (default is `eloquent` which uses `webhook_calls` table). After that, we'll pass that newly created `WebhookCall` model to a queued job. Most webhook sending apps expect you to respond very quickly. Offloading the real processing work allows for speedy responses. You can specify which job should process the webhook in the `process_webhook_job` in the `webhook-client` config file. Should an exception be thrown while queueing the job, the package will store that exception in the `exception` attribute on the `WebhookCall` model.

After the job has been dispatched, the controller will respond with a `200` status code.

Expand Down Expand Up @@ -179,11 +207,9 @@ After creating your own `WebhookProfile` you must register it in the `webhook_pr

After the signature is validated and the webhook profile has determined that the request should be processed, the package will store and process the request.

The request will first be stored in the `webhook_calls` table. This is done using the `WebhookCall` model.

Should you want to customize the table name or anything on the storage behavior, you can let the package use an alternative model. A webhook storing model can be specified in the `webhook_model`. Make sure you model extends `Spatie\WebhookClient\Models\WebhookCall`.
The request will first be stored in the configured webhook call storage provider. By default it uses `eloquent` driver and `EloquentWebhookCall` model.

You can change how the webhook is stored by overriding the `storeWebhook` method of `WebhookCall`. In the `storeWebhook` method you should return a saved model.
Should you want to customize the table name or anything on the storage behavior, you can let the package use an alternative model. A webhook storing driver can be specified in the `webhook_storage`. When using `eloquent` with a custom model Make sure you model extends `Spatie\WebhookClient\Models\EloquentWebhookCall`.

Next, the newly created `WebhookCall` model will be passed to a queued job that will process the request. Any class that extends `\Spatie\WebhookClient\ProcessWebhookJob` is a valid job. Here's an example:

Expand Down Expand Up @@ -218,7 +244,7 @@ return [
'signature_header_name' => 'Signature-for-app-1',
'signature_validator' => \Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,
'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,
'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
'webhook_storage' => 'eloquent',
'process_webhook_job' => '',
],
[
Expand All @@ -227,7 +253,7 @@ return [
'signature_header_name' => 'Signature-for-app-2',
'signature_validator' => \Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,
'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,
'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
'webhook_storage' => 'eloquent',
'process_webhook_job' => '',
],
],
Expand Down Expand Up @@ -256,7 +282,7 @@ $webhookConfig = new \Spatie\WebhookClient\WebhookConfig([
'signature_header_name' => 'Signature',
'signature_validator' => \Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,
'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,
'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
'webhook_storage' => 'eloquent',
'process_webhook_job' => '',
]);

Expand Down
38 changes: 33 additions & 5 deletions config/webhook-client.php
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
<?php

return [
'storage' => [
/*
* Default webhook storage driver.
*/
'default' => env('WEBHOOK_CLIENT_STORAGE', 'eloquent'),

/*
* List of webhook storage drivers.
* Supported drivers: eloquent, memory, cache
*/
'config' => [
'eloquent' => [
'driver' => 'eloquent',
'model' => env('WEBHOOK_CLIENT_ELOQUENT_MODEL', Spatie\WebhookClient\Models\EloquentWebhookCall::class),
],

'memory' => [
'driver' => 'memory',
],

'cache' => [
'driver' => 'cache',
'store' => env('WEBHOOK_CLIENT_CACHE_STORE', 'file'),
'lifetime' => env('WEBHOOK_CLIENT_CACHE_LIFETIME', 60),
'prefix' => env('WEBHOOK_CLIENT_CACHE_PREFIX', 'webhook_call:'),
],
],
],

'configs' => [
[
/*
Expand All @@ -25,18 +54,17 @@
*
* It should implement \Spatie\WebhookClient\SignatureValidator\SignatureValidator
*/
'signature_validator' => \Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,
'signature_validator' => Spatie\WebhookClient\SignatureValidator\DefaultSignatureValidator::class,

/*
* This class determines if the webhook call should be stored and processed.
*/
'webhook_profile' => \Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,
'webhook_profile' => Spatie\WebhookClient\WebhookProfile\ProcessEverythingWebhookProfile::class,

/*
* The classname of the model to be used to store call. The class should be equal
* or extend Spatie\WebhookClient\Models\WebhookCall.
* One of configured webhook storage name.
*/
'webhook_model' => \Spatie\WebhookClient\Models\WebhookCall::class,
'webhook_storage' => 'eloquent',

/*
* The class name of the job that will process the webhook request.
Expand Down
7 changes: 7 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
<logging>
<log type="tap" target="build/report.tap"/>
<log type="junit" target="build/report.junit.xml"/>
<log type="coverage-html" target="build/coverage"/>
<log type="coverage-text" target="build/coverage.txt"/>
<log type="coverage-clover" target="build/logs/clover.xml"/>
</logging>
</phpunit>
7 changes: 7 additions & 0 deletions src/Events/WebhookCallDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Spatie\WebhookClient\Events;

class WebhookCallDeletedEvent extends WebhookCallEvent
{
}
21 changes: 21 additions & 0 deletions src/Events/WebhookCallEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\WebhookClient\Events;

use Spatie\WebhookClient\Models\WebhookCall;

class WebhookCallEvent
{
/**
* @var WebhookCall
*/
public $webhookCall;

/**
* @param WebhookCall $webhookCall
*/
public function __construct(WebhookCall $webhookCall)
{
$this->webhookCall = $webhookCall;
}
}
24 changes: 24 additions & 0 deletions src/Events/WebhookCallFailedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Spatie\WebhookClient\Events;

use Spatie\WebhookClient\Models\WebhookCall;

class WebhookCallFailedEvent extends WebhookCallEvent
{
/**
* @var \Exception
*/
public $exception;

/**
* @param WebhookCall $webhookCall
* @param \Exception $exception
*/
public function __construct(WebhookCall $webhookCall, \Exception $exception)
{
parent::__construct($webhookCall);

$this->exception = $exception;
}
}
8 changes: 8 additions & 0 deletions src/Events/WebhookCallProcessingEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Spatie\WebhookClient\Events;

class WebhookCallProcessingEvent extends WebhookCallEvent
{
//
}
7 changes: 7 additions & 0 deletions src/Events/WebhookCallStoredEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Spatie\WebhookClient\Events;

class WebhookCallStoredEvent extends WebhookCallEvent
{
}
8 changes: 8 additions & 0 deletions src/Exceptions/InvalidConfig.php
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Exception;
use Spatie\WebhookClient\ProcessWebhookJob;
use Spatie\WebhookClient\Storage\WebhookCallStorage;
use Spatie\WebhookClient\WebhookProfile\WebhookProfile;
use Spatie\WebhookClient\SignatureValidator\SignatureValidator;

Expand Down Expand Up @@ -34,4 +35,11 @@ public static function invalidProcessWebhookJob(string $processWebhookJob): Inva

return new static("`{$processWebhookJob}` is not a valid process webhook job class. A valid class should implement `{$abstractProcessWebhookJob}`.");
}

public static function invalidWebhookStorage(string $invalidWebhookStorage): InvalidConfig
{
$webhookStorageInterface = WebhookCallStorage::class;

return new static("`{$invalidWebhookStorage}` is not a valid signature validator class. A valid storage is a class that implements `{$webhookStorageInterface}`.");
}
}
21 changes: 21 additions & 0 deletions src/Listeners/LogEloquentExceptionListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\WebhookClient\Listeners;

use Spatie\WebhookClient\Models\EloquentWebhookCall;
use Spatie\WebhookClient\Events\WebhookCallFailedEvent;

class LogEloquentExceptionListener
{
/**
* Save processing errors for eloquent models.
*
* @param WebhookCallFailedEvent $event
*/
public function handle(WebhookCallFailedEvent $event)
{
if ($event->webhookCall instanceof EloquentWebhookCall) {
$event->webhookCall->saveException($event->exception);
}
}
}
21 changes: 21 additions & 0 deletions src/Listeners/ResetEloquentExceptionListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\WebhookClient\Listeners;

use Spatie\WebhookClient\Models\EloquentWebhookCall;
use Spatie\WebhookClient\Events\WebhookCallProcessingEvent;

class ResetEloquentExceptionListener
{
/**
* Reset processing errors for eloquent models.
*
* @param WebhookCallProcessingEvent $event
*/
public function handle(WebhookCallProcessingEvent $event)
{
if ($event->webhookCall instanceof EloquentWebhookCall) {
$event->webhookCall->clearException();
}
}
}
63 changes: 63 additions & 0 deletions src/Models/DefaultWebhookCall.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Spatie\WebhookClient\Models;

class DefaultWebhookCall implements WebhookCall
{
/**
* @var string
*/
protected $id;

/**
* @var string
*/
protected $name;

/**
* @var array
*/
protected $payload;

/**
* @param string $id
* @param string $name
* @param array $payload
*/
public function __construct(string $id, string $name, array $payload)
{
$this->id = $id;
$this->name = $name;
$this->payload = $payload;
}

/**
* Return webhook's ID.
*
* @return string
*/
public function getId(): string
{
return $this->id;
}

/**
* Returns called webhook's name.
*
* @return string
*/
public function getName(): string
{
return $this->name;
}

/**
* Returns webhook's payload.
*
* @return array
*/
public function getPayload(): array
{
return $this->payload;
}
}
Loading