Integrace databází a ORM v PHP
Integrace databází patří v ekosystému PHP mezi nejčastější úkoly. Volba přístupu – od „čistého“ PDO, přes query builder, až po plnohodnotné ORM (Object–Relational Mapping) – zásadně ovlivňuje bezpečnost, výkon, udržovatelnost i rychlost vývoje. Tento článek shrnuje architektonické styly, klíčové koncepty ORM, výhody a nevýhody různých přístupů, best practices, výkonové optimalizace a specifika nejrozšířenějších frameworků (Laravel, Symfony, Nette, Laminas, Yii).
Architektonické styly práce s databází
- PDO (low-level přístup): Ruční psaní SQL dotazů, připravené dotazy, plná kontrola nad výkonem i transakcemi. Vhodné pro vysoce optimalizované části, reporting a složité dotazy.
- Query Builder: Fluent API pro skládání SQL (dbal, Eloquent Builder, NetteDatabaseExplorer, LaminasDbSql). Snižuje riziko chyb a zvyšuje čitelnost, přitom stále zachovává blízkost k SQL.
- ORM: Mapování tabulek na entity a vztahy, Unit of Work, Identity Map, lazy/eager loading, migrace. Typicky Doctrine ORM (Symfony), Eloquent (Laravel), Cycle ORM, Propel, Atlas.
Vzory ORM: Active Record vs. Data Mapper
- Active Record: Třída entity nese metody
save(),find(),delete()(např. Eloquent, Yii AR). Jednodušší pro CRUD operace, hůře škáluje u komplexních domén. - Data Mapper: Odděluje doménový model od perzistence (např. Doctrine). Nabízí vyšší flexibilitu pro Domain-Driven Design (DDD), ale vyžaduje složitější konfiguraci.
Klíčové koncepty ORM
- Entity a hodnotové objekty: Entity mají identitu (primární klíč), hodnotové objekty jsou neidentitní a neměnné.
- Unit of Work a Identity Map: Sledování změn entit, zabránění duplicitním instancím stejného řádku.
- Vztahy: OneToOne, OneToMany, ManyToMany; kardinality a vlastnictví vztahu (owning/inverse side) ovlivňují generované SQL.
- Načítání dat: Lazy vs. eager loading; strategie join fetch, select in, subselect.
- Životní cyklus entity: stavy new, managed, detached, removed; události (prePersist, postLoad apod.).
Bezpečnost: SQL injection a práce s daty
- Připravené dotazy: Vždy používejte parametrizaci (
?/:name), nikdy neskládajte SQL řetězec z neověřených vstupů. - Escapování vs. parametrizace: Přednost má parametrizace; escapování je doplňkové a chybové scénáře se mohou lišit mezi ovladači.
- Serializace JSON/XML: Při ukládání dokumentů do sloupců využívejte validaci schématu, limity velikosti a indexy (např.
GINpro JSONB). - Least privilege: Aplikační účet s omezenými právy (SELECT/INSERT/UPDATE/DELETE pro konkrétní schéma), oddělené uživatelské role pro migrace.
Transakce a izolace
- Granularita: Obalujte logické jednotky práce (service nebo use-case) do transakcí; v ORM používejte
EntityManager::transactional()(Doctrine) čiDB::transaction()(Laravel). - Izolační úrovně: READ COMMITTED, REPEATABLE READ, SERIALIZABLE; volba ovlivňuje riziko „phantoms“, „non-repeatable reads“.
- Deadlocky: Implementujte idempotentní retry mechanismus s exponenciálním zpožděním a auditováním.
Migrace schématu a verzování
- Nástroje: Doctrine Migrations, Laravel Migrations, Phinx; verzujte spolu s kódem a CI/CD pipeline.
- Bezvýpadkové změny: Přidávejte nové sloupce jako
NULLnebo s výchozí hodnotou, provádějte backfill v dávkách, poté zpřísněte constraintNOT NULL. - Seed/fixtures: Deterministická testovací data; oddělujte dev seed od produkční inicializace.
Výkon a optimalizace (ORM i SQL)
- N+1 dotazů: Používejte eager loading (
with()v Eloquent, JOIN FETCH v Doctrine) a dávkové načítání (batching). - Indexy: Měřte a přidávejte kompozitní indexy dle reálných dotazů; sledujte EXPLAIN plány.
- Pagination a streaming: Keyset pagination (pomocí >/<) je efektivnější než
OFFSETu velkých tabulek; využijte kurzory. - Kešování: Aplikační cache (Redis, Memcached), 2nd-level cache (Doctrine), query cache tam, kde je to bezpečné.
- Bulk operace: Dávkové insert/update s vypnutým sledováním změn v ORM (pomocí clear, detach) a využitím native queries pro masivní operace.
- Asynchronní běh: V kombinaci se Swoole/RoadRunner využijte persistentní připojení a connection pooly; dejte pozor na stavovost ORM objektů mezi požadavky.
Doménové modelování a repozitáře
- Repository pattern: Zapouzdřuje dotazy nad agregáty, udržuje kontrakty domény; v Doctrine lze implementovat vlastní Repository třídy.
- Specifikace a CQRS: Těžké čtecí dotazy přesuňte do read-modelů (DTO/projekce) a oddělte od zápisového modelu.
- Event sourcing: V doménách s auditními požadavky zvažte ukládání událostí; projekce denormalizujte do tabulek pro rychlé čtení.
Podpora typů a moderní PHP
- Typed properties a readonly: Zvyšují spolehlivost entit; vyžadují opatrnost u lazy-loading proxy objektů.
- Enum a backed enum: Mapujte na malé tabulky či
ENUMsloupce; v Doctrine/Eloquent implementujte jako custom typy nebo casts. - Atributy: Konfigurace ORM přes PHP atributy namísto anotací či YAML; přehlednější a typově bezpečnější.
- Statická analýza: Psalm/PHPStan s generiky (phpdoc) pro kolekce; identifikuje nekompatibilní dotazy ještě před nasazením.
Práce s více databázemi, replikace a škálování
- Read/Write splitting: Zápisy na master, čtení z replik; pozor na replication lag a konzistenci po zápisu (sticky sessions, read your write).
- Sharding: Logická distribuce dat (uživatelé, tenanti) podle klíče; repozitáře rozhodují o správném shardu.
- Multi-tenant: Izolace per tenant (schéma/tabulky) vs. sdílené tabulky s
tenant_ida aplikací row-level security.
Práce s NoSQL a speciálními typy
- JSON/JSONB: Mapujte na DTO a validujte; použijte indexy pro často dotazované cesty (
->,->>,#>). - Geodata: PostGIS; v Doctrine vlastní typy pro
geometry, v Eloquent casty a kontrolaSRID. - Fulltext: MySQL InnoDB FULLTEXT/Boolean mode nebo specializovaný vyhledávač (OpenSearch, Meilisearch) se synchronizací událostí.
Zpracování změn: concurrency a audit
- Optimistické zámky: Sloupec
versionneboupdated_atpro detekci konfliktů; ORM vyhodí výjimku při kolizi. - Pessimistické zámky:
SELECT ... FOR UPDATEpro kritické sekce; nezapomeňte na timeouty. - Audit trail: Listener a subscriber patterny logují změny; ukládejte rozdíly nebo celé snímky dle potřeby.
Testování a izolace
- Transakce na test: Obalte test do transakce a na konci proveďte rollback; rychlé a izolované testování.
- Fixtures a factories: Vytvářejte data skrze doménové API; neobcházejte validační logiku.
- Integrace vs. unit testy: Složitější dotazy testujte integračně proti skutečné databázi (např. v kontejnerech), doménovou logiku unit-testujte se stuby repozitářů.
Integrace ve frameworkách
- Laravel (Eloquent): Active Record,
migrations,seeder,factories, globální i scoped query, casts, události modelů; snadné eager loading a withCount(). - Symfony (Doctrine ORM): Data Mapper,
EntityManager,Repository,QueryBuilder, hydrátory, 2nd-level cache; silný ekosystém nástrojů. - Nette (Database/Explorer, integrace Doctrine): Lehký query builder a mapování na objekty řádků; pro DDD se často kombinuje s Doctrine.
- Laminas (Db): SQL builder, adaptéry, TableGateway; vhodné pro projekty preferující explicitní SQL.
- Yii (Active Record): Podobné Eloquentu s propracovaným
with()a scénáři validace.
Logování a observabilita
- SQL log: Zapněte logování dotazů s parametry a dobou trvání; v produkci používejte s rozmyslem (sampling).
- Tracing: OpenTelemetry/Jaeger; anotujte hranice (repozitáře, transakce), přidávejte DB span atributy (db.system, statement, rows).
- Performance budget: Definujte SLA pro latenci dotazů a počet round-tripů na request.
Typické anti-patterny a jak se jim vyhnout
- Mass assignment bez whitelistu: V Eloquent používejte
$fillable/$guarded; v Doctrine validujte DTO před hydratací. - Business logika v kontrolerech: Přesuňte do služeb a doménové vrstvy; kontroler by měl volat pouze use-case.
- N+1 problémy a eager loading všude: Vždy měřte dopad; někdy je lepší explicitní SQL s agregací.
- Neřízený lazy-loading v šablonách: Vyvolává nestabilní latenci; data připravujte v aplikační vrstvě před renderováním.
Roadmapa implementace v projektu
- Volba přístupu: Definujte oblasti, kde použijete ORM, query builder nebo nativní SQL.
- Model a hranice: Navrhněte entity, agregáty, repozitáře, transakční hranice a politiky načítání dat.
- Migrace a seed: Nastavte nástroje, konvence verzování a CI pipeline pro migrační procesy.
- Bezpečnost: Parametrizace dotazů, role v DB, audit dotazů i přístupů, testy proti SQL injection.
- Výkon: Optimalizujte indexy, eager loading, cache, keyset pagination, sledujte EXPLAIN plány.
- Testy: Vypracujte strategii pro unit i integrační testy, zabezpečte transakční testování, využijte fixtures.
- Observabilita: Zapojte logování SQL, tracing, metriky a alerting.
Tabulkové srovnání přístupů
| Přístup | Kontrola nad SQL | Produktivita | Složitost | Vhodné pro |
|---|---|---|---|---|
| PDO | Maximální | Nižší | Nižší | Výkonnostně citlivé části, reporting |
| Query Builder | Vysoká | Střední | Střední | CRUD s komplexními filtry |
| ORM – Active Record | Střední | Vysoká | Střední | Rychlé CRUD, malé až střední domény |
| ORM – Data Mapper | Střední | Střední | Vyšší | DDD, komplexní vztahy, dlouhodobé projekty |
Závěr
Úspěšná integrace databází v PHP spočívá v promyšlené kombinaci nástrojů a přístupů. ORM výrazně zvyš


























