ADR-002 - Database-abstractie
ADR-002: Database-abstractie
Section titled “ADR-002: Database-abstractie”Architectuurbeslissingsrecord voor het objectgeoriënteerde databasetoegangspatroon van XOOPS.
Status
Section titled “Status”Geaccepteerd - Kernpatroon sinds XOOPS 2.0
Context
Section titled “Context”XOOPS had een database-interactiestrategie nodig die:
- Abstracteer database-specifieke SQL-syntaxis
- Zorg voor consistente CRUD-bewerkingen in alle modules
- Schakel automatische gegevensopschoning en ontsnapping in
- Ondersteuning van toekomstige wijzigingen in de database-engine
- Vereenvoudig algemene handelingen voor ontwikkelaars
De alternatieven waren:
- Raw SQL in de hele codebase
- Volledige ORM (doctrine, welsprekend)
- Aangepaste lichtgewicht abstractie
Beslissingsdiagram
Section titled “Beslissingsdiagram”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 --> IBesluit
Section titled “Besluit”We zullen een Handler-patroon implementeren met:
1. XoopsObject - Gegevenscontainer
Section titled “1. XoopsObject - Gegevenscontainer”Elke gegevensentiteit breidt XoopsObject uit:
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); }}2. Handler - Operationeel manager
Section titled “2. Handler - Operationeel manager”Elk object heeft een bijbehorende handler:
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()}3. Criteria - Querybouwer
Section titled “3. Criteria - Querybouwer”Objectgeoriënteerde queryvoorwaarden:
$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);Gegevenstypeconstanten
Section titled “Gegevenstypeconstanten”// 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 pointOvererving van de handler
Section titled “Overerving van de handler”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 <|-- ItemHandlerGevolgen
Section titled “Gevolgen”Positief
Section titled “Positief”- Consistentie: Alle modules gebruiken dezelfde patronen
- Beveiliging: automatisch ontsnappen voorkomt injectie met SQL
- Eenvoud: algemene bewerkingen vereisen minimale code
- Onderhoudbaarheid: wijzigingen in de databaselaag hebben geen invloed op modules
- Testbaarheid: Handlers kunnen worden bespot voor het testen
Negatief
Section titled “Negatief”- Prestaties: Extra abstractie-overhead
- Complexiteit: leercurve voor nieuwe ontwikkelaars
- Beperkingen: voor complexe zoekopdrachten is mogelijk onbewerkte SQL nodig
- N+1 Probleem: Geen ingebouwd gretig laden
Mitigaties
Section titled “Mitigaties”- Prestaties: Cache van veelgebruikte objecten
- Complexe zoekopdrachten: sta onbewerkte SQL toe wanneer dat nodig is
- N+1: Gebruik getAll() met de juiste criteria
Evolutie naar XOOPS 4.0
Section titled “Evolutie naar 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-abonnementen:
- Doctrine DBAL voor database-abstractie
- Repositorypatroon ter vervanging van handlers
- Querybuilder voor complexe queries
- Volledige PSR-11 containerintegratie
Codevoorbeelden
Section titled “Codevoorbeelden”Basis CRUD
Section titled “Basis CRUD”$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);Complexe zoekopdracht
Section titled “Complexe zoekopdracht”$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);Gerelateerde beslissingen
Section titled “Gerelateerde beslissingen”- ADR-001: modulaire architectuur
- ADR-003: Smarty-sjabloonengine
Referenties
Section titled “Referenties”- Martin Fowler - Patronen van Enterprise Application Architecture
- Domeingestuurde ontwerpconcepten
- Actieve Record versus Data Mapper-patronen
#xoops #architectuur #adr #database #handler #design-decision