Overview
This project consists of an object-oriented PHP system designed to manage and render data for Magic: The Gathering cards. The system employs a layered architecture, separating all data handling (queries, retrieval) from the presentation layer (HTML rendering, filtering).
The core functions are managed by two classes:
MtgRepository: Handles all database operations, querying themtg_cardstable and returning structured results.MtgRenderer: Responsible for rendering HTML for filters, card lists, and card details, combining PHP output buffering with HTML templates for flexibility.
⚙️ Technical Stack
| Area | Technologies |
|---|---|
| Backend | PHP (OOP design), PDO |
| Data Source | MySQL/SQL (querying the mtg_cards table) |
| Rendering | PHP Output Buffering, HTML, SVG (for symbols) |
| Filtering | POST/GET parameter handling |
Architecture & Design
The architecture is built around clear separation of concerns using two primary classes:
- Database Access: The
MtgRepositoryclass requires and utilizes aDatabase.phpfile to establish a connection via PDO (Database::getConnection()). This repository handles complex data retrieval, such as fetching cards with filters, limits, and offsets, or retrieving print variants using theoracle_id. - Presentation Logic: The
MtgRenderermanages the display. It requires an instance ofMtgRepositoryduring its construction. It uses PHP output buffering (ob_start()andob_get_clean()) to build complex HTML structures, such as filter forms and card grids. - Input Sanitization: A private
sanitize()method is implemented within theMtgRendererto protect against Cross-Site Scripting (XSS).
Features
The system provides robust features for filtering and displaying card data:
- Filter Generation: The system dynamically fetches distinct card properties from the database to build HTML filter forms, including types, rarities, and editions (sets).
- SQL Filtering: It can construct SQL-safe WHERE conditions by processing user input from POST/GET parameters for type, edition, rarity, and color identity. For colors, it uses a defined mapping of single-letter keys (U, B, R, W, G) to their full names (Blue, Black, Red, White, Green).
- Detailed Card View: The
getCard()method retrieves detailed card information, includingprices,oracle_text,released_at, andrarity. - Symbol Rendering: When displaying the card's
oracle_text, the renderer processes placeholders (e.g.,{W},{T}) and replaces them with the contents of the corresponding SVG files stored in a designated folder. It sanitizes the SVG content and adds inline styling to scale it to text height. - Variant Display: It supports listing other printings of the same card by querying all cards sharing the same
oracle_id. - Set Collection Display: It can retrieve a random sample of 12 cards from the same collection/set using
ORDER BY RAND().
Challenges & Solutions
- Challenge: Accurately fetching general card types (e.g., "Creature") when the database field (
type_line) might contain subtypes (e.g., "Creature — Goblin").- Solution: The
getTypes()method uses aCASE WHENstatement and string manipulation functions (LOCATEandSUBSTRING) in SQL to strip the subtype if an '—' is found, returning only the primary type.
- Solution: The
- Challenge: Securely passing dynamic variables (like pagination controls) into SQL queries.
- Solution: The
getCards()method utilizes prepared statements ($this->pdo->prepare($sql)) and explicitly binds variables usingPDO::PARAM_INTfor the$limitand$offsetparameters.
- Solution: The
- Challenge: Rendering complex text containing custom card symbols.
- Solution: The
displayCard()method usespreg_replace_callbackto find symbols enclosed in braces ({...}) and replaces them with sanitized, injected SVG code fetched from local files, ensuring the symbols scale appropriately within the text.
- Solution: The
Code Snippets
The core responsibility of the repository is defined in its initialization:
require_once __DIR__ . '/Database.php';
/**
* Class MtgRepository
*
* Handles all database operations for Magic: The Gathering card data.
* Responsible for querying the mtg_cards table and returning structured results.
*/
class MtgRepository {
private PDO $pdo;
public function __construct() {
$this->pdo = Database::getConnection();
}
// ... methods for fetching data ...
The method for fetching distinct card types demonstrates how complex SQL logic is used to clean data:
SELECT DISTINCT
CASE WHEN LOCATE('—', type_line) > 0 THEN SUBSTRING(type_line, 1, LOCATE('—', type_line) - 1)
ELSE type_line
END AS value
FROM mtg_cards
ORDER BY type_line;
Results & Learnings
This project demonstrates proficiency in building a robust, data-driven application using Object-Oriented PHP. Key learning outcomes include managing complex data transformation within SQL, implementing secure and parameterized queries, and employing advanced text processing with preg_replace_callback to integrate visual assets (SVGs) into dynamic text content. It provides a scalable structure for handling large, complex datasets like those found in Magic: The Gathering.
Future roadmap
- ✅ Pagination for card list
- ✅ Monthly card price update
- Add the remaining cards (may take a while, they are not physically with me)









