ADR-002 - Datenbankabstraktion
ADR-002: Datenbankabstraktion
Abschnitt betitelt „ADR-002: Datenbankabstraktion“Architecture Decision Record für XOOPS’s objekt-orientiertes Datenbankzugriffssmuster.
Akzeptiert - Kernmuster seit XOOPS 2.0
Context
Abschnitt betitelt „Context“XOOPS benötigte eine Datenbank-Interaktionsstrategie, die folgende Anforderungen erfüllte:
- Datenbank-spezifische SQL-Syntax abstrahieren
- Konsistente CRUD-Operationen für alle Module bieten
- Automatische Datenbereinigungs- und Escape-Operationen aktivieren
- Zukünftige Datenbankengineänderungen unterstützen
- Häufige Operationen für Entwickler vereinfachen
Die Alternativen waren:
- Raw SQL durchgehend im Codebase
- Vollständige ORM (Doctrine, Eloquent)
- Benutzerdefinierte leichte Abstraktion
Decision Diagram
Abschnitt betitelt „Decision Diagram“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 --> IDecision
Abschnitt betitelt „Decision“Wir werden ein Handler-Muster mit folgendem implementieren:
1. XoopsObject - Datencontainer
Abschnitt betitelt „1. XoopsObject - Datencontainer“Jede Datenentität erweitert XoopsObject:
<?phpclass 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); }}2. Handler - Operationen-Manager
Abschnitt betitelt „2. Handler - Operationen-Manager“Jedes Objekt hat einen entsprechenden Handler:
<?phpclass 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()}3. Criteria - Abfrage-Builder
Abschnitt betitelt „3. Criteria - Abfrage-Builder“Objekt-orientierte Abfragebedingungen:
<?php$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);Datentyp-Konstanten
Abschnitt betitelt „Datentyp-Konstanten“// Variable types with automatic sanitizationXOBJ_DTYPE_INT // IntegerXOBJ_DTYPE_TXTBOX // Single-line text (escaped)XOBJ_DTYPE_TXTAREA // Multi-line text (escaped)XOBJ_DTYPE_EMAIL // Email validationXOBJ_DTYPE_URL // URL validationXOBJ_DTYPE_ARRAY // Serialized arrayXOBJ_DTYPE_OTHER // No processingXOBJ_DTYPE_FLOAT // Floating pointHandler-Vererbung
Abschnitt betitelt „Handler-Vererbung“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 <|-- ItemHandlerConsequences
Abschnitt betitelt „Consequences“Positiv
Abschnitt betitelt „Positiv“- Konsistenz: Alle Module verwenden gleiche Muster
- Sicherheit: Automatisches Escaping verhindert SQL-Injection
- Einfachheit: Häufige Operationen erfordern minimalen Code
- Wartbarkeit: Datenbankschichtänderungen beeinflussen Module nicht
- Testbarkeit: Handler können für Tests gemockt werden
Negativ
Abschnitt betitelt „Negativ“- Leistung: Zusätzlicher Abstraktions-Overhead
- Komplexität: Lernkurve für neue Entwickler
- Limitierungen: Komplexe Abfragen benötigen möglicherweise Raw-SQL
- N+1 Problem: Kein eingebautes Eager Loading
Mitigationen
Abschnitt betitelt „Mitigationen“- Leistung: Häufig zugegriffene Objekte zwischenspeichern
- Komplexe Abfragen: Raw-SQL zulassen, wenn nötig
- N+1: getAll() mit ordentlichen Criteria verwenden
Evolution zu XOOPS 4.0
Abschnitt betitelt „Evolution zu XOOPS 4.0“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 --> GXOOPS 4.0 plant:
- Doctrine DBAL für Datenbankabstraktion
- Repository-Muster ersetzt Handler
- Query Builder für komplexe Abfragen
- Vollständige PSR-11-Container-Integration
Code-Beispiele
Abschnitt betitelt „Code-Beispiele“Basic CRUD
Abschnitt betitelt „Basic CRUD“<?php$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);Complex Query
Abschnitt betitelt „Complex Query“<?php$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);Related Decisions
Abschnitt betitelt „Related Decisions“- ADR-001: Modular Architecture
- ADR-003: Smarty Template Engine
References
Abschnitt betitelt „References“- Martin Fowler - Patterns of Enterprise Application Architecture
- Domain-Driven Design concepts
- Active Record vs Data Mapper patterns
#xoops #architecture #adr #database #handler #design-decision