Building a Decentralized Event Ticketing System Web3 with Symfony 7.4
Building a Web3 with
In the fast-evolving world of Web3, traditional event ticketing systems are facing massive challenges. Scalping, counterfeit tickets, and lack of transparency plague centralized platforms like Ticketmaster. Enter
This comprehensive guide dives deep into
Why Build a in Web3?
Centralized ticketing has issues:
- Fraud and Scalping: Bots snatch tickets and resell at exorbitant prices.
- No Ownership: Buyers don’t truly own their tickets.
- High Fees: Middlemen take massive cuts.
A Web3 solution flips the script:
- NFT-based tickets ensure authenticity and transferability on the blockchain.
- Smart contracts automate royalties for artists and prevent unauthorized resales.
- Users control their tickets via wallets like MetaMask.
With
Tech Stack Overview
| Component | Technology |
|---|---|
| Backend Framework | Symfony 7.4 |
| Blockchain | Ethereum (Sepolia Testnet) |
| Smart Contracts | Solidity (ERC-721 NFTs) |
| PHP Web3 Library | web3p/web3.php |
| Database | Doctrine ORM (PostgreSQL) |
| Frontend (Optional) | React + Ethers.js |
| Deployment | Docker + Vercel/Netlify for frontend, Railway/Heroku for backend |
Prerequisites
- PHP 8.2+ and Composer installed.
- Node.js for smart contract compilation (Hardhat).
- MetaMask wallet and Sepolia ETH (free from faucets).
- Basic knowledge of Symfony, Solidity, and APIs.
Step 1: Set Up Your Project
Create a new Symfony project:
composer create-project symfony/skeleton:"7.4.*" web3-ticketing
cd web3-ticketing
composer require web3p/web3.php
composer require doctrine orm maker api
Configure your database in .env:
DATABASE_URL="postgresql://user:pass@127.0.0.1:5432/ticketing?serverVersion=15&charset=utf8"
Install assets and create the database:
php bin/console doctrine:database:create
php bin/console make:entity EventTicket
Define the EventTicket entity with fields like id, eventName, tokenId (NFT ID), ownerAddress, and price.
Step 2: Develop the Smart Contract for NFT Tickets
In a separate contracts/ folder, use Hardhat:
npx hardhat init
npm install @openzeppelin/contracts dotenv
Create TicketingNFT.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract TicketingNFT is ERC721, Ownable {
uint256 private _nextTokenId;
constructor(address initialOwner) ERC721("EventTicket", "TKT") Ownable(initialOwner) {}
function mint(address to, uint256 quantity) external onlyOwner {
for(uint256 i = 0; i < quantity; i++) {
_mint(to, _nextTokenId);
_nextTokenId++;
}
}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _nextTokenId;
_nextTokenId++;
_safeMint(to, tokenId);
}
}
Compile and deploy to Sepolia:
npx hardhat run scripts/deploy.js --network sepolia
Note your contract address – you'll need it!
Step 3: Integrate Web3 with Backend
Install web3.php:
composer require web3p/web3.php
Create a service src/Service/Web3Service.php:
<?php
namespace App\Service;
use Web3\Web3;
use Web3\Contract;
class Web3Service
{
private Web3 $web3;
private string $contractAddress;
public function __construct()
{
$this->web3 = new Web3('https://sepolia.infura.io/v3/YOUR_INFURA_KEY');
$this->contractAddress = 'YOUR_CONTRACT_ADDRESS';
}
public function getTicketOwner(int $tokenId): string
{
$abi = json_decode(file_get_contents('abi.json'), true);
$contract = new Contract($this->web3->provider, $abi);
$contract->at($this->contractAddress);
$result = $contract->ownerOf($tokenId)->send();
return $result[0];
}
// More methods: mint, transfer, etc.
}
Step 4: Build API Endpoints
Generate a controller:
php bin/console make:controller TicketController
In TicketController.php:
#[Route('/api/tickets/{tokenId}', name: 'ticket_info')]
public function getTicket(int $tokenId, Web3Service $web3): JsonResponse
{
$owner = $web3->getTicketOwner($tokenId);
return new JsonResponse(['owner' => $owner]);
}
Secure with API keys or JWT for production.
Step 5: Frontend Integration (Quick Example)
Connect React frontend to your Symfony API and MetaMask:
import { ethers } from 'ethers';
const mintTicket = async () => {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer);
const tx = await contract.safeMint(signer.address);
await tx.wait();
// Call Symfony API to sync off-chain data
};
Step 6: Testing and Deployment
Test with PHPUnit and Postman. Deploy backend to Railway:
- Dockerize your app.
- Set env vars for Infura and DB.
Challenges to watch:
- Gas fees – use Layer 2 like Polygon.
- Oracle integration for event verification.
- Scalability – Symfony Messenger for queues.
Benefits of This
- Immutable Ownership: NFTs can't be faked.
- Programmable Royalties: 10% auto-resale fee to organizers.
- Global Access: No geo-restrictions.
- Low Cost: Symfony's efficiency + blockchain optimization.
Conclusion
Ready to launch? Fork the code on GitHub (link in bio) and share your builds in the comments.
FAQ
Q: Can I use this for production?
A: Yes, after audits and Layer 2 migration.
Q: Alternatives to Symfony?
A: Laravel or NestJS, but Symfony excels in APIs.
Q: Mainnet ready?
A: Test on Sepolia first!