本指南展示如何使用 Symfony Messenger 在 PHP 中构建可扩展的基于 NFT 的活动票务后端,以安全可靠地处理区块链延迟。本指南展示如何使用 Symfony Messenger 在 PHP 中构建可扩展的基于 NFT 的活动票务后端,以安全可靠地处理区块链延迟。

使用 Symfony 7.4 构建去中心化活动票务系统 Web3

2025/12/22 01:43
阅读时长 6 分钟
如需对本内容提供反馈或相关疑问,请通过邮箱 [email protected] 联系我们。

Web3 dan rangka kerja web tradisional bersilang di mana utiliti dunia sebenar bermula. Walaupun kitaran gembar-gembur datang dan pergi, utiliti Token Tidak Boleh Fungible (NFT) untuk mengesahkan pemilikan — khususnya dalam tiket acara — kekal sebagai kes penggunaan yang kukuh.

Dalam artikel ini, kita akan membina tulang belakang Sistem Tiket Acara Terdesentralisasi menggunakan Symfony 7.4 dan PHP 8.3. Kita akan melangkaui tutorial asas dan melaksanakan seni bina gred pengeluaran yang mengendalikan sifat asinkronus transaksi blockchain menggunakan komponen Symfony Messenger.

Seni Bina

Pendekatan "Senior" mengakui bahawa PHP bukanlah proses berjalan lama seperti Node.js. Oleh itu, kita tidak mendengar peristiwa blockchain dalam masa nyata dalam pengawal. Sebaliknya, kita menggunakan pendekatan hibrid:

  1. Interaksi Langsung (Tulis): Kita menggunakan Symfony Messenger untuk memindahkan transaksi "Minting" kepada pekerja, mencegah tamat masa HTTP.
  2. Pengundian RPC (Baca): Kita menggunakan arahan berjadual untuk mengesahkan status on-chain.
  3. Kontrak Pintar: Kita menganggap kontrak ERC-721 standard yang digunakan pada rantai serasi EVM (Ethereum, Polygon, Base).

Prasyarat & Stack

  • PHP: 8.3+
  • Symfony: 7.4 (LTS)
  • Nod Blockchain: Infura, Alchemy, atau nod Hardhat tempatan.

Banyak perpustakaan PHP Web3 ditinggalkan atau ditaip dengan buruk. Walaupun web3p/web3.php adalah yang paling terkenal, bergantung sepenuhnya padanya boleh berisiko kerana jurang penyelenggaraan.

Untuk panduan ini, kita akan menggunakan web3p/web3.php (versi ^0.3) untuk pengekodan ABI tetapi akan memanfaatkan HttpClient asli Symfony untuk pengangkutan JSON-RPC sebenar. Ini memberi kita kawalan penuh ke atas tamat masa, percubaan semula dan pembalakan — kritikal untuk aplikasi pengeluaran.

Persediaan Projek

Pertama, mari kita pasang kebergantungan. Kita memerlukan runtime Symfony, klien HTTP dan perpustakaan 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

Pastikan composer.json anda mencerminkan kestabilan:

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

Perkhidmatan Blockchain

Kita memerlukan perkhidmatan yang kukuh untuk bercakap dengan blockchain. Kita akan mencipta EthereumService yang membungkus panggilan JSON-RPC.

//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; } }

Jalankan ujian tempatan mengakses getTicketOwner dengan ID yang diketahui telah dicetak. Jika anda mendapat alamat 0x, sambungan RPC anda berfungsi.

Pencetakan Asinkronus dengan Messenger

Transaksi blockchain adalah perlahan (15 saat hingga minit). Jangan sekali-kali membuat pengguna menunggu pengesahan blok dalam permintaan pelayar. Kita akan menggunakan Symfony Messenger untuk mengendalikan ini di latar belakang.

Mesej

//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 ) {} }

Pengendali

Di sinilah keajaiban berlaku. Kita akan menggunakan pembantu perpustakaan web3p/web3.php untuk menandatangani transaksi secara tempatan.

Nota: Dalam persekitaran keselamatan tinggi, anda akan menggunakan Perkhidmatan Pengurusan Kunci (KMS) atau enklaf tandatangan berasingan. Untuk artikel ini, kita menandatangani secara tempatan.

//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; } } }

Pengawal

Pengawal kekal nipis. Ia menerima permintaan, mengesahkan input, mencipta entiti tiket "Pending" dalam pangkalan data anda (ditinggalkan untuk ringkas) dan menghantar mesej.

//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); } }

Konfigurasi & Panduan Gaya

Mengikuti gaya Symfony 7.4, kita menggunakan taip ketat dan atribut. Pastikan messenger.yaml anda dikonfigurasikan untuk pengangkutan async.

#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

Pengesahan

Untuk mengesahkan pelaksanaan ini berfungsi tanpa menggunakan ke Mainnet:

Nod Tempatan: Jalankan blockchain tempatan menggunakan Hardhat atau Anvil (Foundry).

npx hardhat node

Persekitaran: Tetapkan .env.local anda untuk menunjuk ke 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"

Gunakan: Mulakan pekerja.

php bin/console messenger:consume async -vv

Permintaan:

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

Anda sepatutnya melihat pekerja memproses mesej dan, jika anda melaksanakan logik tandatangan transaksi mentah sepenuhnya, hash transaksi muncul dalam konsol Hardhat anda.

Kesimpulan

Membina aplikasi Web3 dalam PHP memerlukan perubahan pemikiran. Anda bukan hanya membina aplikasi CRUD; anda membina orkestrator untuk keadaan terdesentralisasi.

Dengan menggunakan Symfony 7.4, kita memanfaatkan:

  • HttpClient untuk komunikasi RPC yang boleh dipercayai dan boleh dikawal.
  • Messenger untuk mengendalikan realiti asinkronus blockchain.
  • Atribut PHP 8.3 untuk kod yang bersih dan mudah dibaca.

Seni bina ini berskala. Sama ada anda menjual 10 tiket atau 10,000, baris gilir mesej bertindak sebagai penampan, memastikan nonce transaksi anda tidak berlanggar dan pelayan anda tidak tergantung.

Bersedia untuk meningkatkan infrastruktur Web3 anda?

Mengintegrasikan blockchain memerlukan ketepatan. Jika anda memerlukan bantuan mengaudit interaksi kontrak pintar anda atau meningkatkan penggunaan mesej Symfony anda, mari kita berhubung.

\

市场机遇
4 图标
4实时价格 (4)
$0.010237
$0.010237$0.010237
-1.80%
USD
4 (4) 实时价格图表
免责声明: 本网站转载的文章均来源于公开平台,仅供参考。这些文章不代表 MEXC 的观点或意见。所有版权归原作者所有。如果您认为任何转载文章侵犯了第三方权利,请联系 [email protected] 以便将其删除。MEXC 不对转载文章的及时性、准确性或完整性作出任何陈述或保证,并且不对基于此类内容所采取的任何行动或决定承担责任。转载材料仅供参考,不构成任何商业、金融、法律和/或税务决策的建议、认可或依据。

您可能也会喜欢

唐杰的上联, 姚顺雨的下联

唐杰的上联, 姚顺雨的下联

文章作者、来源:36Kr 腾讯发布开源模型插件,专为解决模型记忆问题而生 agent正在变得越来越能干,但它还有一个很尴尬的问题,那就是干着干着,就忘了自己要干什么了。 长任务、跨会话、连续执行,这些的确是agent的发展方向,可前提是它必须有一套可靠的记忆系统。否则,再强的模型也只能在一次次对话里反复“重新认识世界”
分享
MetaEra2026/05/19 13:16
当「龙虾」走进编辑部,媒体工作流如何被AI重构?

当「龙虾」走进编辑部,媒体工作流如何被AI重构?

文章作者、来源:36氪Pro 当传播大脑的“灵思超级助手”部署在腾讯云ClawPro上,传统媒体工作流真正迎来了从“串行流水线”到“并行智能体”的效率重构。 AI内容井喷的时代,新闻人的价值是什么? 这并非宏大叙事,而是悬在每一个媒体从业者头上的达摩克利斯之剑。大模型会写稿,AI会剪视频,数字人主播不请假、不喊累,当A
分享
MetaEra2026/05/19 13:26
智能体AI公益实战培训会将于6月13日在香港理工大学举行,开启AI Native 时代

智能体AI公益实战培训会将于6月13日在香港理工大学举行,开启AI Native 时代

文章作者、来源:ME News 当大模型技术从“被动问答”的工具属性,全速演进为“具备自主规划、决策与执行能力”的 Agentic AI(智能体 AI),一场席卷全球的生产力范式革命已悄然拉开序幕。对于当下的企业决策者、金融机构高管与科研学者而言,核心的命题已不再是“要不要拥抱 AI”,而是“如何在一线实操中解构 AI
分享
MetaEra2026/05/19 17:02

不懂K线也能赚?抄作业就够了

不懂K线也能赚?抄作业就够了不懂K线也能赚?抄作业就够了

3 秒复制大牛策略 ,自动开平仓,收益实时同步