Lớp cơ sở dữ liệu
🗄️ Lớp cơ sở dữ liệu
Phần tiêu đề “🗄️ Lớp cơ sở dữ liệu”2.5.x ✅ 4.0.x ✅
Tìm hiểu về tính trừu tượng hóa cơ sở dữ liệu XOOPS, tính bền vững của đối tượng và xây dựng truy vấn.
Tổng quan
Phần tiêu đề “Tổng quan”Lớp cơ sở dữ liệu XOOPS cung cấp khả năng trừu tượng hóa mạnh mẽ trên MySQL/MariaDB, bao gồm:
- Mẫu nhà máy - Quản lý kết nối cơ sở dữ liệu tập trung
- Ánh xạ quan hệ đối tượng - XoopsObject và các trình xử lý
- Xây dựng truy vấn - Hệ thống tiêu chí cho các truy vấn phức tạp
- Tái sử dụng kết nối - Kết nối đơn thông qua nhà máy đơn lẻ (không gộp)
🏗️ Kiến trúc
Phần tiêu đề “🏗️ Kiến trúc”flowchart TB subgraph App["📱 Application Code"] AppCode["Your Module Code"] end
subgraph Handler["🔧 XoopsPersistableObjectHandler"] HandlerMethods["create() | get() | insert() | delete()<br/>getObjects() | getCount() | deleteAll()"] end
subgraph Object["📦 XoopsObject"] ObjectMethods["initVar() | getVar() | setVar() | toArray()"] end
subgraph Criteria["🔍 Criteria System"] CriteriaMethods["Criteria | CriteriaCompo | CriteriaElement"] end
subgraph Database["🗄️ XoopsDatabase"] DatabaseMethods["query() | queryF() | fetchArray() | insert()"] end
subgraph Storage["💾 MySQL / MariaDB"] DB[(Database)] end
App --> Handler Handler --> Object Object --> Criteria Criteria --> Database Database --> Storage
style App fill:#e3f2fd,stroke:#1976d2 style Handler fill:#e8f5e9,stroke:#388e3c style Object fill:#fff3e0,stroke:#f57c00 style Criteria fill:#f3e5f5,stroke:#7b1fa2 style Database fill:#fce4ec,stroke:#c2185b style Storage fill:#eceff1,stroke:#546e7a🔌 Kết nối cơ sở dữ liệu
Phần tiêu đề “🔌 Kết nối cơ sở dữ liệu”Nhận kết nối
Phần tiêu đề “Nhận kết nối”// Recommended: Use the global database instance$db = \XoopsDatabaseFactory::getDatabaseConnection();
// Legacy: Global variable (still works)global $xoopsDB;XoopsDatabaseFactory
Phần tiêu đề “XoopsDatabaseFactory”Mẫu nhà máy đảm bảo một kết nối cơ sở dữ liệu duy nhất được sử dụng lại:
<?php
class XoopsDatabaseFactory{ private static ?XoopsDatabase $instance = null;
public static function getDatabaseConnection(): XoopsDatabase { if (self::$instance === null) { self::$instance = new XoopsMySQLDatabase(); } return self::$instance; }}📦 XoopsObject
Phần tiêu đề “📦 XoopsObject”class cơ sở cho tất cả các đối tượng dữ liệu trong XOOPS.
Định nghĩa một đối tượng
Phần tiêu đề “Định nghĩa một đối tượng”<?php
namespace XoopsModules\MyModule;
class Article extends \XoopsObject{ public function __construct() { $this->initVar('article_id', \XOBJ_DTYPE_INT, null, false); $this->initVar('category_id', \XOBJ_DTYPE_INT, 0, true); $this->initVar('title', \XOBJ_DTYPE_TXTBOX, '', true, 255); $this->initVar('content', \XOBJ_DTYPE_TXTAREA, '', false); $this->initVar('author_id', \XOBJ_DTYPE_INT, 0, true); $this->initVar('status', \XOBJ_DTYPE_TXTBOX, 'draft', true, 20); $this->initVar('views', \XOBJ_DTYPE_INT, 0, false); $this->initVar('created', \XOBJ_DTYPE_INT, time(), false); $this->initVar('updated', \XOBJ_DTYPE_INT, 0, false); }}Kiểu dữ liệu
Phần tiêu đề “Kiểu dữ liệu”| Hằng số | Loại | Mô tả |
|---|---|---|
XOBJ_DTYPE_INT | Số nguyên | Giá trị số |
XOBJ_DTYPE_TXTBOX | Chuỗi | Văn bản ngắn (< 255 ký tự) |
XOBJ_DTYPE_TXTAREA | văn bản | Nội dung văn bản dài |
XOBJ_DTYPE_EMAIL | Địa chỉ email | |
XOBJ_DTYPE_URL | URL | Địa chỉ web |
XOBJ_DTYPE_FLOAT | Phao | Số thập phân |
XOBJ_DTYPE_ARRAY | Mảng | Mảng nối tiếp |
XOBJ_DTYPE_OTHER | Hỗn hợp | Dữ liệu thô |
Làm việc với các đối tượng
Phần tiêu đề “Làm việc với các đối tượng”// Create new object$article = new Article();
// Set values$article->setVar('title', 'My Article');$article->setVar('content', 'Article content here...');$article->setVar('category_id', 5);$article->setVar('author_id', $xoopsUser->getVar('uid'));
// Get values$title = $article->getVar('title'); // Raw value$titleDisplay = $article->getVar('title', 'e'); // For editing (HTML entities)$titleShow = $article->getVar('title', 's'); // For display (sanitized)
// Bulk assign from array$article->assignVars([ 'title' => 'New Title', 'status' => 'published']);
// Convert to array$data = $article->toArray();🔧 Trình xử lý đối tượng
Phần tiêu đề “🔧 Trình xử lý đối tượng”XoopsPersistableObjectHandler
Phần tiêu đề “XoopsPersistableObjectHandler”Trình xử lý class quản lý các hoạt động CRUD cho các phiên bản XoopsObject.
<?php
namespace XoopsModules\MyModule;
class ArticleHandler extends \XoopsPersistableObjectHandler{ public function __construct(\XoopsDatabase $db = null) { parent::__construct( $db, 'mymodule_articles', // Table name Article::class, // Object class 'article_id', // Primary key 'title' // Identifier field ); }}Phương thức xử lý
Phần tiêu đề “Phương thức xử lý”// Get handler instance$articleHandler = xoops_getModuleHandler('article', 'mymodule');
// Create new object$article = $articleHandler->create();
// Get by ID$article = $articleHandler->get(123);
// Insert (create or update)$success = $articleHandler->insert($article);
// Delete$success = $articleHandler->delete($article);
// Get multiple objects$articles = $articleHandler->getObjects($criteria);
// Get count$count = $articleHandler->getCount($criteria);
// Get as array (key => value)$list = $articleHandler->getList($criteria);
// Delete multiple$deleted = $articleHandler->deleteAll($criteria);Phương thức xử lý tùy chỉnh
Phần tiêu đề “Phương thức xử lý tùy chỉnh”<?php
namespace XoopsModules\MyModule;
class ArticleHandler extends \XoopsPersistableObjectHandler{ // ... constructor
/** * Get published articles */ public function getPublished(int $limit = 10, int $start = 0): array { $criteria = new \CriteriaCompo(); $criteria->add(new \Criteria('status', 'published')); $criteria->setSort('created'); $criteria->setOrder('DESC'); $criteria->setLimit($limit); $criteria->setStart($start);
return $this->getObjects($criteria); }
/** * Get articles by category */ public function getByCategory(int $categoryId, int $limit = 10): array { $criteria = new \CriteriaCompo(); $criteria->add(new \Criteria('category_id', $categoryId)); $criteria->add(new \Criteria('status', 'published')); $criteria->setSort('created'); $criteria->setOrder('DESC'); $criteria->setLimit($limit);
return $this->getObjects($criteria); }
/** * Get articles by author */ public function getByAuthor(int $authorId): array { $criteria = new \Criteria('author_id', $authorId); return $this->getObjects($criteria); }
/** * Increment view count */ public function incrementViews(int $articleId): bool { $sql = sprintf( 'UPDATE %s SET views = views + 1 WHERE article_id = %d', $this->table, $articleId ); return $this->db->queryF($sql) !== false; }
/** * Get popular articles */ public function getPopular(int $limit = 5): array { $criteria = new \CriteriaCompo(); $criteria->add(new \Criteria('status', 'published')); $criteria->setSort('views'); $criteria->setOrder('DESC'); $criteria->setLimit($limit);
return $this->getObjects($criteria); }}🔍 Hệ thống tiêu chí
Phần tiêu đề “🔍 Hệ thống tiêu chí”Hệ thống Tiêu chí cung cấp một cách mạnh mẽ, hướng đối tượng để xây dựng các mệnh đề SQL WHERE.
Tiêu chí cơ bản
Phần tiêu đề “Tiêu chí cơ bản”// Simple equality$criteria = new \Criteria('status', 'published');
// With operator$criteria = new \Criteria('views', 100, '>=');
// Column comparison$criteria = new \Criteria('updated', 'created', '>');CriteriaCompo (Tiêu chí kết hợp)
Phần tiêu đề “CriteriaCompo (Tiêu chí kết hợp)”$criteria = new \CriteriaCompo();
// AND conditions (default)$criteria->add(new \Criteria('status', 'published'));$criteria->add(new \Criteria('category_id', 5));
// OR conditions$criteria->add(new \Criteria('featured', 1), 'OR');
// Nested conditions$subCriteria = new \CriteriaCompo();$subCriteria->add(new \Criteria('author_id', 1));$subCriteria->add(new \Criteria('author_id', 2), 'OR');$criteria->add($subCriteria);Sắp xếp và phân trang
Phần tiêu đề “Sắp xếp và phân trang”$criteria = new \CriteriaCompo();$criteria->add(new \Criteria('status', 'published'));
// Sorting$criteria->setSort('created');$criteria->setOrder('DESC');
// Multiple sort fields$criteria->setSort('category_id, created');$criteria->setOrder('ASC, DESC');
// Pagination$criteria->setLimit(10); // Items per page$criteria->setStart(20); // Offset
// Group by$criteria->setGroupby('category_id');Người vận hành
Phần tiêu đề “Người vận hành”| Nhà điều hành | Ví dụ | Đầu ra SQL |
|---|---|---|
= | new Criteria('status', 'published') | status = 'published' |
!= | new Criteria('status', 'draft', '!=') | status != 'draft' |
> | new Criteria('views', 100, '>') | views > 100 |
>= | new Criteria('views', 100, '>=') | views >= 100 |
< | new Criteria('views', 100, '<') | views < 100 |
<= | new Criteria('views', 100, '<=') | views <= 100 |
LIKE | new Criteria('title', '%php%', 'LIKE') | title LIKE '%php%' |
NOT LIKE | new Criteria('title', '%test%', 'NOT LIKE') | title NOT LIKE '%test%' |
IN | new Criteria('id', '(1,2,3)', 'IN') | id IN (1,2,3) |
NOT IN | new Criteria('id', '(1,2,3)', 'NOT IN') | id NOT IN (1,2,3) |
Ví dụ phức tạp
Phần tiêu đề “Ví dụ phức tạp”// Find published articles in specific categories,// with search term in title, sorted by views$criteria = new \CriteriaCompo();
// Status must be published$criteria->add(new \Criteria('status', 'published'));
// In categories 1, 2, or 3$criteria->add(new \Criteria('category_id', '(1, 2, 3)', 'IN'));
// Title contains search term$searchTerm = '%' . $db->escape($searchQuery) . '%';$criteria->add(new \Criteria('title', $searchTerm, 'LIKE'));
// Created in last 30 days$thirtyDaysAgo = time() - (30 * 24 * 60 * 60);$criteria->add(new \Criteria('created', $thirtyDaysAgo, '>='));
// Sort by views descending$criteria->setSort('views');$criteria->setOrder('DESC');
// Paginate$criteria->setLimit(10);$criteria->setStart($page * 10);
$articles = $articleHandler->getObjects($criteria);$totalCount = $articleHandler->getCount($criteria);📝 Truy vấn trực tiếp
Phần tiêu đề “📝 Truy vấn trực tiếp”Đối với các truy vấn phức tạp không thể thực hiện được bằng Tiêu chí, hãy sử dụng SQL trực tiếp.### Truy vấn an toàn (Đọc)
$db = \XoopsDatabaseFactory::getDatabaseConnection();
$sql = sprintf( 'SELECT a.*, c.category_name FROM %s a LEFT JOIN %s c ON a.category_id = c.category_id WHERE a.status = %s ORDER BY a.created DESC LIMIT %d', $db->prefix('mymodule_articles'), $db->prefix('mymodule_categories'), $db->quoteString('published'), 10);
$result = $db->query($sql);
while ($row = $db->fetchArray($result)) { // Process row echo $row['title'];}Viết truy vấn
Phần tiêu đề “Viết truy vấn”// Insert$sql = sprintf( "INSERT INTO %s (title, content, created) VALUES (%s, %s, %d)", $db->prefix('mymodule_articles'), $db->quoteString($title), $db->quoteString($content), time());$db->queryF($sql);$newId = $db->getInsertId();
// Update$sql = sprintf( "UPDATE %s SET views = views + 1 WHERE article_id = %d", $db->prefix('mymodule_articles'), $articleId);$db->queryF($sql);$affectedRows = $db->getAffectedRows();
// Delete$sql = sprintf( "DELETE FROM %s WHERE article_id = %d", $db->prefix('mymodule_articles'), $articleId);$db->queryF($sql);Giá trị thoát
Phần tiêu đề “Giá trị thoát”// String escaping$safeString = $db->quoteString($userInput);// or$safeString = $db->escape($userInput);
// Integer (no escaping needed, just cast)$safeInt = (int) $userInput;⚠️ Các phương pháp bảo mật tốt nhất
Phần tiêu đề “⚠️ Các phương pháp bảo mật tốt nhất”Luôn thoát khỏi thao tác nhập của người dùng
Phần tiêu đề “Luôn thoát khỏi thao tác nhập của người dùng”// NEVER do this$sql = "SELECT * FROM articles WHERE title = '$_GET[title]'"; // SQL Injection!
// DO this$title = $db->escape($_GET['title']);$sql = "SELECT * FROM articles WHERE title = '$title'";
// Or better, use Criteria$criteria = new \Criteria('title', $db->escape($_GET['title']));Sử dụng truy vấn được tham số hóa (XMF)
Phần tiêu đề “Sử dụng truy vấn được tham số hóa (XMF)”use Xmf\Database\TableLoad;
// Safe bulk insert$tableLoad = new TableLoad('mymodule_articles');$tableLoad->insert([ ['title' => 'Article 1', 'content' => 'Content 1'], ['title' => 'Article 2', 'content' => 'Content 2'],]);Xác thực loại đầu vào
Phần tiêu đề “Xác thực loại đầu vào”use Xmf\Request;
$id = Request::getInt('id', 0, 'GET');$title = Request::getString('title', '', 'POST');📊 Ví dụ về lược đồ cơ sở dữ liệu
Phần tiêu đề “📊 Ví dụ về lược đồ cơ sở dữ liệu”-- sql/mysql.sql
CREATE TABLE `{PREFIX}_mymodule_articles` ( `article_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `category_id` INT(11) UNSIGNED NOT NULL DEFAULT 0, `title` VARCHAR(255) NOT NULL DEFAULT '', `content` TEXT, `author_id` INT(11) UNSIGNED NOT NULL DEFAULT 0, `status` VARCHAR(20) NOT NULL DEFAULT 'draft', `views` INT(11) UNSIGNED NOT NULL DEFAULT 0, `created` INT(11) UNSIGNED NOT NULL DEFAULT 0, `updated` INT(11) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`article_id`), KEY `category_id` (`category_id`), KEY `author_id` (`author_id`), KEY `status` (`status`), KEY `created` (`created`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;🔗 Tài liệu liên quan
Phần tiêu đề “🔗 Tài liệu liên quan”#xoops #database #orm #criteria #handlers #mysql