يوضح هذا الدليل كيفية بناء نظام خلفي قابل للتطوير لتذاكر الفعاليات القائمة على NFT في PHP باستخدام Symfony Messenger للتعامل مع تأخر البلوكشين بشكل آمن وموثوق.يوضح هذا الدليل كيفية بناء نظام خلفي قابل للتطوير لتذاكر الفعاليات القائمة على NFT في PHP باستخدام Symfony Messenger للتعامل مع تأخر البلوكشين بشكل آمن وموثوق.

بناء نظام حجز تذاكر فعاليات لامركزي Web3 باستخدام Symfony 7.4

يبدأ التقاطع بين Web3 وأطر الويب التقليدية حيث تبدأ الفائدة الحقيقية في العالم الواقعي. بينما تأتي دورات الضجة وتذهب، تظل فائدة الرموز غير القابلة للاستبدال (NFTs) للتحقق من الملكية - خاصة في تذاكر الأحداث - حالة استخدام قوية.

في هذا المقال، سنبني العمود الفقري لـ نظام تذاكر الأحداث اللامركزي باستخدام Symfony 7.4 و PHP 8.3. سننتقل إلى ما هو أبعد من البرامج التعليمية الأساسية وننفذ هندسة معمارية على مستوى الإنتاج تتعامل مع الطبيعة غير المتزامنة لمعاملات البلوكتشين باستخدام مكون Symfony Messenger.

الهندسة المعمارية

يقر النهج "الأقدم" بأن PHP ليست عملية طويلة الأمد مثل Node.js. لذلك، نحن لا نستمع إلى أحداث البلوكتشين في الوقت الفعلي داخل وحدة التحكم. بدلاً من ذلك، نستخدم نهجًا هجينًا:

  1. التفاعل المباشر (الكتابة): نستخدم Symfony Messenger لنقل معاملات "السك" إلى عامل، مما يمنع انتهاء مهلة HTTP.
  2. استطلاع RPC (القراءة): نستخدم الأوامر المجدولة للتحقق من الحالة على السلسلة.
  3. العقد الذكي: نفترض عقد ERC-721 قياسيًا منشورًا على سلسلة متوافقة مع EVM (الإيثيريوم، Polygon، Base).

المتطلبات الأساسية والمكدس

  • PHP: 8.3+
  • Symfony: 7.4 (LTS)
  • عقدة البلوكتشين: Infura أو Alchemy أو عقدة Hardhat محلية.

تم التخلي عن العديد من مكتبات PHP Web3 أو أنها ضعيفة الكتابة. بينما تعتبر web3p/web3.php الأكثر شهرة، فإن الاعتماد الصارم عليها يمكن أن يكون محفوفًا بالمخاطر بسبب فجوات الصيانة.

لهذا الدليل، سنستخدم web3p/web3.php (الإصدار ^0.3) لترميز ABI ولكن سنستفيد من HttpClient الأصلي لـ Symfony لنقل JSON-RPC الفعلي. هذا يمنحنا التحكم الكامل في انتهاء المهلة وإعادة المحاولات والتسجيل - الأمر الحاسم لتطبيقات الإنتاج.

إعداد المشروع

أولاً، لنقم بتثبيت التبعيات. نحتاج إلى وقت تشغيل 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" } }

خدمة البلوكتشين

نحتاج إلى خدمة قوية للتحدث إلى البلوكتشين. سننشئ EthereumService يلف استدعاءات 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; } }

قم بتشغيل اختبار محلي للوصول إلى 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 الخاصة بك.

الخلاصة

يتطلب بناء تطبيقات Web3 في PHP تحولاً في العقلية. أنت لا تبني فقط تطبيق CRUD؛ أنت تبني منسقًا للحالة اللامركزية.

باستخدام Symfony 7.4، استفدنا من:

  • HttpClient للاتصال الموثوق والقابل للتحكم في RPC.
  • Messenger للتعامل مع الواقع غير المتزامن للبلوكتشين.
  • سمات PHP 8.3 للحصول على كود نظيف وقابل للقراءة.

هذه الهندسة المعمارية قابلة للتوسع. سواء كنت تبيع 10 تذاكر أو 10,000 تذكرة، يعمل قائمة انتظار الرسائل كمنطقة عازلة، مما يضمن عدم تصادم معاملاتك ولا يتوقف خادمك.

هل أنت مستعد لتوسيع نطاق البنية التحتية لـ Web3 الخاصة بك؟

يتطلب دمج البلوكتشين الدقة. إذا كنت بحاجة إلى مساعدة في تدقيق تفاعلات العقد الذكي الخاصة بك أو توسيع نطاق مستهلكي رسائل Symfony، فلنكن على اتصال.

\

فرصة السوق
شعار 4
4 السعر(4)
$0.02033
$0.02033$0.02033
+3.35%
USD
مخطط أسعار 4 (4) المباشر
إخلاء مسؤولية: المقالات المُعاد نشرها على هذا الموقع مستقاة من منصات عامة، وهي مُقدمة لأغراض إعلامية فقط. لا تُظهِر بالضرورة آراء MEXC. جميع الحقوق محفوظة لمؤلفيها الأصليين. إذا كنت تعتقد أن أي محتوى ينتهك حقوق جهات خارجية، يُرجى التواصل عبر البريد الإلكتروني service@support.mexc.com لإزالته. لا تقدم MEXC أي ضمانات بشأن دقة المحتوى أو اكتماله أو حداثته، وليست مسؤولة عن أي إجراءات تُتخذ بناءً على المعلومات المُقدمة. لا يُمثل المحتوى نصيحة مالية أو قانونية أو مهنية أخرى، ولا يُعتبر توصية أو تأييدًا من MEXC.