Skip to content

Commit c65f994

Browse files
matej21dg
authored andcommitted
Database doc update
1 parent 6033604 commit c65f994

File tree

4 files changed

+167
-37
lines changed

4 files changed

+167
-37
lines changed

doc/cs/database-activerow.texy

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
Database: ActiveRow
22
*******************
33

4-
Každý řádek, který vrátí [Selection | api:Nette\Database\Table\Selection] je reprezentován instancí [ActiveRow | api:Nette\Database\Table\ActiveRow]. Tato třída poskytuje standardní interface pro přístup k vybraným sloupcům. Data může číst jako členské proměnné nebo použít přístup přes klíče pole. Pokud sloupec neexistuje, je vyhozena výjimka [MemberAccessException | api:Nette\MemberAccessException]. Pomocí standardní konstrukce `isset` lze ověřit, zda má sloupec nastavenou neprázdnou hodnotu.
4+
Každý řádek, který vrátí [Selection | api:Nette\Database\Table\Selection], je reprezentován instancí [ActiveRow | api:Nette\Database\Table\ActiveRow]. Tato třída poskytuje standardní interface pro přístup k vybraným sloupcům. Data můžeme číst jako členské proměnné nebo použít přístup přes klíče pole. Pokud sloupec neexistuje, je vyhozena výjimka [MemberAccessException | api:Nette\MemberAccessException]. Pomocí standardní konstrukce `isset` lze ověřit, zda má sloupec nastavenou neprázdnou hodnotu.
5+
56

67
/--code php
78
echo $book->id;
@@ -11,7 +12,7 @@ isset($book->id);
1112
isset($book['title']);
1213
\--
1314

14-
Pozor, `isset` vrátí FALSE, i když byl sloupec dotazem vybrán, ale má hodnotu NULL.
15+
Pozor, `isset` vrátí `FALSE`, i když byl sloupec dotazem vybrán, ale má hodnotu `NULL`.
1516

1617

1718
Vztahy
@@ -20,18 +21,18 @@ Vztahy
2021
Hlavním principem Nette\Database\Table je oddělené načítání dat z různých tabulek. Toto chování je zajišťováno samotnou Nette\Database, příbuzná data jsou z databáze vybrána pro všechny řádky najednou. Máme dva hlavní druhy vztahů: "has one" a "has many".
2122

2223
.[note]
23-
Budeme používat DiscoveredConventions, která načte vztahy mezi tabulkami přímo z databáze.
24+
Budeme používat `DiscoveredConventions`, která načte vztahy mezi tabulkami přímo z databáze.
2425

2526
Relace Has one
2627
--------------
27-
Relace has one je velmi běžná. Kniha *má jednoho* autora. Kniha *má jednoho* překladatele. Řádek, který je ve vztahu has one získáme pomocí metody [ref() | api:Nette\Database\Table\ActiveRow::ref()]. Ref() přijímá dva argumenty: jméno cílové tabulky a název spojovacího sloupce. Viz příklad:
28+
Relace has one je velmi běžná. Kniha *má jednoho* autora. Kniha *má jednoho* překladatele. Řádek, který je ve vztahu has one získáme pomocí metody [ref() | api:Nette\Database\Table\ActiveRow::ref()]. `ref()` přijímá dva argumenty: jméno cílové tabulky a název spojovacího sloupce. Viz příklad:
2829

2930
/--code php
3031
$book = $context->table('book')->get(1);
3132
$book->ref('author', 'author_id');
3233
\--
3334

34-
V příkladu výše vybíráme souvisejícího autora z tabulky `author`. Primární klíč tabulky `author` je hledán podle sloupce `book.author_id`. Metoda ref() vrací instanci ActiveRow nebo NULL, pokud hledaný záznam neexistuje. Vrácený řádek je instance ActiveRow, takže s ním můžeme pracovat stejně jako se záznamem knihy.
35+
V příkladu výše vybíráme souvisejícího autora z tabulky `author`. Primární klíč tabulky `author` je hledán podle sloupce `book.author_id`. Metoda `ref()` vrací instanci `ActiveRow` nebo `NULL`, pokud hledaný záznam neexistuje. Vrácený řádek je instance `ActiveRow`, takže s ním můžeme pracovat stejně jako se záznamem knihy.
3536

3637
/--code php
3738
$author = $book->ref('author', 'author_id');
@@ -50,15 +51,15 @@ $book->ref('author', 'translator_id')->name
5051

5152
Tento přístup je funkční, ale pořád trochu zbytečně těžkopádný, nemyslíte? Databáze už obsahuje definice cizích klíčů, tak proč je nepoužít automaticky. Pojďme to vyzkoušet.
5253

53-
Pokud přistoupíme k členské proměnné, která neexistuje, ActiveRow se pokusí použít jméno této proměnné pro relaci "has one". Čtení této proměnné je stejné jako volání metody ref() pouze s jedním parametrem. Tomuto parametru budeme říkat **klíč**. Tento klíč bude použit pro vyhledání cizího klíče v tabulce. Předaný klíč je porovnán se sloupci, a pokud odpovídá pravidlům, je cizí klíč na daném sloupci použit pro čtení dat z příbuzné tabulky. Viz příklad:
54+
Pokud přistoupíme k členské proměnné, která neexistuje, ActiveRow se pokusí použít jméno této proměnné pro relaci "has one". Čtení této proměnné je stejné jako volání metody `ref()` pouze s jedním parametrem. Tomuto parametru budeme říkat **klíč**. Tento klíč bude použit pro vyhledání cizího klíče v tabulce. Předaný klíč je porovnán se sloupci, a pokud odpovídá pravidlům, je cizí klíč na daném sloupci použit pro čtení dat z příbuzné tabulky. Viz příklad:
5455

5556
/--code php
5657
$book->author->name;
5758
// je stejné jako
5859
$book->ref('author')->name;
5960
\--
6061

61-
Instance ActiveRow nemá žádný sloupec author. Všechny sloupce tabulky book jsou prohledány na shodu s *klíčem*. Shoda v tomto případě znamená, že jméno sloupce musí obsahovat klíč. V příkladu výše sloupec `author_id` obsahuje řetězec "author" a tedy odpovídá klíči "author". Pokud chceme přistoupit k záznamu překladatele, obdobným způsobem použijeme klíč "translator", protože bude odpovídat sloupci `translator_id`. Více o logice párování klíčů si můžete přečíst v kapitole [Joining expressions | database-selection#joining-key].
62+
Instance ActiveRow nemá žádný sloupec `author`. Všechny sloupce tabulky `book` jsou prohledány na shodu s *klíčem*. Shoda v tomto případě znamená, že jméno sloupce musí obsahovat klíč. V příkladu výše sloupec `author_id` obsahuje řetězec "author" a tedy odpovídá klíči "author". Pokud chceme přistoupit k záznamu překladatele, obdobným způsobem použijeme klíč "translator", protože bude odpovídat sloupci `translator_id`. Více o logice párování klíčů si můžete přečíst v kapitole [Joining expressions | database-selection#joining-key].
6263

6364
/--code php
6465
echo $book->title . ": ";
@@ -108,7 +109,7 @@ foreach ($author->related('book.translator_id') as $book) {
108109
}
109110
\--
110111

111-
Metoda [related() | api:Nette\Database\Table\ActiveRow::related()] přijímá popis spojení jako dva argumenty, nebo jako jeden argument spojený tečkou. První argument je cílová tabulka, druhý je sloupec.
112+
Metoda `related()` přijímá popis spojení jako dva argumenty, nebo jako jeden argument spojený tečkou. První argument je cílová tabulka, druhý je sloupec.
112113
/--code php
113114
$author->related('book.translator_id');
114115
// je stejné jako
@@ -117,7 +118,7 @@ $author->related('book', 'translator_id');
117118

118119
Můžeme použít heuristiku Nette\Database založenou na cizích klíčích a použít pouze **klíč**. Klíč bude porovnán s cizími klíči, které odkazují do aktuální tabulky (tabulka `author`). Pokud je nalezena shoda, Nette\Database použije tento cizí klíč, v opačném případě vyhodí výjimku [Nette\InvalidArgumentException | api:Nette\InvalidArgumentException] nebo [AmbiguousReferenceKeyException | api:Nette\Database\Conventions\AmbiguousReferenceKeyException]. Více o logice párování klíčů si můžete přečíst v kapitole [Joining expressions | database-selection#joining-key].
119120

120-
Metodu related může samozřejmě volat na všechny získané autory a Nette\Database načte všechny odpovídající knihy najednou.
121+
Metodu `related()` může samozřejmě volat na všechny získané autory a Nette\Database načte všechny odpovídající knihy najednou.
121122

122123
/--code php
123124
$authors = $context->table('author');

doc/cs/database-selection.texy

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Database: Selection
55

66
Filtrování
77
----------
8-
Pojďme se podívat na základní API Selection. Jednoduché podmínky můžeme vytvořit zavoláním metody [where() |api:Nette\Database\Table\Selection::where()]. Otazníky v dotazu budou nahrazeny obsahem proměnných.
8+
Pojďme se podívat na základní API třídy Selection. Jednoduché podmínky můžeme vytvořit zavoláním metody [where() |api:Nette\Database\Table\Selection::where()]. Otazníky v dotazu budou nahrazeny obsahem proměnných.
99

1010
/--code php
1111
$selection->where('name = ?', $name);
@@ -89,7 +89,7 @@ $selection->group('author.id')
8989
->having('COUNT(:book.id) > 3');
9090
\--
9191

92-
Možná jste si všimli, že spojovací výraz odkazuje na book, ale není jasné, jestli spojujeme přes `author_id` nebo `translator_id`. Ve výše uvedeném příkladu Selection spojuje přes sloupec `author_id`, protože byla nalezena shoda se jménem zdrojové tabulky - tabulky `author`. Pokud by neexistovala shoda a existovalo více možností, Nette vyhodí výjimku [AmbiguousReferenceKeyException |api:Nette\Database\Conventions\AmbiguousReferenceKeyException].
92+
Možná jste si všimli, že spojovací výraz odkazuje na `book`, ale není jasné, jestli spojujeme přes `author_id` nebo `translator_id`. Ve výše uvedeném příkladu Selection spojuje přes sloupec `author_id`, protože byla nalezena shoda se jménem zdrojové tabulky - tabulky `author`. Pokud by neexistovala shoda a existovalo více možností, Nette vyhodí výjimku [AmbiguousReferenceKeyException |api:Nette\Database\Conventions\AmbiguousReferenceKeyException].
9393

9494
Abychom mohli spojovat přes `translator_id`, stačí přidat volitelný "parametr" do spojovacího výrazu.
9595

@@ -128,7 +128,14 @@ Podívejme se na různé možnosti filtrování a omezování výběru pomocí A
128128
| `$table->group($columns)` | Nastaví GROUP BY
129129
| `$table->having($having)` | Nastaví HAVING
130130

131-
Můžeme použít tzv. fluent interface, například `$table->where(...)->order(...)->limit(...)`. Více `where` nebo `whereOr` podmínek je spojeno pomocí operátoru `AND`.
131+
Nejen v metodě `where` můžeme použít parametry. Parametry jsou podporovány i v metodách `order, select, group a having`. A pokud do těchto metod dosazujeme hodnotu, je nutné parametry použít, aby Nette\Database správně dotaz escapovalo (viz [zapisování dotazů|database-table#zapisovani-dotazu]:
132+
133+
/--code php
134+
$table->select('DATE_FORMAT(created, ?)', '%d.%m.%Y')
135+
\--
136+
137+
138+
Můžeme použít tzv. fluent interface, například `$table->where(...)->order(...)->limit(...)`. Více `where` nebo `whereOr` podmínek je spojeno pomocí operátoru `AND`. Pro operátor `OR` musíme použít pouze jedno volání `where()`:
132139

133140
Možné argumenty metody [where() |api:Nette\Database\Table\Selection::where()]:
134141

@@ -150,6 +157,9 @@ Můžeme vytvořit také agregaci výsledků:
150157
| `$table->sum($column)` | Vrátí součet všech hodnot
151158
| `$table->aggregation("GROUP_CONCAT($column)")` | Pro jakoukoliv jinou agregační funkci
152159

160+
.[caution]
161+
Metoda `count()` bez uvedeného parametru vybere všechny záznamy a vrátí velikost pole, což je velmi neefektivní. Pokud potřebujete například spočítat počet řádků pro stránkování, vždy první argument uveďte.
162+
153163
Čtení dat:
154164

155165
.[wide]

doc/cs/database-table.texy

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ Pojďme si vyzkoušet jednoduchý příklad. Potřebujeme z databáze vybrat kni
1111

1212
Vrstva Database\Table poskytuje instanci [Selection |api:Nette\Database\Table\Selection], která reprezentuje výběr dat z *jedné* databázové tabulky. Tato instance umožňuje filtrování požadovaných dat a vrací je jako instance ActiveRow.
1313

14-
Vytvoření Selection je jednoduché, stačí zavolat metodu [table() |api:Nette\Database\Context::table()] na objektu databázového připojení. Jak se k databázi připojíme je popsáno v kapitole [Nette\Database | database].
14+
Vytvoření Selection je jednoduché, stačí zavolat metodu [table() |api:Nette\Database\Context::table()] na objektu databázového připojení. Jak se [k databázi připojíme |database#Vytvoření pomocí aplikační konfigurace] je popsáno v kapitole [Nette\Database | database], pokud však používáme Nette\Database samostatně, je nutno tento objekt [vytvořit |#rucni-vytvoreni-database-context].
1515

1616
/--code php
1717
$selection = $context->table('book'); // jméno tabulky je "book"
1818
\--
1919

20-
Selection implementuje interface [Traversable |php:Traversable]: nad instancí můžeme jednoduše iterovat a vybrat tak všechny knihy. Řádky jsou vráceny jako instance Active Row a data z nich můžeme přímo číst.
20+
Selection implementuje interface [Traversable |php:Traversable]: nad instancí můžeme jednoduše iterovat a vybrat tak všechny knihy. Řádky jsou vráceny jako instance ActiveRow a data z nich můžeme přímo číst.
2121

2222
/--code php
2323
$books = $context->table('book');
@@ -82,6 +82,54 @@ SELECT `book_id`, `tag_id` FROM `book_tag` WHERE (`book_tag`.`book_id` IN (1, 4,
8282
SELECT `id`, `name` FROM `tag` WHERE (`tag`.`id` IN (21, 22, 23))
8383
\--
8484

85+
Zapisování dotazů
86+
-----------------
87+
88+
Database\Table umí chytře escapovat parametry a identifikátory. Pro správnou funkčnost je ale nutno dodržovat několik pravidel:
89+
90+
- klíčová slova, názvy funkcí, procedur apod. psát velkými písmeny
91+
- názvy sloupečků a tabulek psát malými písmeny
92+
- hodnoty dosazovat přes parametry
93+
94+
/--code php
95+
//SPATNE!:
96+
//->where("name like ?", "John"); //vygeneruje: `name` `like` ?
97+
//spravne:
98+
->where("name LIKE ?", "John");
99+
100+
//SPATNE!:
101+
//->where("KEY = ?", $value); //KEY je klíčové slovo
102+
//spravne:
103+
->where("key = ?", $value); //vygeneruje: `key` = ?
104+
105+
//SPATNE!:
106+
//->where("name = " . $name); //sql injection!
107+
//spravne:
108+
->where("name = ?", $name);
109+
\--
110+
111+
.[warning]
112+
Špatné použití může vést k bezpečnostním dírám v aplikaci.
113+
114+
115+
Ruční vytvoření Database\Context
116+
--------------------------------
117+
118+
Pokud jsme si vytvořili databázové spojení pomocí aplikační konfigurace, nemusíme se o nic starat. Vytvořila se nám totiž i služba typu `Nette\Database\Context`, kterou si můžeme předat pomocí DI.
119+
120+
Pokud ale používáme Nette\Database samostatně a chceme využívat vrstvu Table, musíme instanci Database\Context vytvořit ručně.
121+
122+
/--code php
123+
//$storage obsahuje implementaci Nette\Caching\IStorage, napr.:
124+
//$storage = new Nette\Caching\FileStorage($tempDir);
125+
126+
$connection = new Nette\Database\Connection($dsn, $user, $password);
127+
128+
$structure = new Nette\Database\Structure($connection, $storage);
129+
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
130+
$context = new Nette\Database\Context($connection, $structure, $conventions, $storage);
131+
\--
132+
85133
{{toc: title}}
86134

87135
{{themeicon: icon-database.png}}

0 commit comments

Comments
 (0)