跳转到内容

“ADR-002 - 数据库抽象”

XOOPS 对象-oriented 数据库访问模式的架构决策记录。


已接受 - 自 XOOPS 2.0 起的核心模式


XOOPS 需要一个数据库交互策略:

1.抽象数据库-specificSQL语法 2. 跨所有模区块提供一致的CRUD操作 3.启用自动数据清理和转义 4.支持未来数据库引擎的变更 5、简化开发者常用操作

替代方案是:

  • 整个代码库中的原始SQL
  • 完整ORM(教义,雄辩)
  • 自定义轻量级抽象

graph TB
subgraph "Application Layer"
A[Module Code]
B[Handler Methods]
end
subgraph "Abstraction Layer"
C[XoopsObjectHandler]
D[XoopsPersistableObjectHandler]
E[Criteria System]
end
subgraph "Database Layer"
F[XoopsDatabase]
G[MySQLDatabase]
H[PDO Wrapper]
end
subgraph "Storage"
I[(MySQL/MariaDB)]
end
A --> B
B --> C
B --> D
C --> E
D --> E
E --> F
F --> G
F --> H
G --> I
H --> I

我们将通过以下方式实现 处理程序模式

每个数据实体都扩展 XOOPSObject:

class Item extends XoopsObject
{
public function __construct()
{
$this->initVar('id', XOBJ_DTYPE_INT, null, false);
$this->initVar('title', XOBJ_DTYPE_TXTBOX, '', true, 255);
$this->initVar('content', XOBJ_DTYPE_TXTAREA, '', false);
$this->initVar('status', XOBJ_DTYPE_INT, 0, false);
}
}

每个对象都有一个对应的处理程序:

class ItemHandler extends XoopsPersistableObjectHandler
{
public function __construct($db)
{
parent::__construct($db, 'mymodule_items', Item::class, 'id', 'title');
}
// CRUD methods inherited:
// - create(), get(), insert(), delete()
// - getObjects(), getCount(), getAll()
}

对象-oriented查询条件:

$criteria = new CriteriaCompo();
$criteria->add(new Criteria('status', 1));
$criteria->add(new Criteria('created', time() - 86400, '>='));
$criteria->setSort('created');
$criteria->setOrder('DESC');
$criteria->setLimit(10);
$items = $handler->getObjects($criteria);

// Variable types with automatic sanitization
XOBJ_DTYPE_INT // Integer
XOBJ_DTYPE_TXTBOX // Single-line text (escaped)
XOBJ_DTYPE_TXTAREA // Multi-line text (escaped)
XOBJ_DTYPE_EMAIL // Email validation
XOBJ_DTYPE_URL // URL validation
XOBJ_DTYPE_ARRAY // Serialized array
XOBJ_DTYPE_OTHER // No processing
XOBJ_DTYPE_FLOAT // Floating point

classDiagram
class XoopsObjectHandler {
<<abstract>>
#db: XoopsDatabase
+create(): XoopsObject
+get(id): XoopsObject
+insert(object): bool
+delete(object): bool
}
class XoopsPersistableObjectHandler {
+getObjects(criteria): array
+getCount(criteria): int
+getAll(criteria): array
+deleteAll(criteria): bool
+updateAll(field, value, criteria): bool
}
class ItemHandler {
+getPublishedItems(): array
+getByCategory(catId): array
}
XoopsObjectHandler <|-- XoopsPersistableObjectHandler
XoopsPersistableObjectHandler <|-- ItemHandler

  1. 一致性:所有模区块使用相同的模式
  2. 安全:自动转义防止SQL注入
  3. 简单:常用操作需要最少的代码
  4. 可维护性:数据库层的更改不会影响模区块
  5. 可测试性:可以模拟处理程序以进行测试
  1. 性能:额外的抽象开销
  2. 复杂性:新开发人员的学习曲线
  3. 限制:复杂查询可能需要原始SQL
  4. N+1问题:未构建-in急切加载
  • 性能:缓存经常访问的对象
  • 复杂查询:需要时允许原始SQL
  • N+1:按照适当的标准使用getAll()

flowchart LR
subgraph "Current (2.5.x)"
A[XoopsDatabase]
B[Handlers]
C[Criteria]
end
subgraph "Future (4.0.x)"
D[PDO/DBAL]
E[Repository Pattern]
F[Query Builder]
G[DI Container]
end
A --> D
B --> E
C --> F
D --> G
E --> G

XOOPS 4.0 计划:

  • 数据库抽象的原则DBAL
  • 存储库模式替换处理程序
  • 用于复杂查询的查询构建器
  • 完整的PSR-11容器集成

$helper = Helper::getInstance();
$handler = $helper->getHandler('Item');
// Create
$item = $handler->create();
$item->setVar('title', 'New Item');
$handler->insert($item);
// Read
$item = $handler->get($id);
$title = $item->getVar('title');
// Update
$item->setVar('title', 'Updated Title');
$handler->insert($item);
// Delete
$handler->delete($item);
$criteria = new CriteriaCompo();
$criteria->add(new Criteria('status', 'published'));
$criteria->add(new Criteria('category_id', '(1,2,3)', 'IN'));
$criteria->add(new Criteria('created', strtotime('-30 days'), '>='));
$criteria->setSort('views');
$criteria->setOrder('DESC');
$criteria->setLimit(10);
$criteria->setStart(0);
$items = $handler->getObjects($criteria);
$total = $handler->getCount($criteria);

  • ADR-001:模区块化架构
  • ADR-003:Smarty模板引擎

  • Martin Fowler - 企业应用程序架构模式
  • 领域-Driven设计理念
  • Active Record 与 Data Mapper 模式

#XOOPS #architecture #adr #database #handler #design-decision