要望や症状
EC-CUBE 4系において、注文が発生した際に運用チームへSlackで自動通知を送りたいという要望があります。
注文完了時に自動でSlack通知を送信し、注文番号、購入者情報、支払方法、金額などの基本情報をSlackに送信したい場合のカスタマイズが必要です。
理由や原因
EC-CUBE 4系では注文完了時のSlack通知機能が標準では提供されていません。そのため、Slack通知機能を利用するには別途実装が必要となります。
解決策
注文完了時にSlack通知を送信するため、イベントリスナーを使用して実装します。注文ステータスが変更されたタイミングでSlack通知を送信する方法が最も確実で拡張性に優れています。
1. Slack Webhook URLの設定
SlackワークスペースでIncoming Webhookを設定し、EC-CUBEの設定ファイルにWebhook URLを記述します。
# app/config/eccube/packages/slack.yaml
parameters:
slack_webhook_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
slack_channel: '#orders'
2. Slack通知サービスクラスの作成
注文情報をSlackに送信するためのサービスクラスを作成します。
<?php
// app/Customize/Service/SlackNotificationService.php
namespace Customize\Service;
use Eccube\Entity\Order;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Psr\Log\LoggerInterface;
class SlackNotificationService
{
private $parameterBag;
private $logger;
public function __construct(ParameterBagInterface $parameterBag, LoggerInterface $logger)
{
$this->parameterBag = $parameterBag;
$this->logger = $logger;
}
public function sendOrderNotification(Order $order)
{
try {
$webhookUrl = $this->parameterBag->get('slack_webhook_url');
$channel = $this->parameterBag->get('slack_channel');
if (empty($webhookUrl)) {
return false;
}
$message = $this->buildOrderMessage($order, $channel);
return $this->sendToSlack($webhookUrl, $message);
} catch (\Exception $e) {
$this->logger->error('Slack通知送信エラー: ' . $e->getMessage());
return false;
}
}
private function buildOrderMessage(Order $order, string $channel): array
{
$customerName = $order->getName01() . ' ' . $order->getName02();
$paymentMethod = $order->getPayment() ? $order->getPayment()->getMethod() : '未設定';
return [
'channel' => $channel,
'username' => 'EC-CUBE注文通知',
'icon_emoji' => ':shopping_cart:',
'text' => sprintf(
"🛒 新しい注文が入りました\n\n" .
"📋 注文番号: %s\n" .
"👤 お客様名: %s\n" .
"💳 支払方法: %s\n" .
"💰 合計金額: %s円\n" .
"📅 注文日時: %s",
$order->getOrderNo(),
$customerName,
$paymentMethod,
number_format($order->getPaymentTotal()),
$order->getCreateDate()->format('Y-m-d H:i:s')
)
];
}
private function sendToSlack(string $webhookUrl, array $message): bool
{
$postData = json_encode($message);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $webhookUrl,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $httpCode === 200;
}
}
3. イベントリスナーの作成
注文完了時のイベントを監視してSlack通知を送信するリスナーを作成します。
<?php
// app/Customize/EventListener/OrderSlackNotificationListener.php
namespace Customize\EventListener;
use Eccube\Event\EccubeEvents;
use Eccube\Event\EventArgs;
use Customize\Service\SlackNotificationService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class OrderSlackNotificationListener implements EventSubscriberInterface
{
private $slackService;
public function __construct(SlackNotificationService $slackService)
{
$this->slackService = $slackService;
}
public static function getSubscribedEvents()
{
return [
EccubeEvents::FRONT_SHOPPING_COMPLETE_INITIALIZE => 'onShoppingComplete',
];
}
public function onShoppingComplete(EventArgs $event)
{
$order = $event->getArgument('Order');
if ($order) {
$this->slackService->sendOrderNotification($order);
}
}
}
4. サービス定義の登録
作成したサービスクラスとイベントリスナーをDIコンテナに登録します。
# app/config/eccube/services.yaml
services:
Customize\Service\SlackNotificationService:
arguments:
- '@parameter_bag'
- '@logger'
Customize\EventListener\OrderSlackNotificationListener:
arguments:
- '@Customize\Service\SlackNotificationService'
tags:
- { name: kernel.event_subscriber }
5. キャッシュクリアと動作確認
設定ファイルとサービス定義を変更した後は、必ずキャッシュをクリアします。
php bin/console cache:clear --no-warmup
php bin/console cache:warmup
実際に注文を行い、Slackチャンネルに通知が送信されることを確認してください。
セキュリティと運用上の注意事項
Slack Webhook URLは機密情報です。本番環境では環境変数として管理し、設定ファイルには直接記述しないことを強く推奨します。また、通知の送信失敗が注文処理に影響を与えないよう、エラーハンドリングを適切に実装しています。
通知メッセージの内容は個人情報を含むため、Slackのアクセス権限管理も適切に行ってください。