Symfony Component Advent Calendar 2023の16日目の記事です。
外部サービスからのイベントを受け取るよ、"RemoteEvent"
RemoteEventは、外部サービスからのイベントを『リモートからのイベント』とみなし、イベントを発火させるコンポーネントです。
インストール
composer require symfony/remote-event
使い方
Symfonyの偉い人は考えました。『Webhookって要はリモートからのイベントじゃん。』
webhookでSymfonyにアクセスされた時、それをRemoteEvent
に置き換えてイベント発火させ、処理を行います。処理の流れはこんな感じです。
- 外部サービスのwebhookを解析する
RequestParser
を作る - 解析したリクエストを
RemoteEvent
にする - イベントを受け取って実行する
Consumer
を作る - webhookとして設定する
このうち、3,4は前編のWebhookとして説明しましたが、再度記載します。
1. RequestParserを作る & 2. RemoteEventを作る
namespace App\Webhook;
use Symfony\Component\HttpFoundation\ChainRequestMatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestMatcher\HostRequestMatcher;
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;
class SampleWebhookParser extends AbstractRequestParser
{
protected function getRequestMatcher(): RequestMatcherInterface
{
return new ChainRequestMatcher([
new HostRequestMatcher('github.com'),
new IsJsonRequestMatcher(),
new MethodRequestMatcher('POST')
]);
}
protected function doParse(Request $request, #[\SensitiveParameter] string $secret): ?RemoteEvent
{
$content = $request->toArray();
return new RemoteEvent('sample', 1, [
'name' => $content['repository']['full_name'],
'action' => $content['action'],
'secret' => $secret,
]); // RemoteEvent('{イベント名}', '{イベントID}', {ペイロード})
}
}
getRequestMatcher()
でどのURLからアクセスされたものをRemoteEventにするか設定します。
上記の場合、
- github.comからのアクセス
- リクエストボディがJSON
- メソッドがPOST
の場合に、このクラスのdoParse()
が実行されます。
doParse()
では、Requestオブジェクトを使って、リクエスト内容を取得し、その内容を使ってRemoteEvent
オブジェクトを作って返します。
3. Consumerを作る
namespace App\RemoteEvent;
use Symfony\Component\RemoteEvent\Attribute\AsRemoteEventConsumer;
use Symfony\Component\RemoteEvent\Consumer\ConsumerInterface;
use Symfony\Component\RemoteEvent\Event\Mailer\AbstractMailerEvent;
use Symfony\Component\RemoteEvent\Event\Mailer\MailerDeliveryEvent;
use Symfony\Component\RemoteEvent\RemoteEvent;
use Symfony\Contracts\EventDispatcher\Event;
#[AsRemoteEventConsumer(name: 'sample')]
class SampleEventConsumer implements ConsumerInterface
{
public function __construct(private readonly LoggerInterface $logger)
{
}
public function consume(RemoteEvent $event): void
{
$payload = $event->getPayload();
$name = $payload['name'];
$action = $payload['action'];
$this->logger->info("{$name}: {$action}");
}
}
#[AsRemoteEventConsumer]
に2で作成したRemoteEventのイベント名を設定します。そうすることで、RemoteEventが発火した際にこのConsumerのconsume()
が実行されます。
consume()
内は、やりたいことを好きに書いてください。気をつけないといけないのはこのメソッドはvoidなので、何も返しません。
4. webhookの設定
framework:
webhook:
routing:
sample:
service: 'App\Webhook\SampleWebhookParser'
webhookの設定を行います。この設定により、/webhook/sample
で、github.comからPOSTでJSONを送られてきた時用のwebhookが作成されます。
まとめ
今回はRemoteEvent
でした。Webhook
で定義されていない外部サービスでも、このようにすればwebhookを作成することができます!