Web3 এবং ঐতিহ্যবাহী ওয়েব ফ্রেমওয়ার্কের ছেদবিন্দুতেই বাস্তব-জগতের উপযোগিতা শুরু হয়। হাইপ চক্র আসে এবং যায়, কিন্তু মালিকানা যাচাইয়ের জন্য নন-ফাঞ্জিবল টোকেন (NFTs) এর উপযোগিতা — বিশেষত ইভেন্ট টিকিটিংয়ে — একটি শক্ত ব্যবহার কেস হিসেবে রয়ে গেছে।
এই নিবন্ধে, আমরা Symfony 7.4 এবং PHP 8.3 ব্যবহার করে একটি বিকেন্দ্রীকৃত ইভেন্ট টিকিটিং সিস্টেমের মেরুদণ্ড তৈরি করব। আমরা মৌলিক টিউটোরিয়াল অতিক্রম করে Symfony Messenger কম্পোনেন্ট ব্যবহার করে ব্লকচেইন লেনদেনের অ্যাসিঙ্ক্রোনাস প্রকৃতি পরিচালনা করে এমন প্রোডাকশন-গ্রেড আর্কিটেকচার প্রয়োগ করব।
একটি "সিনিয়র" পদ্ধতি স্বীকার করে যে PHP, Node.js-এর মতো দীর্ঘ-চলমান প্রক্রিয়া নয়। তাই, আমরা একটি কন্ট্রোলারের মধ্যে রিয়েল-টাইমে ব্লকচেইন ইভেন্ট শুনি না। পরিবর্তে, আমরা একটি হাইব্রিড পদ্ধতি ব্যবহার করি:
অনেক 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" } }
ব্লকচেইনের সাথে কথা বলার জন্য আমাদের একটি শক্তিশালী সার্ভিস প্রয়োজন। আমরা একটি 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 ) {} /** * একটি নির্দিষ্ট টিকিট ID (ERC-721 ownerOf) এর মালিক পড়ে। */ public function getTicketOwner(int $tokenId): ?string { // ownerOf(uint256) এর জন্য ফাংশন স্বাক্ষর হল 0x6352211e // আমরা tokenId কে 64 অক্ষরে (32 বাইট) প্যাড করি $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; } // ঠিকানা ডিকোড করুন (64-অক্ষর ফলাফলের শেষ 40 অক্ষর) return '0x' . substr($response['result'], -40); } /** * Symfony HttpClient ব্যবহার করে একটি কাঁচা JSON-RPC অনুরোধ পাঠায়। * এটি স্ট্যান্ডার্ড লাইব্রেরির চেয়ে ভাল পর্যবেক্ষণযোগ্যতা প্রদান করে। */ 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 সংযোগ কাজ করছে।
ব্লকচেইন লেনদেন ধীর (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 লাইব্রেরি হেল্পার ব্যবহার করব।
নোট: একটি উচ্চ-নিরাপত্তা পরিবেশে, আপনি একটি Key Management Service (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, // আমাদের কাস্টম সার্ভিস 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. লেনদেন ডেটা প্রস্তুত করুন (mintTo ফাংশন) // কাঁচা লেনদেন স্বাক্ষরের বিস্তারিত বাস্তবায়ন সাধারণত এখানে যায়। // সংক্ষিপ্ততার জন্য, আমরা লজিক ফ্লো সিমুলেট করি: try { // EthereumService এর মাধ্যমে বর্তমান nonce এবং গ্যাস মূল্য পাওয়ার লজিক // $nonce = ... // $gasPrice = ... // নেটওয়ার্কের মাধ্যমে কী এক্সপোজার প্রতিরোধ করতে অফলাইনে লেনদেন স্বাক্ষর করুন // $tx = new Transaction([...]); // $signedTx = '0x' . $tx->sign($this->privateKey); // সম্প্রচার // $txHash = $this->ethereumService->sendRawTransaction($signedTx); // একটি প্রকৃত অ্যাপে, আপনি এখানে ডাটাবেস এনটিটিতে $txHash সংরক্ষণ করবেন $this->logger->info("Mint transaction broadcast successfully."); } catch (\Throwable $e) { $this->logger->error("Minting failed: " . $e->getMessage()); // Symfony Messenger কনফিগের উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে পুনঃচেষ্টা করবে 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. মৌলিক যাচাইকরণ if (!$walletAddress || !str_starts_with($walletAddress, '0x')) { return $this->json(['error' => 'Invalid wallet address'], 400); } // 2. অভ্যন্তরীণ ID তৈরি করুন $ticketId = Uuid::v7(); // 3. মেসেজ প্রেরণ করুন (ফায়ার অ্যান্ড ফরগেট) $bus->dispatch(new MintTicketMessage( $ticketId, $walletAddress, 'https://api.myapp.com/metadata/' . $ticketId->toRfc4122() )); // 4. অবিলম্বে প্রতিক্রিয়া জানান return $this->json([ 'status' => 'processing', 'ticket_id' => $ticketId->toRfc4122(), 'message' => 'Minting request queued. Check status later.' ], 202); } }
Symfony 7.4 স্টাইল অনুসরণ করে, আমরা কঠোর টাইপিং এবং অ্যাট্রিবিউট ব্যবহার করি। নিশ্চিত করুন আপনার messenger.yaml 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
মেইননেটে ডিপ্লয় না করে এই বাস্তবায়ন কাজ করে কিনা যাচাই করতে:
লোকাল নোড: Hardhat বা Anvil (Foundry) ব্যবহার করে একটি স্থানীয় ব্লকচেইন চালান।
npx hardhat node
এনভায়রনমেন্ট: আপনার .env.local লোকালহোস্টকে নির্দেশ করতে সেট করুন।
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 ব্যবহার করে, আমরা ব্যবহার করেছি:
এই আর্কিটেকচার স্কেল করে। আপনি 10টি টিকিট বিক্রি করছেন বা 10,000, মেসেজ কিউ একটি বাফার হিসাবে কাজ করে, নিশ্চিত করে যে আপনার লেনদেন nonce-গুলি সংঘর্ষ করে না এবং আপনার সার্ভার হ্যাং হয় না।
ব্লকচেইন সংহত করতে নির্ভুলতা প্রয়োজন। যদি আপনার স্মার্ট কন্ট্র্যাক্ট ইন্টারঅ্যাকশন অডিট করতে বা আপনার Symfony মেসেজ কনজিউমার স্কেল করতে সাহায্যের প্রয়োজন হয়, চলুন যোগাযোগ করি।
\


