You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/cs/database-activerow.texy
+10-9Lines changed: 10 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,8 @@
1
1
Database: ActiveRow
2
2
*******************
3
3
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
+
5
6
6
7
/--code php
7
8
echo $book->id;
@@ -11,7 +12,7 @@ isset($book->id);
11
12
isset($book['title']);
12
13
\--
13
14
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`.
15
16
16
17
17
18
Vztahy
@@ -20,18 +21,18 @@ Vztahy
20
21
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".
21
22
22
23
.[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.
24
25
25
26
Relace Has one
26
27
--------------
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:
28
29
29
30
/--code php
30
31
$book = $context->table('book')->get(1);
31
32
$book->ref('author', 'author_id');
32
33
\--
33
34
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.
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.
52
53
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:
54
55
55
56
/--code php
56
57
$book->author->name;
57
58
// je stejné jako
58
59
$book->ref('author')->name;
59
60
\--
60
61
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].
62
63
63
64
/--code php
64
65
echo $book->title . ": ";
@@ -108,7 +109,7 @@ foreach ($author->related('book.translator_id') as $book) {
108
109
}
109
110
\--
110
111
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.
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].
119
120
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.
Copy file name to clipboardExpand all lines: doc/cs/database-selection.texy
+13-3Lines changed: 13 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ Database: Selection
5
5
6
6
Filtrování
7
7
----------
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.
9
9
10
10
/--code php
11
11
$selection->where('name = ?', $name);
@@ -89,7 +89,7 @@ $selection->group('author.id')
89
89
->having('COUNT(:book.id) > 3');
90
90
\--
91
91
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].
93
93
94
94
Abychom mohli spojovat přes `translator_id`, stačí přidat volitelný "parametr" do spojovacího výrazu.
95
95
@@ -128,7 +128,14 @@ Podívejme se na různé možnosti filtrování a omezování výběru pomocí A
128
128
| `$table->group($columns)` | Nastaví GROUP BY
129
129
| `$table->having($having)` | Nastaví HAVING
130
130
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]:
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()`:
132
139
133
140
Možné argumenty metody [where() |api:Nette\Database\Table\Selection::where()]:
134
141
@@ -150,6 +157,9 @@ Můžeme vytvořit také agregaci výsledků:
150
157
| `$table->sum($column)` | Vrátí součet všech hodnot
151
158
| `$table->aggregation("GROUP_CONCAT($column)")` | Pro jakoukoliv jinou agregační funkci
152
159
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.
Copy file name to clipboardExpand all lines: doc/cs/database-table.texy
+50-2Lines changed: 50 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -11,13 +11,13 @@ Pojďme si vyzkoušet jednoduchý příklad. Potřebujeme z databáze vybrat kni
11
11
12
12
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.
13
13
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].
15
15
16
16
/--code php
17
17
$selection = $context->table('book'); // jméno tabulky je "book"
18
18
\--
19
19
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.
21
21
22
22
/--code php
23
23
$books = $context->table('book');
@@ -82,6 +82,54 @@ SELECT `book_id`, `tag_id` FROM `book_tag` WHERE (`book_tag`.`book_id` IN (1, 4,
82
82
SELECT `id`, `name` FROM `tag` WHERE (`tag`.`id` IN (21, 22, 23))
83
83
\--
84
84
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
Š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);
0 commit comments