Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kurozumi committed Sep 12, 2024
0 parents commit ccd5281
Show file tree
Hide file tree
Showing 11 changed files with 348 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

name: Packaging for EC-CUBE Plugin
on:
release:
types: [ published ]
jobs:
deploy:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Packaging
working-directory: ../
run: |
rm -rf $GITHUB_WORKSPACE/.github
find $GITHUB_WORKSPACE -name "dummy" -delete
find $GITHUB_WORKSPACE -name ".git*" -and ! -name ".gitkeep" -print0 | xargs -0 rm -rf
chmod -R o+w $GITHUB_WORKSPACE
cd $GITHUB_WORKSPACE
tar cvzf ../${{ github.event.repository.name }}-${{ github.event.release.tag_name }}.tar.gz ./*
- name: Upload binaries to release of TGZ
uses: svenstaro/upload-release-action@v1-release
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ runner.workspace }}/${{ github.event.repository.name }}-${{ github.event.release.tag_name }}.tar.gz
asset_name: ${{ github.event.repository.name }}-${{ github.event.release.tag_name }}.tar.gz
tag: ${{ github.ref }}
overwrite: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.tar.gz
!.gitkeep
.idea
.php-cs-fixer.cache
51 changes: 51 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/*
* This file is part of Stripe Webhook
*
* Copyright(c) Akira Kurozumi All Rights Reserved.
*
* https://a-zumi.net
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

if (php_sapi_name() !== 'cli') {
throw new LogicException();
}

$header = <<<EOL
This file is part of Stripe Webhook

Copyright(c) Akira Kurozumi All Rights Reserved.

https://a-zumi.net

For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOL;

$rules = [
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'phpdoc_align' => false,
'phpdoc_summary' => false,
'phpdoc_scalar' => false,
'phpdoc_annotation_without_dot' => false,
'no_superfluous_phpdoc_tags' => false,
'increment_style' => false,
'yoda_style' => false,
'header_comment' => ['header' => $header],
];

$finder = PhpCsFixer\Finder::create()
->in(__DIR__)
->name('*.php')
;
$config = new PhpCsFixer\Config();

return $config
->setRules($rules)
->setFinder($finder)
;
103 changes: 103 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Stripe Webhook

StripeのWebhookに登録するエンドポイントを構築するためのプラグインです。

## 各種ライブラリをインストール

以下のライブラリをcomposerでインストールしてください。

```bash
composer require symfony/webhook symfony/remote-event stripe/stripe-php
```

## Webhookの署名シークレットを設定

.envにWebhookの署名シークレットを設定してください。

```text
STRIPE_SIGNING_SECRET=whsec_t6KFvU8...
```

StripeWebhookプラグインをEC-CUBEにインストール・有効化してください。

```bash
git clone [email protected]:kurozumi/eccube-stripe-webhook.git app/Plugin
bin/console e:p:i --code StripeWebhook
bin/console e:p:e --code StripeWebhook
```

## エンドポイント

下記のエンドポイントをStripeのWebhookに登録してください。

```text
https://my-domain/webhook/stripe
```

## 定期支払いが成功したり失敗した場合に何かする処理の実装方法

```php
<?php

declare(strict_types=1);

namespace Customize\EventListener;

use Plugin\StripeWebhook\RemoteEvent\Event\StripeEvent;
use Stripe\Checkout\Session;
use Stripe\Event;
use Stripe\Invoice;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class StripeEventListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
Event::CHECKOUT_SESSION_COMPLETED => ['onCheckoutSessionCompleted'],
Event::INVOICE_PAID => ['onInvoicePaid'],
Event::INVOICE_PAYMENT_FAILED => ['onInvoicePaymentFailed']
];
}

/**
* 顧客が「支払う」または「登録」ボタンをクリックしたときに何かする
*
* @param StripeEvent $event
*/
public function onCheckoutSessionCompleted(StripeEvent $event)
{
/** @var Session $session */
$session = $event->getResource();
}

/**
* 支払いが成功した場合に何かする
*
* @param StripeEvent $event
*/
public function onInvoicePaid(StripeEvent $event)
{
/** @var Invoice $invoice */
$invoice = $event->getResource();
}

/**
* 顧客の支払い方法に問題があった場合に何かする
*
* @param StripeEvent $event
*/
public function onInvoicePaymentFailed(StripeEvent $event)
{
/** @var Invoice $invoice */
$invoice = $event->getResource();
}
}

```

## ご注意

カスタマイズ、または他社プラグインとの競合による動作不良つきましてはサポート対象外です。

本プラグインを導入したことによる不具合や被った不利益につきましては一切責任を負いません。 ご理解の程よろしくお願いいたします。
37 changes: 37 additions & 0 deletions RemoteEvent/Consumer/StripeConsumer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

/*
* This file is part of Stripe Webhook
*
* Copyright(c) Akira Kurozumi All Rights Reserved.
*
* https://a-zumi.net
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Plugin\StripeWebhook\RemoteEvent\Consumer;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\RemoteEvent\Attribute\AsRemoteEventConsumer;
use Symfony\Component\RemoteEvent\Consumer\ConsumerInterface;
use Symfony\Component\RemoteEvent\RemoteEvent;

#[AsRemoteEventConsumer(name: 'stripe')]
class StripeConsumer implements ConsumerInterface
{
private EventDispatcherInterface $eventDispatcher;

public function __construct(EventDispatcherInterface $eventDispatcher)
{
$this->eventDispatcher = $eventDispatcher;
}

public function consume(RemoteEvent $event): void
{
$this->eventDispatcher->dispatch($event, $event->getName());
}
}
36 changes: 36 additions & 0 deletions RemoteEvent/Event/StripeEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/*
* This file is part of Stripe Webhook
*
* Copyright(c) Akira Kurozumi All Rights Reserved.
*
* https://a-zumi.net
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Plugin\StripeWebhook\RemoteEvent\Event;

use Stripe\ApiResource;
use Symfony\Component\RemoteEvent\RemoteEvent;

final class StripeEvent extends RemoteEvent
{
public function __construct(
private readonly string $name,
private readonly string $id,
private readonly array $payload,
private readonly ApiResource $resource
) {
parent::__construct($this->name, $this->id, $this->payload);
}

public function getResource(): ApiResource
{
return $this->resource;
}
}
10 changes: 10 additions & 0 deletions Resource/config/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
parameters:
env(STRIPE_SIGNING_SECRET): ''
stripe_signing_secret: '%env(STRIPE_SIGNING_SECRET)%'

framework:
webhook:
routing:
stripe:
service: Plugin\StripeWebhook\Webhook\StripeRequestParser
secret: '%stripe_signing_secret%'
Empty file.
Empty file.
62 changes: 62 additions & 0 deletions Webhook/StripeRequestParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/*
* This file is part of Stripe Webhook
*
* Copyright(c) Akira Kurozumi All Rights Reserved.
*
* https://a-zumi.net
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Plugin\StripeWebhook\Webhook;

use Plugin\StripeWebhook\RemoteEvent\Event\StripeEvent;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Exception\UnexpectedValueException;
use Stripe\Webhook;
use Symfony\Component\HttpFoundation\ChainRequestMatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcher\IsJsonRequestMatcher;
use Symfony\Component\HttpFoundation\RequestMatcher\MethodRequestMatcher;
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\RemoteEvent\RemoteEvent;
use Symfony\Component\Webhook\Client\AbstractRequestParser;
use Symfony\Component\Webhook\Exception\RejectWebhookException;

class StripeRequestParser extends AbstractRequestParser
{
public function __construct(
private readonly string $signatureHeaderName = 'HTTP_STRIPE_SIGNATURE'
) {
}

protected function getRequestMatcher(): RequestMatcherInterface
{
return new ChainRequestMatcher([
new IsJsonRequestMatcher(),
new MethodRequestMatcher(Request::METHOD_POST),
]);
}

protected function doParse(Request $request, #[\SensitiveParameter] string $secret): ?RemoteEvent
{
try {
$signature = $request->server->get($this->signatureHeaderName);
$event = Webhook::constructEvent($request->getContent(), $signature, $secret);
} catch (UnexpectedValueException|SignatureVerificationException $exception) {
throw new RejectWebhookException(406, $exception->getMessage());
}

return new StripeEvent(
name: $event->type,
id: $event->id,
payload: $event->data->object->toArray(),
resource: $event->data->object
);
}
}
16 changes: 16 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "ec-cube/stripewebhook",
"version": "1.0.0",
"description": "Stripe Webhook",
"type": "eccube-plugin",
"require": {
"ec-cube/plugin-installer": "^2.0",
"php": ">=8.1",
"symfony/webhook": "*",
"symfony/remote-event": "*",
"stripe/stripe-php": "*"
},
"extra": {
"code": "StripeWebhook"
}
}

0 comments on commit ccd5281

Please sign in to comment.