ADR-002 - Abstrakcja bazy danych
ADR-002: Abstrakcja bazy danych
Dział zatytułowany „ADR-002: Abstrakcja bazy danych”Rekord decyzji architektonicznej dla wzorca dostępu do bazy danych zorientowanego obiektowo w XOOPS.
Accepted - Wzorzec rdzenia od XOOPS 2.0
Kontekst
Dział zatytułowany „Kontekst”XOOPS potrzebował strategii interakcji z bazą danych, która by:
- Abstrahowała składnię SQL specyficzną dla bazy danych
- Zapewniała spójne operacje CRUD na wszystkich modułach
- Umożliwiała automatyczne oczyszczanie i escaping danych
- Wspierała przyszłe zmiany silnika bazy danych
- Uproszczała typowe operacje dla programistów
Alternatywy były:
- Raw SQL w całej bazie kodu
- Pełny ORM (Doctrine, Eloquent)
- Niestandardowa lekka abstrakcja
Diagram decyzji
Dział zatytułowany „Diagram decyzji”graph TB subgraph "Warstwa aplikacji" A[Kod modułu] B[Metody handlera] end
subgraph "Warstwa abstrakcji" C[XoopsObjectHandler] D[XoopsPersistableObjectHandler] E[System kryteriów] end
subgraph "Warstwa bazy danych" F[XoopsDatabase] G[MySQLDatabase] H[Wrapper PDO] end
subgraph "Pamięć masowa" I[(MySQL/MariaDB)] end
A --> B B --> C B --> D C --> E D --> E E --> F F --> G F --> H G --> I H --> IDecyzja
Dział zatytułowany „Decyzja”Wdrożymy Wzorzec handlera z:
1. XoopsObject - Kontener danych
Dział zatytułowany „1. XoopsObject - Kontener danych”Każda jednostka danych rozszerza 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 - Menadżer operacji
Dział zatytułowany „2. Handler - Menadżer operacji”Każdy obiekt ma odpowiadający handler:
class ItemHandler extends XoopsPersistableObjectHandler{ public function __construct($db) { parent::__construct($db, 'mymodule_items', Item::class, 'id', 'title'); }
// Odziedziczone metody CRUD: // - create(), get(), insert(), delete() // - getObjects(), getCount(), getAll()}3. Criteria - Konstruktor zapytań
Dział zatytułowany „3. Criteria - Konstruktor zapytań”Warunki zapytań zorientowane obiektowo:
$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);Stałe typu danych
Dział zatytułowany „Stałe typu danych”// Typy zmiennych z automatycznym oczyszczaniemXOBJ_DTYPE_INT // Liczba całkowitaXOBJ_DTYPE_TXTBOX // Tekst jednolinijkowy (escaped)XOBJ_DTYPE_TXTAREA // Tekst wielolinijkowy (escaped)XOBJ_DTYPE_EMAIL // Weryfikacja poczty elektronicznejXOBJ_DTYPE_URL // Weryfikacja URLXOBJ_DTYPE_ARRAY // Serializowana tablicaXOBJ_DTYPE_OTHER // Bez przetwarzaniaXOBJ_DTYPE_FLOAT // ZmiennoprzecinkowyDziedziczenie handlera
Dział zatytułowany „Dziedziczenie handlera”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 <|-- ItemHandlerKonsekwencje
Dział zatytułowany „Konsekwencje”Pozytywne
Dział zatytułowany „Pozytywne”- Konsystencja: Wszystkie moduły używają tych samych wzorców
- Bezpieczeństwo: Automatyczne escaping zapobiega wstrzyknięciom SQL
- Prostota: Typowe operacje wymagają minimalnego kodu
- Utrzymywalność: Zmiany w warstwie bazy danych nie wpływają na moduły
- Testowalność: Handlery mogą być mockowane do testowania
Negatywne
Dział zatytułowany „Negatywne”- Wydajność: Dodatkowy narzut abstrakcji
- Złożoność: Krzywa nauki dla nowych programistów
- Ograniczenia: Złożone zapytania mogą wymagać raw SQL
- Problem N+1: Brak wbudowanego eager loadingu
Łagodzenie
Dział zatytułowany „Łagodzenie”- Wydajność: Buforuj często dostępne obiekty
- Złożone zapytania: Pozwalaj raw SQL gdy potrzeba
- N+1: Użyj getAll() z odpowiednimi kryteriami
Ewolucja do XOOPS 4.0
Dział zatytułowany „Ewolucja do XOOPS 4.0”flowchart LR subgraph "Aktualne (2.5.x)" A[XoopsDatabase] B[Handlery] C[Kryteria] end
subgraph "Przyszłe (4.0.x)" D[PDO/DBAL] E[Wzorzec repozytorium] F[Konstruktor zapytań] G[Kontener DI] end
A --> D B --> E C --> F D --> G E --> GPlany XOOPS 4.0:
- Doctrine DBAL dla abstrakcji bazy danych
- Wzorzec repozytorium zastępujący handlery
- Konstruktor zapytań dla złożonych zapytań
- Pełna integracja kontenera PSR-11
Przykłady kodu
Dział zatytułowany „Przykłady kodu”Podstawowa operacja CRUD
Dział zatytułowany „Podstawowa operacja CRUD”$helper = Helper::getInstance();$handler = $helper->getHandler('Item');
// Utwórz$item = $handler->create();$item->setVar('title', 'Nowy element');$handler->insert($item);
// Czytaj$item = $handler->get($id);$title = $item->getVar('title');
// Aktualizuj$item->setVar('title', 'Zaktualizowany tytuł');$handler->insert($item);
// Usuń$handler->delete($item);Złożone zapytanie
Dział zatytułowany „Złożone zapytanie”$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);Powiązane decyzje
Dział zatytułowany „Powiązane decyzje”- ADR-001: Architektura modularna
- ADR-003: Silnik szablonów Smarty
Odwołania
Dział zatytułowany „Odwołania”- Martin Fowler - Patterns of Enterprise Application Architecture
- Koncepcje Domain-Driven Design
- Wzorce Active Record vs Data Mapper
#xoops #architektura #adr #baza-danych #handler #decyzja-projektowa