Přeskočit na obsah

ADR-002 - Abstrakce databáze

ADR-002: Abstrakce databáze

Sekce “ADR-002: Abstrakce databáze”

Záznam rozhodnutí o architektuře pro vzor objektově orientovaného přístupu k databázi XOOPS.


Přijato – Vzor jádra od XOOPS 2.0


XOOPS potřeboval strategii interakce s databází, která by:

  1. Syntaxe SQL specifická pro databázi
  2. Zajistěte konzistentní operace CRUD napříč všemi moduly
  3. Povolte automatickou dezinfekci a únik dat
  4. Podporujte budoucí změny databázového stroje
  5. Zjednodušte vývojářům běžné operace

Alternativy byly:

  • Nezpracované SQL v celé kódové základně
  • Plná ORM (doktrína, výmluvná)
  • Vlastní lehká abstrakce

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

Implementujeme Vzor manipulátoru s:

1. XOOPSObject – datový kontejner

Sekce “1. XOOPSObject – datový kontejner”

Každá datová entita rozšiřuje 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);
}
}

2. Handler - Operations Manager

Sekce “2. Handler - Operations Manager”

Každý objekt má odpovídající 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. Kritéria – Tvůrce dotazů

Sekce “3. Kritéria – Tvůrce dotazů”

Podmínky objektově orientovaného dotazu:

$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);

Konstanty datového typu

Sekce “Konstanty datového typu”
// 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

Dědičnost manipulátoru

Sekce “Dědičnost manipulátoru”
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. Konzistence: Všechny moduly používají stejné vzory
  2. Zabezpečení: Automatický únik zabraňuje vstřikování SQL
  3. Jednoduchost: Běžné operace vyžadují minimální kód
  4. Udržovatelnost: Změny v databázové vrstvě neovlivňují moduly
  5. Testovatelnost: Obslužné rutiny lze pro testování zesměšňovat
  1. Výkon: Extra režie abstrakce
  2. Složitost: Křivka učení pro nové vývojáře
  3. Omezení: Komplexní dotazy mohou vyžadovat nezpracovaný SQL
  4. N+1 Problém: Žádné vestavěné dychtivé načítání
  • Výkon: Ukládání často používaných objektů do mezipaměti
  • Složité dotazy: V případě potřeby povolte nezpracované SQL
  • N+1: Použijte getAll() se správnými kritérii

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

Plány XOOPS 4.0:

  • Doktrína DBAL pro abstrakci databáze
  • Vzor úložiště nahrazující handlery
  • Tvůrce dotazů pro složité dotazy
  • Plná integrace kontejneru 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);

Související rozhodnutí

Sekce “Související rozhodnutí”
  • ADR-001: Modulární architektura
  • ADR-003: Smarty šablonový modul

  • Martin Fowler - Vzory podnikové aplikační architektury
  • Domain-Driven Design koncepty
  • Vzory Active Record vs Data Mapper

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