このガイドでは、Symfony Messengerを使用してブロックチェーンのレイテンシを安全かつ確実に処理する、PHPでのスケーラブルなNFTベースのイベントチケッティングバックエンドの構築方法を紹介します。このガイドでは、Symfony Messengerを使用してブロックチェーンのレイテンシを安全かつ確実に処理する、PHPでのスケーラブルなNFTベースのイベントチケッティングバックエンドの構築方法を紹介します。

Symfony 7.4でWeb3分散型イベントチケットシステムを構築する

Web3と従来のウェブフレームワークの交差点は、実用性が始まる場所です。誇大宣伝のサイクルは来ては去りますが、所有権を検証するための非代替性トークン(NFT)の実用性、特にイベントチケッティングにおいては、確固たるユースケースとして残っています。

この記事では、Symfony 7.4とPHP 8.3を使用して分散型イベントチケッティングシステムのバックボーンを構築します。基本的なチュートリアルを超えて、Symfony Messengerコンポーネントを使用してブロックチェーントランザクションの非同期性を処理する本番環境グレードのアーキテクチャを実装します。

アーキテクチャ

「シニア」アプローチは、PHPがNode.jsのような長時間実行プロセスではないことを認識しています。したがって、コントローラー内でブロックチェーンイベントをリアルタイムで監視することはしません。代わりに、ハイブリッドアプローチを使用します:

  1. 直接インタラクション(書き込み): Symfony Messengerを使用して「ミント」トランザクションをワーカーにオフロードし、HTTPタイムアウトを防ぎます。
  2. RPCポーリング(読み取り): スケジュールされたコマンドを使用してオンチェーンステータスを検証します。
  3. スマートコントラクト: EVM互換チェーン(イーサリアム、Polygon、Base)にデプロイされた標準的なERC-721コントラクトを想定します。

前提条件とスタック

  • PHP: 8.3+
  • Symfony: 7.4 (LTS)
  • Blockchain Node: Infura、Alchemy、またはローカルのHardhatノード。

多くのPHP Web3ライブラリは放棄されているか、型付けが不十分です。web3p/web3.phpが最も有名ですが、メンテナンスのギャップにより、厳密に依存することはリスクがあります。

このガイドでは、ABIエンコーディングにはweb3p/web3.php(バージョン ^0.3)を使用しますが、実際のJSON-RPCトランスポートにはSymfonyのネイティブHttpClientを活用します。これにより、タイムアウト、リトライ、ロギングを完全に制御できます - 本番環境アプリにとって重要です。

プロジェクトセットアップ

まず、依存関係をインストールしましょう。Symfonyランタイム、HTTPクライアント、Web3ライブラリが必要です。

composer create-project symfony/skeleton:"7.4.*" decentralized-ticketing cd decentralized-ticketing composer require symfony/http-client symfony/messenger symfony/uid web3p/web3.php

composer.jsonが安定性を反映していることを確認してください:

{ "require": { "php": ">=8.3", "symfony/http-client": "7.4.*", "symfony/messenger": "7.4.*", "symfony/uid": "7.4.*", "web3p/web3.php": "^0.3.0" } }

ブロックチェーンサービス

ブロックチェーンと通信するための堅牢なサービスが必要です。JSON-RPC呼び出しをラップするEthereumServiceを作成します。

//src/Service/Web3/EthereumService.php namespace App\Service\Web3; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Web3\Utils; class EthereumService { private const JSON_RPC_VERSION = '2.0'; public function __construct( private HttpClientInterface $client, #[Autowire(env: 'BLOCKCHAIN_RPC_URL')] private string $rpcUrl, #[Autowire(env: 'SMART_CONTRACT_ADDRESS')] private string $contractAddress, #[Autowire(env: 'WALLET_PRIVATE_KEY')] private string $privateKey ) {} /** * Reads the owner of a specific Ticket ID (ERC-721 ownerOf). */ public function getTicketOwner(int $tokenId): ?string { // Function signature for ownerOf(uint256) is 0x6352211e // We pad the tokenId to 64 chars (32 bytes) $data = '0x6352211e' . str_pad(Utils::toHex($tokenId, true), 64, '0', STR_PAD_LEFT); $response = $this->callRpc('eth_call', [ [ 'to' => $this->contractAddress, 'data' => $data ], 'latest' ]); if (empty($response['result']) || $response['result'] === '0x') { return null; } // Decode the address (last 40 chars of the 64-char result) return '0x' . substr($response['result'], -40); } /** * Sends a raw JSON-RPC request using Symfony HttpClient. * This offers better observability than standard libraries. */ private function callRpc(string $method, array $params): array { $response = $this->client->request('POST', $this->rpcUrl, [ 'json' => [ 'jsonrpc' => self::JSON_RPC_VERSION, 'method' => $method, 'params' => $params, 'id' => random_int(1, 9999) ] ]); $data = $response->toArray(); if (isset($data['error'])) { throw new \RuntimeException('RPC Error: ' . $data['error']['message']); } return $data; } }

既知のミントされたIDでgetTicketOwnerにアクセスするローカルテストを実行します。0xアドレスを取得できれば、RPC接続が機能しています。

Messengerによる非同期ミント

ブロックチェーントランザクションは遅いです(15秒から数分)。ブラウザリクエストでユーザーにブロック確認を待たせることは決してありません。バックグラウンドでこれを処理するためにSymfony Messengerを使用します。

メッセージ

//src/Message/MintTicketMessage.php: namespace App\Message; use Symfony\Component\Uid\Uuid; readonly class MintTicketMessage { public function __construct( public Uuid $ticketId, public string $userWalletAddress, public string $metadataUri ) {} }

ハンドラー

ここで魔法が起こります。web3p/web3.phpライブラリヘルパーを使用してローカルでトランザクションに署名します。

注意: 高セキュリティ環境では、鍵管理サービス(KMS)または別の署名エンクレーブを使用します。この記事では、ローカルで署名します。

//src/MessageHandler/MintTicketHandler.php namespace App\MessageHandler; use App\Message\MintTicketMessage; use App\Service\Web3\EthereumService; use Psr\Log\LoggerInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Web3\Contract; use Web3\Providers\HttpProvider; use Web3\RequestManagers\HttpRequestManager; use Web3p\EthereumTx\Transaction; #[AsMessageHandler] class MintTicketHandler { public function __construct( private EthereumService $ethereumService, // Our custom service private LoggerInterface $logger, #[Autowire(env: 'BLOCKCHAIN_RPC_URL')] private string $rpcUrl, #[Autowire(env: 'WALLET_PRIVATE_KEY')] private string $privateKey, #[Autowire(env: 'SMART_CONTRACT_ADDRESS')] private string $contractAddress ) {} public function __invoke(MintTicketMessage $message): void { $this->logger->info("Starting mint process for Ticket {$message->ticketId}"); // 1. Prepare Transaction Data (mintTo function) // detailed implementation of raw transaction signing usually goes here. // For brevity, we simulate the logic flow: try { // Logic to get current nonce and gas price via EthereumService // $nonce = ... // $gasPrice = ... // Sign transaction offline to prevent key exposure over network // $tx = new Transaction([...]); // $signedTx = '0x' . $tx->sign($this->privateKey); // Broadcast // $txHash = $this->ethereumService->sendRawTransaction($signedTx); // In a real app, you would save $txHash to the database entity here $this->logger->info("Mint transaction broadcast successfully."); } catch (\Throwable $e) { $this->logger->error("Minting failed: " . $e->getMessage()); // Symfony Messenger will automatically retry based on config throw $e; } } }

コントローラー

コントローラーは薄いままです。リクエストを受け入れ、入力を検証し、データベースに「保留中」のチケットエンティティを作成し(簡潔にするため省略)、メッセージをディスパッチします。

//src/Controller/TicketController.php: namespace App\Controller; use App\Message\MintTicketMessage; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Uid\Uuid; #[Route('/api/v1/tickets')] class TicketController extends AbstractController { #[Route('/mint', methods: ['POST'])] public function mint(Request $request, MessageBusInterface $bus): JsonResponse { $payload = $request->getPayload(); $walletAddress = $payload->get('wallet_address'); // 1. Basic Validation if (!$walletAddress || !str_starts_with($walletAddress, '0x')) { return $this->json(['error' => 'Invalid wallet address'], 400); } // 2. Generate Internal ID $ticketId = Uuid::v7(); // 3. Dispatch Message (Fire and Forget) $bus->dispatch(new MintTicketMessage( $ticketId, $walletAddress, 'https://api.myapp.com/metadata/' . $ticketId->toRfc4122() )); // 4. Respond immediately return $this->json([ 'status' => 'processing', 'ticket_id' => $ticketId->toRfc4122(), 'message' => 'Minting request queued. Check status later.' ], 202); } }

設定とスタイルガイド

Symfony 7.4スタイルに従って、厳格な型付けと属性を使用します。messenger.yamlが非同期トランスポート用に設定されていることを確認してください。

#config/packages/messenger.yaml: framework: messenger: transports: async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' retry_strategy: max_retries: 3 delay: 1000 multiplier: 2 routing: 'App\Message\MintTicketMessage': async

検証

Mainnetにデプロイせずにこの実装が機能することを確認するには:

ローカルノード: HardhatまたはAnvil(Foundry)を使用してローカルブロックチェーンを実行します。

npx hardhat node

環境: .env.localをlocalhostを指すように設定します。

BLOCKCHAIN_RPC_URL="http://127.0.0.1:8545" WALLET_PRIVATE_KEY="<one of the test keys provided by hardhat>" SMART_CONTRACT_ADDRESS="<deployed contract address>" MESSENGER_TRANSPORT_DSN="doctrine://default"

実行: ワーカーを起動します。

php bin/console messenger:consume async -vv

リクエスト:

curl -X POST https://localhost:8000/api/v1/tickets/mint \ -H "Content-Type: application/json" \ -d '{"wallet_address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"}'

ワーカーがメッセージを処理するのが確認でき、生のトランザクション署名ロジックを完全に実装した場合、Hardhatコンソールにトランザクションハッシュが表示されるはずです。

結論

PHPでWeb3アプリケーションを構築するには、考え方の転換が必要です。単にCRUDアプリを構築しているのではなく、分散型状態のオーケストレーターを構築しているのです。

Symfony 7.4を使用することで、以下を活用しました:

  • 信頼性が高く制御可能なRPC通信のためのHttpClient
  • ブロックチェーンの非同期的な現実を処理するためのMessenger
  • クリーンで読みやすいコードのためのPHP 8.3属性

このアーキテクチャはスケールします。チケットを10枚販売しようと10,000枚販売しようと、メッセージキューはバッファとして機能し、トランザクションのナンスが衝突せず、サーバーがハングしないことを保証します。

Web3インフラストラクチャをスケールする準備はできていますか?

ブロックチェーンの統合には精度が必要です。スマートコントラクトインタラクション監査やSymfonyメッセージコンシューマーのスケーリングに関するヘルプが必要な場合は、ご連絡ください。

\

市場の機会
4 ロゴ
4価格(4)
$0.02026
$0.02026$0.02026
+2.99%
USD
4 (4) ライブ価格チャート
免責事項:このサイトに転載されている記事は、公開プラットフォームから引用されており、情報提供のみを目的としています。MEXCの見解を必ずしも反映するものではありません。すべての権利は原著者に帰属します。コンテンツが第三者の権利を侵害していると思われる場合は、削除を依頼するために service@support.mexc.com までご連絡ください。MEXCは、コンテンツの正確性、完全性、適時性について一切保証せず、提供された情報に基づいて行われたいかなる行動についても責任を負いません。本コンテンツは、財務、法律、その他の専門的なアドバイスを構成するものではなく、MEXCによる推奨または支持と見なされるべきではありません。