diff --git a/database/bg/core.texy b/database/bg/core.texy index 3f1ed5af5c..096e5311b0 100644 --- a/database/bg/core.texy +++ b/database/bg/core.texy @@ -1,350 +1 @@ -Ядро на базата данни -******************** - -.[perex] -Ядрото на базата данни на Nette е слой за абстракция на базата данни и осигурява основни функции. - - -Инсталация .[#toc-installation] -=============================== - -Изтеглете и инсталирайте пакета с помощта на [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Свързване и конфигуриране .[#toc-connection-and-configuration] -============================================================== - -За да се свържете с базата данни, просто създайте инстанция на класа [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Параметърът `$dsn` (име на източника на данни) е [същият, който се използва в PDO |https://www.php.net/manual/ru/pdo.construct.php#refsect1-pdo.construct-parameters], например `host=127.0.0.1;dbname=test`. Ако не успее, се изхвърля изключение `Nette\Database\ConnectionException`. - -[Конфигурацията на приложението |configuration] обаче предлага по-сложен начин. Ще добавим раздел `database`, а той ще създаде необходимите обекти и панел `Database` в панела за отстраняване на грешки на [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Обектът за връзка, който [получаваме като услуга от DI-контейнера |dependency-injection:passing-dependencies], напр: - -```php -class Model -{ - // подайте Nette\Database\Explorer, за да работите със слоя Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -За повече информация вижте [Конфигурация на базата данни |configuration]. - - -Запитвания .[#toc-queries] -========================== - -За да направите заявка към базата данни, използвайте метода `query()`, който връща [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // връща броя на редовете, ако е известен -``` - -.[note] -Можете да итерирате над `ResultSet` само веднъж, ако трябва да итерирате повече от веднъж, трябва да преобразувате резултата в масив, като използвате метода `fetchAll()`. - -Можете лесно да добавяте параметри към заявката, като обърнете внимание на въпросителния знак: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids - массив -``` -
- -ПРЕДУПРЕЖДЕНИЕ Никога не конкатенирайте низове, за да избегнете [уязвимост чрез SQL инжекция |https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // НЕПРАВИЛЬНО!!! -\-- -
- -Ако не успее, `query()` изхвърля изключението `Nette\Database\DriverException` или някое от неговите подчинени изключения: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - нарушение на някое от условията -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - невалиден чужд ключ -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - нарушение на условие NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - конфликт на уникален индекс - -Освен `query()`, има и други полезни методи: - -```php -// Връща асоциативен масив id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -//връщане на всички редове като масив -$rows = $database->fetchAll('SELECT * FROM users'); - -//връща един ред -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// връщане на едно поле -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -При неуспешен опит всички тези методи хвърлят изключение `Nette\Database\DriverException`. - - -Вмъкване, актуализиране и изтриване .[#toc-insert-update-delete] -================================================================ - -Параметърът, който вмъкваме в SQL заявката, може да бъде и масив (в този случай можем да пропуснем заместващия символ `?`), что может быть полезно для оператора `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // тук може да се пропусне въпросителен знак - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // връща автоматичното увеличение на вмъкнатия низ - -$id = $database->getInsertId($последователност); // или стойност на последователността -``` - -Вмъкване на няколко стойности: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Можем също така да предаваме файлове, обекти DateTime или [изброявания |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // или $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // вмъква съдържанието на файла - 'status' => State::New, // enum State -]); -``` - -Струни за актуализация: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // връща броя на засегнатите редове -``` - -За UPDATE можем да използваме операторите `+=` и `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Изтриване: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // връща броя на засегнатите редове -``` - - -Разширени заявки .[#toc-advanced-queries] -========================================= - -Вмъкнете или актуализирайте, ако даден запис вече съществува: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Обърнете внимание, че Nette Database разпознава SQL контекста, в който е вмъкнат параметърът на масива, и изгражда SQL кода по съответния начин. Така той генерира `(id, name, year) VALUES (123, 'Jim', 1978)` от първия масив и преобразува втория масив в `name = 'Jim', year = 1978`. - -Можем също така да опишем сортирането с помощта на масив, в който ключовете са имена на колони, а стойностите са булеви стойности, които определят дали да се сортират във възходящ ред: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // възходящо - 'name' => false, // низходящо -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Ако откриването е неуспешно, можете да посочите формата на асемблито, като използвате заместителя `?`, последван от подсказка. Поддържат се следните команди: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | ключ1 = стойност1 ИЛИ ключ2 = стойност2 ... -| ?order | key1 ASC, key2 DESC - -В декларацията WHERE се използва операторът `?and`, така че условията са свързани `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Което може лесно да се промени на `OR`, като се използва заместителният символ `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Можем да използваме оператори в условията: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -както и трансфери: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // изброяване + оператор NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Можем също така да включим част от персонализирания SQL код, като използваме така наречения SQL литерал: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Алтернативно: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -Литералът на SQL може да има и свои собствени параметри: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Благодарение на това можем да създаваме интересни комбинации: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Име на променливата .[#toc-variable-name] -========================================= - -Има заместващ символ `?name', който се използва, ако името на таблица или колона е променлива. (Внимавайте да не позволите на потребителя да манипулира съдържанието на такава променлива): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Транзакции .[#toc-transactions] -=============================== - -Съществуват три метода за обработка на транзакции: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Един елегантен метод предлага методът `transaction()`. Предавате обратно извикване, което се изпълнява в транзакция. Ако по време на изпълнението възникне изключение, транзакцията се прекратява, а ако всичко е наред, транзакцията се предава. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Както можете да видите, методът `transaction()` връща стойността на обратната връзка. - -Функцията Transaction() също може да бъде вложена, което опростява прилагането на независими хранилища. +{{redirect: guide}} diff --git a/database/cs/core.texy b/database/cs/core.texy index 02c3104e43..096e5311b0 100644 --- a/database/cs/core.texy +++ b/database/cs/core.texy @@ -1,350 +1 @@ -Database Core -************* - -.[perex] -Nette Database Core je základní vrstva pro přístup k databázi, tzv. database abstraction layer. - - -Instalace -========= - -Knihovnu stáhnete a nainstalujete pomocí nástroje [Composer|best-practices:composer]: - -```shell -composer require nette/database -``` - - -Připojení a konfigurace -======================= - -Pro připojení k databázi stačí vytvořit instanci třídy [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Parametr `$dsn` (data source name) je stejný, [jaký používá PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], např. `host=127.0.0.1;dbname=test`. V případě selhání vyhodí výjimku `Nette\Database\ConnectionException`. - -Nicméně šikovnější způsob nabízí [aplikační konfigurace |configuration], kam stačí přidat sekci `database` a vytvoří se potřebné objekty a také databázový panel v [Tracy |tracy:] baru. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Poté objekt spojení [získáme jako službu z DI kontejneru |dependency-injection:passing-dependencies], např.: - -```php -class Model -{ - // pro práci s vrstvou Database Explorer si předáme Nette\Database\Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Více informací o [konfiguraci databáze|configuration]. - - -Dotazy -====== - -Databázové dotazy pokládáme metodou `query()`, která vrací [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // vrací počet řádků výsledku, pokud je znám -``` - -.[note] -Nad `ResultSet` je možné iterovat pouze jednou, pokud potřebujeme iterovat vícekrát, je nutno výsledek převést na pole metodou `fetchAll()`. - -Do dotazu lze velmi snadno přidávat i parametry, všimněte si otazníku: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids je pole -``` - -
-POZOR, nikdy dotazy neskládejte jako řetězce, vznikla by zranitelnost [SQL injection |https://cs.wikipedia.org/wiki/SQL_injection] -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // ŠPATNĚ!!! -\-- -
- -V případě selhání `query()` vyhodí buď `Nette\Database\DriverException` nebo některého z potomků: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - porušení nějakého omezení pro tabulku -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - neplatný cizí klíč -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - porušení podmínky NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - koliduje unikátní index - -Kromě `query()` jsou tu další užitečné funkce: - -```php -// vrátí asociativní pole id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// vrátí všechny záznamy jako pole -$rows = $database->fetchAll('SELECT * FROM users'); - -// vrátí jeden záznam -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// vrátí přímo hodnotu buňky -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -V případě selhání všechny tyto metody vyhodí `Nette\Database\DriverException`. - - -Insert, Update & Delete -======================= - -Parameterem, který vkládáme do SQL dotazu, může být i pole (v takovém případě je navíc možné zástupný symbol `?` vynechat), což se hodí třeba pro sestavení příkazu `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // tady můžeme otazník vynechat - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // vrátí auto-increment vloženého záznamu - -$id = $database->getInsertId($sequence); // nebo hodnotu sekvence -``` - -Vícenásobný INSERT: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Jako parametry můžeme předávat i soubory, objekty DateTime nebo [výčtové typy |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // nebo $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // vloží soubor - 'status' => State::New, // enum State -]); -``` - -Úprava záznamů: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // vrací počet ovlivněných řádků -``` - -Pro UPDATE můžeme využít operátorů `+=` a `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // všimněte si += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Mazání: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // vrací počet ovlivněných řádků -``` - - -Pokročilé dotazy -================ - -Vložení, nebo úprava záznamu, pokud již existuje: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Všimněte si, že Nette Database pozná, v jakém kontextu SQL příkazu parametr s polem vkládáme a podle toho z něj sestaví SQL kód. Takže z prvního pole sestavil `(id, name, year) VALUES (123, 'Jim', 1978)`, zatímco druhé převedl do podoby `name = 'Jim', year = 1978`. - -Také řazení můžeme ovlivnit polem, v klíčích uvedeme sloupce a hodnotou bude boolean určující, zda řadit vzestupně: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // vzestupně - 'name' => false, // sestupně -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Pokud by u neobvyklé konstrukce detekce nezafungovala, můžete formu sestavení určit zástupným symbolem `?` doplněným o hint. Podporovány jsou tyto hinty: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -V klauzuli WHERE se používá operátor `?and`, takže podmínky se spojují operátorem `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Což můžeme snadno změnit na `OR` tím, že uvedeme zástupný symbol `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -V podmínkách můžeme používat operátory: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -A také výčty: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // výčet + operátor NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Do podmínky také můžeme vložit kus vlastního SQL kódu pomocí tzv. SQL literálu: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Nebo alternativě: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literál také může mít své parametry: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Díky čemuž můžeme vytvářet zajímavé kombinace: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Proměnný název -============== - -Ještě existuje zástupný symbol `?name`, který využijete v případě, že název tabulky nebo sloupce je proměnnou. (Pozor, nedovolte uživateli manipulovat s obsahem takové proměnné): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transakce -========= - -Pro práci s transakcemi slouží trojice metod: - -```php -$database->beginTransaction(); // zahájení transakce - -$database->commit(); // potvrzení - -$database->rollback(); // vrácení zpět -``` - -Elegantní způsob nabízí metoda `transaction()`, které předáme callback, který se vykoná v transakci. Pokud během vykonávání dojde k vyhození výjimky, transakce se zahodí, pokud vše proběhne v pořádku, transakce se potvrdí. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Jak vidíte, metoda `transaction()` vrací návratovou hodnotu callbacku. - -Volání `transaction()` může být i zanořeno, což zjednodušuje implementaci nezávislých repozitářů. +{{redirect: guide}} diff --git a/database/de/core.texy b/database/de/core.texy index 75b7f21349..096e5311b0 100644 --- a/database/de/core.texy +++ b/database/de/core.texy @@ -1,350 +1 @@ -Datenbank-Kern -************** - -.[perex] -Nette Database Core ist eine Datenbankabstraktionsschicht und bietet Kernfunktionen. - - -Installation .[#toc-installation] -================================= - -Laden Sie das Paket herunter und installieren Sie es mit [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Verbindung und Konfiguration .[#toc-connection-and-configuration] -================================================================= - -Um eine Verbindung zur Datenbank herzustellen, erstellen Sie einfach eine Instanz der Klasse [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Der Parameter `$dsn` (Name der Datenquelle) ist [derselbe, der auch von PDO verwendet wird |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], z. B. `host=127.0.0.1;dbname=test`. Im Falle eines Fehlers wird `Nette\Database\ConnectionException` ausgelöst. - -Eine anspruchsvollere Methode bietet jedoch die [Anwendungskonfiguration |configuration]. Wir fügen einen Abschnitt `database` hinzu, der die erforderlichen Objekte und ein Datenbank-Panel in der [Tracy-Leiste |tracy:] erstellt. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Das Verbindungsobjekt [erhalten wir z. B. als Dienst von einem DI-Container |dependency-injection:passing-dependencies]: - -```php -class Model -{ - // übergibt Nette\Database\Explorer, um mit der Datenbank-Explorer-Schicht zu arbeiten - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Weitere Informationen finden Sie unter [Datenbankkonfiguration |configuration]. - - -Abfragen .[#toc-queries] -======================== - -Für Datenbankabfragen verwenden Sie die Methode `query()`, die ein [ResultSet |api:Nette\Database\ResultSet] zurückgibt. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // gibt die Anzahl der Zeilen zurück, wenn diese bekannt ist -``` - -.[note] -Über die `ResultSet` ist es möglich, nur einmal zu iterieren, wenn wir mehrere Male iterieren müssen, ist es notwendig, das Ergebnis in das Array über `fetchAll()` Methode zu konvertieren. - -Sie können der Abfrage einfach Parameter hinzufügen, beachten Sie das Fragezeichen: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids ist array -``` -
- -WARNUNG, verketten Sie niemals Zeichenketten, um eine [SQL-Injection-Schwachstelle |https://en.wikipedia.org/wiki/SQL_injection] zu vermeiden! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -Im Falle eines Fehlers löst `query()` entweder `Nette\Database\DriverException` oder einen seiner Abkömmlinge aus: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - Verletzung einer Beschränkung -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - ungültiger Fremdschlüssel -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - Verstoß gegen die NOT NULL-Bedingung -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - Konflikt eines eindeutigen Index - -Zusätzlich zu `query()` gibt es weitere nützliche Methoden: - -```php -// gibt das assoziative Array id => name zurück -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// gibt alle Zeilen als Array zurück -$rows = $database->fetchAll('SELECT * FROM users'); - -// gibt einzelne Zeile zurück -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// gibt einzelnes Feld zurück -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -Im Falle eines Fehlers werfen alle diese Methoden `Nette\Database\DriverException.` - - -Einfügen, Aktualisieren & Löschen .[#toc-insert-update-delete] -============================================================== - -Der Parameter, den wir in die SQL-Abfrage einfügen, kann auch das Array sein (in diesem Fall ist es möglich, die Platzhalteranweisung `?`), which may be useful for the `INSERT` zu überspringen: - -```php -$database->query('INSERT INTO users ?', [ // hier kann das Fragezeichen weggelassen werden - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // gibt das automatische Inkrement der eingefügten Zeile zurück - -$id = $database->getInsertId($sequence); // oder Sequenzwert -``` - -Mehrfaches Einfügen: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Wir können auch Dateien, DateTime-Objekte oder [Aufzählungen |https://www.php.net/enumerations] übergeben: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // oder $datenbank::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // fügt Dateiinhalt ein - 'status' => State::New, // enum State -]); -``` - -Zeilen aktualisieren: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // gibt die Anzahl der betroffenen Zeilen zurück -``` - -Für UPDATE können wir die Operatoren `+=` und `-=` verwenden: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Löschen: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // gibt die Anzahl der betroffenen Zeilen zurück -``` - - -Erweiterte Abfragen .[#toc-advanced-queries] -============================================ - -Einfügen oder Aktualisieren, wenn sie bereits existiert: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Beachten Sie, dass Nette Database den SQL-Kontext erkennt, in den der Array-Parameter eingefügt wird, und den SQL-Code entsprechend aufbaut. So erzeugt er aus dem ersten Array `(id, name, year) VALUES (123, 'Jim', 1978)`, während der zweite in `name = 'Jim', year = 1978` umgewandelt wird. - -Wir können auch die Sortierung mit Hilfe eines Arrays beschreiben, wobei die Schlüssel Spaltennamen und die Werte Boolesche Werte sind, die festlegen, ob in aufsteigender Reihenfolge sortiert werden soll: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // aufsteigend - 'name' => false, // absteigend -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Wenn die Erkennung nicht funktioniert hat, können Sie die Form der Baugruppe mit einem Platzhalter `?` gefolgt von einem Hinweis angeben. Diese Hinweise werden unterstützt: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = wert1, key2 = wert2, ... -| ?and | Schlüssel1 = Wert1 AND Schlüssel2 = Wert2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -Die WHERE-Klausel verwendet den Operator `?and`, so dass die Bedingungen durch `AND` verknüpft werden: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Das kann leicht in `OR` geändert werden, indem man den Platzhalter `?or` verwendet: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Wir können Operatoren in Bedingungen verwenden: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Und auch Aufzählungen: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // Aufzählung + Operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Wir können auch ein Stück benutzerdefinierten SQL-Code einfügen, indem wir das so genannte SQL-Literal verwenden: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternativ dazu: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL-Literal kann auch seine Parameter haben: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Dadurch können wir interessante Kombinationen erstellen: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Variable Name .[#toc-variable-name] -=================================== - -Es gibt einen `?name` Platzhalter, den Sie verwenden, wenn der Tabellen- oder Spaltenname eine Variable ist. (Achtung, erlauben Sie dem Benutzer nicht, den Inhalt einer solchen Variablen zu manipulieren): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Vorgänge .[#toc-transactions] -============================= - -Es gibt drei Methoden für den Umgang mit Transaktionen: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Einen eleganten Weg bietet die Methode `transaction()`. Sie übergeben den Callback, der in der Transaktion ausgeführt wird. Wenn während der Ausführung eine Ausnahme auftritt, wird die Transaktion abgebrochen, wenn alles gut geht, wird die Transaktion bestätigt. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Wie Sie sehen können, gibt die Methode `transaction()` den Rückgabewert des Callbacks zurück. - -Die Transaktion() kann auch verschachtelt werden, was die Implementierung unabhängiger Repositories vereinfacht. +{{redirect: guide}} diff --git a/database/el/core.texy b/database/el/core.texy index 8087562d37..096e5311b0 100644 --- a/database/el/core.texy +++ b/database/el/core.texy @@ -1,350 +1 @@ -Πυρήνας βάσης δεδομένων -*********************** - -.[perex] -Το Nette Database Core είναι ένα επίπεδο αφαίρεσης βάσεων δεδομένων και παρέχει βασική λειτουργικότητα. - - -Εγκατάσταση .[#toc-installation] -================================ - -Κατεβάστε και εγκαταστήστε το πακέτο χρησιμοποιώντας το [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Composer: Σύνδεση και διαμόρφωση .[#toc-connection-and-configuration] -===================================================================== - -Για να συνδεθείτε στη βάση δεδομένων, απλώς δημιουργήστε μια περίπτωση της κλάσης [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Η παράμετρος `$dsn` (όνομα πηγής δεδομένων) είναι [η ίδια που χρησιμοποιείται από το PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], π.χ. `host=127.0.0.1;dbname=test`. Σε περίπτωση αποτυχίας πετάει το `Nette\Database\ConnectionException`. - -Ωστόσο, ένας πιο εξελιγμένος τρόπος προσφέρει [διαμόρφωση της εφαρμογής |configuration]. Θα προσθέσουμε ένα τμήμα `database` και αυτό δημιουργεί τα απαιτούμενα αντικείμενα και ένα πάνελ βάσης δεδομένων στη γραμμή [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Το αντικείμενο σύνδεσης που [λαμβάνουμε ως υπηρεσία από ένα δοχείο DI |dependency-injection:passing-dependencies], για παράδειγμα: - -```php -class Model -{ - // περάστε το Nette\Database\Explorer για να εργαστείτε με το επίπεδο Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Για περισσότερες πληροφορίες, ανατρέξτε στη [διαμόρφωση της βάσης δεδομένων |configuration]. - - -Ερωτήματα .[#toc-queries] -========================= - -Για να κάνετε ερώτημα στη βάση δεδομένων χρησιμοποιήστε τη μέθοδο `query()` που επιστρέφει [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // επιστρέφει τον αριθμό των γραμμών αν είναι γνωστός -``` - -.[note] -Πάνω από το `ResultSet` είναι δυνατόν να γίνει επανάληψη μόνο μία φορά, αν χρειαστεί να γίνει επανάληψη πολλές φορές, είναι απαραίτητο να μετατρέψουμε το αποτέλεσμα σε πίνακα μέσω της μεθόδου `fetchAll()`. - -Μπορείτε εύκολα να προσθέσετε παραμέτρους στο ερώτημα, σημειώστε το ερωτηματικό: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids είναι πίνακας -``` -
- -ΠΡΟΕΙΔΟΠΟΙΗΣΗ, μην συνδέετε ποτέ συμβολοσειρές για να αποφύγετε [την ευπάθεια SQL injection |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -Σε περίπτωση αποτυχίας το `query()` πετάει είτε το `Nette\Database\DriverException` είτε έναν από τους απογόνους του: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - παραβίαση οποιουδήποτε περιορισμού -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - μη έγκυρο ξένο κλειδί -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - παραβίαση της συνθήκης NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - σύγκρουση μοναδικού δείκτη - -Εκτός από το `query()`, υπάρχουν και άλλες χρήσιμες μέθοδοι: - -```php -// επιστρέφει τον συσχετιστικό πίνακα id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// επιστρέφει όλες τις γραμμές ως πίνακα -$rows = $database->fetchAll('SELECT * FROM users'); - -// επιστρέφει μία μόνο γραμμή -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// επιστρέφει ένα μόνο πεδίο -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -Σε περίπτωση αποτυχίας, όλες αυτές οι μέθοδοι ρίχνουν `Nette\Database\DriverException.` - - -Εισαγωγή, ενημέρωση και διαγραφή .[#toc-insert-update-delete] -============================================================= - -Η παράμετρος που εισάγουμε στο ερώτημα SQL μπορεί επίσης να είναι ο πίνακας (σε αυτή την περίπτωση είναι δυνατόν να παραλείψουμε τη δήλωση μπαλαντέρ `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // εδώ μπορεί να παραλειφθεί το ερωτηματικό - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // επιστρέφει την αυτόματη αύξηση της εισαγόμενης γραμμής - -$id = $database->getInsertId($sequence); // ή τιμή ακολουθίας -``` - -Πολλαπλή εισαγωγή: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -DateTime ή [απαριθμήσεις |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // ή $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // Εισάγει τα περιεχόμενα του αρχείου - 'status' => State::New, // enum Κατάσταση -]); -``` - -Ενημέρωση γραμμών: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // επιστρέφει τον αριθμό των επηρεαζόμενων γραμμών -``` - -Για UPDATE, μπορούμε να χρησιμοποιήσουμε τους τελεστές `+=` και `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Διαγραφή: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // επιστρέφει τον αριθμό των επηρεαζόμενων γραμμών -``` - - -Ερωτήματα για προχωρημένους .[#toc-advanced-queries] -==================================================== - -Εισαγωγή ή ενημέρωση, εάν υπάρχει ήδη: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Σημειώστε ότι η Nette Database αναγνωρίζει το πλαίσιο SQL στο οποίο εισάγεται η παράμετρος του πίνακα και δημιουργεί τον κώδικα SQL ανάλογα. Έτσι, από τον πρώτο πίνακα παράγει το `(id, name, year) VALUES (123, 'Jim', 1978)`, ενώ ο δεύτερος μετατρέπεται σε `name = 'Jim', year = 1978`. - -Μπορούμε επίσης να περιγράψουμε την ταξινόμηση χρησιμοποιώντας array, στο keys είναι ονόματα στηλών και values είναι boolean που καθορίζει αν θα γίνει ταξινόμηση σε αύξουσα σειρά: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // αύξουσα - 'name' => false, // φθίνουσα -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Εάν η ανίχνευση δεν λειτούργησε, μπορείτε να καθορίσετε τη μορφή της συνέλευσης με ένα μπαλαντέρ `?` ακολουθούμενο από μια υπόδειξη. Αυτές οι υποδείξεις υποστηρίζονται: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -Η ρήτρα WHERE χρησιμοποιεί τον τελεστή `?and` έτσι ώστε οι συνθήκες να συνδέονται με το `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Το οποίο μπορεί εύκολα να αλλάξει σε `OR` με τη χρήση του μπαλαντέρ `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Μπορούμε να χρησιμοποιήσουμε τελεστές σε συνθήκες: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Και επίσης απαριθμήσεις: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // απαρίθμηση + τελεστής NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Μπορούμε επίσης να συμπεριλάβουμε ένα κομμάτι προσαρμοσμένου κώδικα SQL χρησιμοποιώντας το λεγόμενο SQL literal: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Εναλλακτικά: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literal μπορεί επίσης να έχει τις παραμέτρους του: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Χάρη σε αυτό μπορούμε να δημιουργήσουμε ενδιαφέροντες συνδυασμούς: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Όνομα μεταβλητής .[#toc-variable-name] -====================================== - -Υπάρχει ένα μπαλαντέρ `?name` που χρησιμοποιείτε αν το όνομα του πίνακα ή της στήλης είναι μεταβλητή. (Προσοχή, μην επιτρέψετε στο χρήστη να χειριστεί το περιεχόμενο μιας τέτοιας μεταβλητής): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Συναλλαγές .[#toc-transactions] -=============================== - -Υπάρχουν τρεις μέθοδοι για την αντιμετώπιση των συναλλαγών: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Η μέθοδος `transaction()` προσφέρει έναν κομψό τρόπο. Περνάτε το callback που εκτελείται στη συναλλαγή. Εάν κατά την εκτέλεση εκσφενδονιστεί μια εξαίρεση, η συναλλαγή εγκαταλείπεται, ενώ εάν όλα πάνε καλά, η συναλλαγή δεσμεύεται. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Όπως μπορείτε να δείτε, η μέθοδος `transaction()` επιστρέφει την τιμή επιστροφής του callback. - -Η transaction() μπορεί επίσης να είναι εμφωλευμένη, γεγονός που απλοποιεί την υλοποίηση ανεξάρτητων αποθετηρίων. +{{redirect: guide}} diff --git a/database/en/core.texy b/database/en/core.texy index d950f13509..096e5311b0 100644 --- a/database/en/core.texy +++ b/database/en/core.texy @@ -1,350 +1 @@ -Database Core -************* - -.[perex] -Nette Database Core is database abstraction layer and provides core functionality. - - -Installation -============ - -Download and install the package using [Composer|best-practices:composer]: - -```shell -composer require nette/database -``` - - -Connection and Configuration -============================ - -To connect to the database, simply create an instance of the [api:Nette\Database\Connection] class: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -The `$dsn` (data source name) parameter is [the same as used by PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], eg `host=127.0.0.1;dbname=test`. In the case of failure it throws `Nette\Database\ConnectionException`. - -However, a more sophisticated way offers [application configuration |configuration]. We will add a `database` section and it creates the required objects and a database panel in the [Tracy |tracy:] bar. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -The connection object we [receive as a service from a DI container |dependency-injection:passing-dependencies], for example: - -```php -class Model -{ - // pass Nette\Database\Explorer to work with the Database Explorer layer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -For more information, see [database configuration|configuration]. - - -Queries -======= - -To query database use `query()` method that returns [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // returns the number of rows if is known -``` - -.[note] -Over the `ResultSet` is possible to iterate only once, if we need to iterate multiple times, it is necessary to convert the result to the array via `fetchAll()` method. - -You can easily add parameters to the query, note the question mark: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids is array -``` - -
-WARNING, never concatenate strings to avoid [SQL injection vulnerability |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -In the case of failure `query()` throws either `Nette\Database\DriverException` or one of its descendants: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - violation of any constraint -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - invalid foreign key -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - violation of the NOT NULL condition -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflict of unique index - -In addition to `query()`, there are other useful methods: - -```php -// returns the associative array id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// returns all rows as array -$rows = $database->fetchAll('SELECT * FROM users'); - -// returns single row -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// return single field -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -In case of failure, all of these methods throw `Nette\Database\DriverException.` - - -Insert, Update & Delete -======================= - -The parameter that we insert into the SQL query can also be the array (in which case it is possible to skip the wildcard `?`), which may be useful for the `INSERT` statement: - -```php -$database->query('INSERT INTO users ?', [ // here can be omitted question mark - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // returns the auto-increment of inserted row - -$id = $database->getInsertId($sequence); // or sequence value -``` - -Multiple insert: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -We can also pass files, DateTime objects or [enumerations |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // or $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserts file contents - 'status' => State::New, // enum State -]); -``` - -Updating rows: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // returns the number of affected rows -``` - -For UPDATE, we can use operators `+=` and `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Deleting: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // returns the number of affected rows -``` - - -Advanced Queries -================ - -Insert or update, if it already exists: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Note that Nette Database recognizes the SQL context in which the array parameter is inserted and builds the SQL code accordingly. So, from the first array he generates `(id, name, year) VALUES (123, 'Jim', 1978)`, while the second converts to `name = 'Jim', year = 1978`. - -We can also describe sorting using array, in keys are column names and values are boolean that determines whether to sort in ascending order: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascending - 'name' => false, // descending -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -If the detection did not work, you can specify the form of the assembly with a wildcard `?` followed by a hint. These hints are supported: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -The WHERE clause uses the `?and` operator so conditions are linked by `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Which can easily be changed to `OR` by using the `?or` wildcard: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -We can use operators in conditions: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -And also enumerations: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -We can also include a piece of custom SQL code using the so-called SQL literal: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternatively: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literal also can have its parameters: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Thanks to which we can create interesting combinations: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Variable Name -============= - -There is a `?name` wildcard that you use if the table name or column name is a variable. (Beware, do not allow the user to manipulate the content of such a variable): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transactions -============ - -There are three methods for dealing with transactions: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -An elegant way is offered by the `transaction()` method. You pass the callback that is executed in the transaction. If an exception is thrown during execution, the transaction is dropped, if everything goes well, the transaction is committed. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -As you can see, the `transaction()` method returns the return value of the callback. - -The transaction() can also be nested, which simplifies the implementation of independent repositories. +{{redirect: guide}} diff --git a/database/es/core.texy b/database/es/core.texy index 9944ca9332..096e5311b0 100644 --- a/database/es/core.texy +++ b/database/es/core.texy @@ -1,350 +1 @@ -Base de datos -************* - -.[perex] -Nette Database Core es la capa de abstracción de la base de datos y proporciona la funcionalidad básica. - - -Instalación .[#toc-installation] -================================ - -Descargue e instale el paquete utilizando [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Conexión y configuración .[#toc-connection-and-configuration] -============================================================= - -Para conectarse a la base de datos, basta con crear una instancia de la clase [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -El parámetro `$dsn` (nombre de la fuente de datos) es el [mismo que utiliza PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], por ejemplo `host=127.0.0.1;dbname=test`. En caso de fallo, lanza `Nette\Database\ConnectionException`. - -Sin embargo, una forma más sofisticada ofrece la [configuración de la aplicación |configuration]. Añadiremos una sección `database` y crea los objetos requeridos y un panel de base de datos en la barra [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -El objeto de conexión que [recibimos como servicio de un contenedor DI |dependency-injection:passing-dependencies], por ejemplo: - -```php -class Model -{ - // pass Nette\Database\Explorer to work with the Database Explorer layer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Para más información, consulte [configuración de la base de datos |configuration]. - - -Consultas .[#toc-queries] -========================= - -Para consultar la base de datos utilice el método `query()` que devuelve [un ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // returns the number of rows if is known -``` - -.[note] -Sobre el `ResultSet` es posible iterar una sola vez, si necesitamos iterar múltiples veces, es necesario convertir el resultado al array mediante el método `fetchAll()`. - -Usted puede agregar fácilmente parámetros a la consulta, tenga en cuenta el signo de interrogación: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids is array -``` -
- -ADVERTENCIA, ¡nunca concatene cadenas para evitar [una vulnerabilidad de inyección SQL |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -En caso de fallo `query()` lanza `Nette\Database\DriverException` o uno de sus descendientes: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - violación de cualquier restricción -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - clave externa no válida -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - violación de la condición NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflicto de índice único - -Además de `query()`, existen otros métodos útiles: - -```php -// returns the associative array id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// returns all rows as array -$rows = $database->fetchAll('SELECT * FROM users'); - -// returns single row -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// return single field -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -En caso de fallo, todos estos métodos lanzan `Nette\Database\DriverException.` - - -Insertar, actualizar y eliminar .[#toc-insert-update-delete] -============================================================ - -El parámetro que insertamos en la consulta SQL también puede ser el array (en cuyo caso es posible omitir la sentencia comodín `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // here can be omitted question mark - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // returns the auto-increment of inserted row - -$id = $database->getInsertId($sequence); // or sequence value -``` - -Inserción múltiple: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -También podemos pasar ficheros, objetos DateTime o [enumeraciones |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // or $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserts file contents - 'status' => State::New, // enum State -]); -``` - -Actualización de filas: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // returns the number of affected rows -``` - -Para UPDATE, podemos utilizar los operadores `+=` y `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Borrado: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // returns the number of affected rows -``` - - -Consultas avanzadas .[#toc-advanced-queries] -============================================ - -Insertar o actualizar, si ya existe: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Nótese que Nette Database reconoce el contexto SQL en el que se inserta el parámetro del array y construye el código SQL en consecuencia. Así, a partir del primer array genera `(id, name, year) VALUES (123, 'Jim', 1978)`, mientras que el segundo lo convierte en `name = 'Jim', year = 1978`. - -También podemos describir la ordenación utilizando un array, en el que las claves son nombres de columnas y los valores son booleanos que determinan si se ordena en orden ascendente: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascending - 'name' => false, // descending -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Si la detección no ha funcionado, puede especificar la forma del conjunto con un comodín `?` seguido de una pista. Estas pistas son compatibles: - -| ?values | (clave1, clave2, ...) VALUES (valor1, valor2, ...) -| ?set | clave1 = valor1, clave2 = valor2, ... -| ?and | clave1 = valor1 Y clave2 = valor2 ... -| ?or | clave1 = valor1 OR clave2 = valor2 ... -| ?order | clave1 ASC, clave2 DESC - -La cláusula WHERE utiliza el operador `?and` por lo que las condiciones están vinculadas por `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Que puede cambiarse fácilmente a `OR` utilizando el comodín `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Podemos utilizar operadores en las condiciones: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Y también en enumeraciones: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -También podemos incluir un trozo de código SQL personalizado utilizando el llamado literal SQL: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternativamente: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literal también puede tener sus parámetros: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Gracias a los cuales podemos crear combinaciones interesantes: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Nombre de la variable .[#toc-variable-name] -=========================================== - -Existe un comodín `?name` que se utiliza si el nombre de la tabla o de la columna es una variable. (Cuidado, no permita que el usuario manipule el contenido de dicha variable): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transacciones .[#toc-transactions] -================================== - -Existen tres métodos para tratar las transacciones: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Una forma elegante es la que ofrece el método `transaction()`. Se pasa la llamada de retorno que se ejecuta en la transacción. Si se lanza una excepción durante la ejecución, la transacción se abandona, si todo va bien, la transacción se compromete. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Como puede ver, el método `transaction()` devuelve el valor de retorno de la llamada de retorno. - -La transacción() también se puede anidar, lo que simplifica la implementación de repositorios independientes. +{{redirect: guide}} diff --git a/database/fr/core.texy b/database/fr/core.texy index 2703fcc41d..096e5311b0 100644 --- a/database/fr/core.texy +++ b/database/fr/core.texy @@ -1,350 +1 @@ -Base de données Core -******************** - -.[perex] -Nette Database Core est une couche d'abstraction de base de données et fournit des fonctionnalités de base. - - -Installation .[#toc-installation] -================================= - -Téléchargez et installez le paquet en utilisant [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Connexion et configuration .[#toc-connection-and-configuration] -=============================================================== - -Pour se connecter à la base de données, il suffit de créer une instance de la classe [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Le paramètre `$dsn` (nom de la source de données) est le [même que celui utilisé par PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], par exemple `host=127.0.0.1;dbname=test`. En cas d'échec, il lance `Nette\Database\ConnectionException`. - -Cependant, une manière plus sophistiquée offre la [configuration de l'application |configuration]. Nous ajouterons une section `database` et elle créera les objets requis et un panneau de base de données dans la barre [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -L'objet de connexion que nous [recevons comme un service d'un conteneur DI |dependency-injection:passing-dependencies], par exemple : - -```php -class Model -{ - // passer Nette\Database\Explorer pour travailler avec la couche Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Pour plus d'informations, voir la [configuration de la base de données |configuration]. - - -Requêtes .[#toc-queries] -======================== - -Pour interroger la base de données, utilisez la méthode `query()` qui renvoie un [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // renvoie le nombre de lignes s'il est connu. -``` - -.[note] -Sur le site `ResultSet` il est possible d'itérer une seule fois, si nous avons besoin d'itérer plusieurs fois, il est nécessaire de convertir le résultat en tableau via la méthode `fetchAll()`. - -Vous pouvez facilement ajouter des paramètres à la requête, notez le point d'interrogation : - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids est un tableau -``` -
- -ATTENTION, ne jamais concaténer des chaînes de caractères pour éviter [une vulnérabilité d'injection SQL |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -En cas d'échec, `query()` lance soit `Nette\Database\DriverException`, soit l'un de ses descendants : - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - violation d'une contrainte quelconque -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - clé étrangère invalide -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - violation de la condition NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflit d'index unique - -En plus de `query()`, il existe d'autres méthodes utiles : - -```php -// renvoie le tableau associatif id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// renvoie toutes les lignes sous forme de tableau -$rows = $database->fetchAll('SELECT * FROM users'); - -// renvoie une seule ligne -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// renvoie un seul champ -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -En cas d'échec, toutes ces méthodes jettent `Nette\Database\DriverException.` - - -Insertion, mise à jour et suppression .[#toc-insert-update-delete] -================================================================== - -Le paramètre que nous insérons dans la requête SQL peut également être un tableau (dans ce cas, il est possible de sauter l'instruction joker `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // ici peut être omis le point d'interrogation - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // renvoie l'auto-incrément de la ligne insérée - -$id = $database->getInsertId($sequence); // ou valeur de la séquence -``` - -Insertion multiple : - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Nous pouvons également passer des fichiers, des objets DateTime ou des [énumérations |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // ou $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // insère le contenu du fichier - 'status' => State::New, // enum State -]); -``` - -Mise à jour des rangs : - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // renvoie le nombre de lignes affectées. -``` - -Pour UPDATE, nous pouvons utiliser les opérateurs `+=` et `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Suppression : - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // renvoie le nombre de lignes affectées. -``` - - -Requêtes avancées .[#toc-advanced-queries] -========================================== - -Insérer ou mettre à jour, s'il existe déjà : - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Notez que Nette Database reconnaît le contexte SQL dans lequel le paramètre du tableau est inséré et construit le code SQL en conséquence. Ainsi, à partir du premier tableau, il génère `(id, name, year) VALUES (123, 'Jim', 1978)`, tandis que le second se convertit en `name = 'Jim', year = 1978`. - -Nous pouvons également décrire le tri en utilisant un tableau, dans lequel les clés sont des noms de colonnes et les valeurs sont des booléens qui déterminent s'il faut trier par ordre croissant : - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascendant - 'name' => false, // descendant -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Si la détection n'a pas fonctionné, vous pouvez spécifier la forme de l'assemblage avec un joker `?` suivi d'un hint. Ces hints sont supportés : - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = valeur1, key2 = valeur2, ... -| ?et | clé1 = valeur1 ET clé2 = valeur2 ... -| ?or | key1 = valeur1 OR key2 = valeur2 ... -| ?order | clé1 ASC, clé2 DESC - -La clause WHERE utilise l'opérateur `?and` de sorte que les conditions sont liées par `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Ce qui peut facilement être changé en `OR` en utilisant le caractère générique `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Nous pouvons utiliser des opérateurs dans les conditions : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Et aussi les énumérations : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // énumération + opérateur NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Nous pouvons également inclure un morceau de code SQL personnalisé en utilisant ce que l'on appelle le littéral SQL : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternativement : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -Le littéral SQL peut aussi avoir ses paramètres : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Grâce à quoi nous pouvons créer des combinaisons intéressantes : - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Nom de la variable .[#toc-variable-name] -======================================== - -Il existe un joker `?name` que vous utilisez si le nom de la table ou de la colonne est une variable. (Attention, ne permettez pas à l'utilisateur de manipuler le contenu d'une telle variable) : - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transactions .[#toc-transactions] -================================= - -Il existe trois méthodes pour traiter les transactions : - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Une manière élégante est offerte par la méthode `transaction()`. Vous passez le callback qui est exécuté dans la transaction. Si une exception est levée pendant l'exécution, la transaction est abandonnée, si tout se passe bien, la transaction est validée. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Comme vous pouvez le voir, la méthode `transaction()` renvoie la valeur de retour de la callback. - -La transaction() peut également être imbriquée, ce qui simplifie la mise en œuvre de référentiels indépendants. +{{redirect: guide}} diff --git a/database/hu/core.texy b/database/hu/core.texy index 6c303bbcff..096e5311b0 100644 --- a/database/hu/core.texy +++ b/database/hu/core.texy @@ -1,350 +1 @@ -Adatbázis mag -************* - -.[perex] -A Nette Database Core az adatbázis absztrakciós rétege, és alapvető funkciókat biztosít. - - -Telepítés .[#toc-installation] -============================== - -Töltse le és telepítse a csomagot a [Composer |best-practices:composer] segítségével: - -```shell -composer require nette/database -``` - - -Csatlakozás és konfiguráció .[#toc-connection-and-configuration] -================================================================ - -Az adatbázishoz való csatlakozáshoz egyszerűen hozzon létre egy példányt a [api:Nette\Database\Connection] osztályból: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -A `$dsn` (adatforrás neve) paraméter [ugyanaz, mint amit a PDO használ |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], pl. `host=127.0.0.1;dbname=test`. Sikertelenség esetén a `Nette\Database\ConnectionException` dobja. - -Azonban egy kifinomultabb módot kínál az [alkalmazás konfigurálása |configuration]. Hozzáadunk egy `database` szakaszt, és ez létrehozza a szükséges objektumokat és egy adatbázis panelt a [Tracy |tracy:] sávban. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -A kapcsolati objektumot például [egy DI konténertől kapjuk szolgáltatásként |dependency-injection:passing-dependencies]: - -```php -class Model -{ - // Nette\Database\Explorer átadása az adatbázis-kutató réteggel való együttműködéshez. - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -További információért lásd: [adatbázis-konfiguráció |configuration]. - - -Lekérdezések .[#toc-queries] -============================ - -Az adatbázis lekérdezéséhez használja a `query()` módszert, amely [ResultSet-et |api:Nette\Database\ResultSet] ad vissza. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // visszaadja a sorok számát, ha ismert. -``` - -.[note] -A `ResultSet` felett csak egyszer lehet iterálni, ha többször kell iterálni, akkor az eredményt a `fetchAll()` metódussal kell tömbre konvertálni. - -A lekérdezéshez könnyen adhatunk paramétereket, figyeljük meg a kérdőjelet: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids egy tömb -``` -
- -FIGYELMEZTETÉS, soha ne fűzzön össze karakterláncokat az [SQL injekciós sebezhetőség |https://en.wikipedia.org/wiki/SQL_injection] elkerülése érdekében! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -Sikertelenség esetén a `query()` a `Nette\Database\DriverException` vagy valamelyik leszármazottját dobja: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - bármelyik megkötés megsértése. -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - érvénytelen idegen kulcs. -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - a NOT NULL feltétel megsértése. -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - az egyedi index konfliktusa. - -A `query()` mellett vannak más hasznos módszerek is: - -```php -// visszaadja az id => name asszociatív tömböt -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// visszaadja az összes sort tömbként -$rows = $database->fetchAll('SELECT * FROM users'); - -// egyetlen sort ad vissza -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// egyetlen mezőt ad vissza -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -Sikertelenség esetén ezek a módszerek mindegyike dobja a `Nette\Database\DriverException.` - - -Beszúrás, frissítés és törlés .[#toc-insert-update-delete] -========================================================== - -Az SQL-lekérdezésbe beszúrandó paraméter lehet a tömb is (ebben az esetben kihagyható a vadkártyás `?`), which may be useful for the `INSERT` utasítás: - -```php -$database->query('INSERT INTO users ?', [ // itt kihagyható a kérdőjel - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // visszaadja a beillesztett sor automatikus inkrementálását. - -$id = $database->getInsertId($sequence); // vagy a sor értéke -``` - -Többszörös beszúrás: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -DateTime objektumokat vagy [felsorolásokat |https://www.php.net/enumerations] is átadhatunk: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // vagy $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // a fájl tartalmának beszúrása. - 'status' => State::New, // enum állapot -]); -``` - -Sorok frissítése: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // visszaadja az érintett sorok számát -``` - -UPDATE esetén a `+=` és a `-=` operátorokat használhatjuk: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Törlés: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // visszaadja az érintett sorok számát. -``` - - -Speciális lekérdezések .[#toc-advanced-queries] -=============================================== - -Beszúrás vagy frissítés, ha már létezik: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Vegye figyelembe, hogy a Nette Database felismeri az SQL-kontextust, amelybe a tömbparamétert beillesztik, és ennek megfelelően építi fel az SQL-kódot. Így az első tömbből a `(id, name, year) VALUES (123, 'Jim', 1978)`, míg a másodikból a `name = 'Jim', year = 1978` címet alakítja át. - -A rendezést is leírhatjuk tömb használatával, a kulcsok az oszlopok nevei, az értékek pedig boolean értékek, amelyek meghatározzák, hogy növekvő sorrendbe rendezzük-e: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // felfelé növekvő - 'name' => false, // csökkenő -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Ha a felismerés nem működött, akkor az összeállítás formáját megadhatjuk a `?` jokerjelzéssel, amelyet egy utalás követ. Ezek a tippek támogatottak: - -| ?values | (kulcs1, kulcs2, ...) VALUES (érték1, érték2, ...) -| ?set | kulcs1 = érték1, kulcs2 = érték2, ... -| ?and | kulcs1 = érték1 ÉS kulcs2 = érték2 ... -| ?or | kulcs1 = érték1 VAGY kulcs2 = érték2 ... -| ?order | kulcs1 ASC, kulcs2 DESC - -A WHERE záradék a `?and` operátort használja, így a feltételeket a `AND` kapcsolja össze: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Ami könnyen megváltoztatható `OR` -ra a `?or` joker használatával: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Használhatunk operátorokat a feltételekben: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -És felsorolásokat is: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Az úgynevezett SQL literál segítségével egy darab egyéni SQL-kódot is beilleszthetünk: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternatívaként: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literál is lehet a paraméterei: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Ennek köszönhetően érdekes kombinációkat hozhatunk létre: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Változó neve .[#toc-variable-name] -================================== - -Van egy `?name` joker, amelyet akkor használhat, ha a táblázat neve vagy az oszlop neve egy változó. (Vigyázat, ne engedje, hogy a felhasználó manipulálja egy ilyen változó tartalmát): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Tranzakciók .[#toc-transactions] -================================ - -A tranzakciók kezelésére három módszer áll rendelkezésre: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -A `transaction()` módszer elegáns megoldást kínál. Átadjuk a tranzakcióban végrehajtott visszahívást. Ha a végrehajtás során kivételt dobunk, a tranzakciót eldobjuk, ha minden rendben megy, a tranzakciót lekötjük. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Mint látható, a `transaction()` metódus a callback visszatérési értékét adja vissza. - -A tranzakció() is beágyazható, ami egyszerűsíti a független tárolók megvalósítását. +{{redirect: guide}} diff --git a/database/it/core.texy b/database/it/core.texy index 562e9d941f..096e5311b0 100644 --- a/database/it/core.texy +++ b/database/it/core.texy @@ -1,350 +1 @@ -Nucleo del database -******************* - -.[perex] -Nette Database Core è il livello di astrazione del database e fornisce le funzionalità principali. - - -Installazione .[#toc-installation] -================================== - -Scaricare e installare il pacchetto utilizzando [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Connessione e configurazione .[#toc-connection-and-configuration] -================================================================= - -Per connettersi al database, è sufficiente creare un'istanza della classe [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Il parametro `$dsn` (nome dell'origine dati) è lo [stesso utilizzato da PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], ad esempio `host=127.0.0.1;dbname=test`. In caso di fallimento, viene lanciato `Nette\Database\ConnectionException`. - -Tuttavia, un modo più sofisticato offre la [configurazione dell'applicazione |configuration]. Aggiungiamo una sezione `database` che crea gli oggetti necessari e un pannello del database nella barra [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -L'oggetto connessione che [riceviamo come servizio da un contenitore DI |dependency-injection:passing-dependencies], ad esempio: - -```php -class Model -{ - // passa Nette\Database\Explorer per lavorare con il livello Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Per ulteriori informazioni, vedere [Configurazione del database |configuration]. - - -Query .[#toc-queries] -===================== - -Per interrogare il database utilizzare il metodo `query()` che restituisce [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // restituisce il numero di righe se è conosciuto -``` - -.[note] -Su `ResultSet` è possibile iterare una sola volta; se abbiamo bisogno di iterare più volte, è necessario convertire il risultato in array con il metodo `fetchAll()`. - -È possibile aggiungere facilmente dei parametri alla query, come il punto interrogativo: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids è un array -``` -
- -ATTENZIONE, non concatenare mai le stringhe per evitare [vulnerabilità da SQL injection |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -In caso di fallimento, `query()` lancia `Nette\Database\DriverException` o uno dei suoi discendenti: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - violazione di qualsiasi vincolo -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - chiave esterna non valida -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - violazione della condizione NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflitto di un indice univoco - -Oltre a `query()`, esistono altri metodi utili: - -```php -// restituisce l'array associativo id => nome -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// restituisce tutte le righe come array -$rows = $database->fetchAll('SELECT * FROM users'); - -// restituisce una singola riga -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// restituisce un singolo campo -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -In caso di fallimento, tutti questi metodi lanciano `Nette\Database\DriverException.` - - -Inserire, aggiornare e cancellare .[#toc-insert-update-delete] -============================================================== - -Il parametro che inseriamo nella query SQL può anche essere un array (in questo caso è possibile saltare l'istruzione jolly `?`), which may be useful for the `INSERT` ): - -```php -$database->query('INSERT INTO users ?', [ // qui si può omettere il punto interrogativo - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // restituisce l'autoincremento della riga inserita - -$id = $database->getInsertId($sequence); // o il valore della sequenza -``` - -Inserimento multiplo: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Si possono passare anche file, oggetti DateTime o [enumerazioni |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // o $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserisce il contenuto del file - 'status' => State::New, // enum State -]); -``` - -Aggiornamento delle righe: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // restituisce il numero delle righe interessate -``` - -Per l'UPDATE si possono utilizzare gli operatori `+=` e `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Eliminazione: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // restituisce il numero di righe interessate -``` - - -Query avanzate .[#toc-advanced-queries] -======================================= - -Inserire o aggiornare, se esiste già: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Si noti che Nette Database riconosce il contesto SQL in cui è inserito il parametro dell'array e costruisce il codice SQL di conseguenza. Quindi, dal primo array genera `(id, name, year) VALUES (123, 'Jim', 1978)`, mentre il secondo si converte in `name = 'Jim', year = 1978`. - -Possiamo anche descrivere l'ordinamento utilizzando un array, in cui le chiavi sono nomi di colonne e i valori sono booleani che determinano se ordinare in ordine crescente: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // crescente - 'name' => false, // discendente -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Se il rilevamento non funziona, è possibile specificare la forma dell'insieme con un carattere jolly `?` seguito da un suggerimento. Sono supportati questi suggerimenti: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = valore1, key2 = valore2, ... -| ?and | key1 = valore1 AND key2 = valore2 ... -| ?or | key1 = valore1 OR key2 = valore2 ... -| ?order | key1 ASC, key2 DESC - -La clausola WHERE utilizza l'operatore `?and`, quindi le condizioni sono collegate da `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Che può essere facilmente modificato in `OR` utilizzando il carattere jolly `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Possiamo usare gli operatori nelle condizioni: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -E anche le enumerazioni: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Possiamo anche includere un pezzo di codice SQL personalizzato utilizzando il cosiddetto letterale SQL: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -In alternativa: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -Anche i letterali SQL possono avere i loro parametri: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Grazie a questi si possono creare interessanti combinazioni: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Nome della variabile .[#toc-variable-name] -========================================== - -Esiste un carattere jolly `?name` da utilizzare se il nome della tabella o della colonna è una variabile. (Attenzione, non permettete all'utente di manipolare il contenuto di tale variabile): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transazioni .[#toc-transactions] -================================ - -Esistono tre metodi per gestire le transazioni: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Un modo elegante è offerto dal metodo `transaction()`. Si passa il callback che viene eseguito nella transazione. Se viene lanciata un'eccezione durante l'esecuzione, la transazione viene abbandonata; se tutto va bene, la transazione viene impegnata. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Come si può vedere, il metodo `transaction()` restituisce il valore di ritorno della callback. - -Il metodo transaction() può anche essere annidato, il che semplifica l'implementazione di repository indipendenti. +{{redirect: guide}} diff --git a/database/pl/core.texy b/database/pl/core.texy index 706713ee75..096e5311b0 100644 --- a/database/pl/core.texy +++ b/database/pl/core.texy @@ -1,350 +1 @@ -Baza danych Rdzeń -***************** - -.[perex] -Nette Database Core to warstwa bazowa dostępu do bazy danych, tzw. warstwa abstrakcji bazy danych. - - -Instalacja .[#toc-installation] -=============================== - -Pobierz i zainstaluj bibliotekę za pomocą [Composera |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Podłączenie i konfiguracja .[#toc-connection-and-configuration] -=============================================================== - -Aby połączyć się z bazą danych, wystarczy stworzyć instancję klasy [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Parametr `$dsn` (nazwa źródła danych) jest taki sam jak ten [używany przez PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], np. `host=127.0.0.1;dbname=test`. W przypadku niepowodzenia rzuca wyjątek `Nette\Database\ConnectionException`. - -Bardziej poręczny sposób oferuje jednak [konfiguracja aplikacji |configuration], gdzie wystarczy dodać sekcję `database`, a ona sama utworzy potrzebne obiekty, a także pasek bazy danych w pasku [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Następnie [otrzymujemy |dependency-injection:passing-dependencies] obiekt połączenia [jako usługę z kontenera DI |dependency-injection:passing-dependencies], na przykład: - -```php -class Model -{ - // pro práci s vrstvou Database Explorer si předáme Nette\Database\Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Więcej informacji na temat [konfiguracji bazy danych |configuration]. - - -Pytania .[#toc-queries] -======================= - -Zapytania do bazy danych są zadawane za pomocą metody `query()`, która zwraca [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // zwraca liczbę wierszy wyniku, jeśli jest znana -``` - -.[note] -Możesz iterować nad `ResultSet` tylko raz, jeśli potrzebujesz iterować więcej niż raz, musisz przekonwertować wynik na tablicę za pomocą metody `fetchAll()`. - -Bardzo łatwo jest również dodać parametry do zapytania, zauważ znak zapytania: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids je pole -``` -
- -OSTRZEŻENIE, nigdy nie komponuj zapytań jako ciągów znaków, to stworzyłoby lukę w [SQL injection |https://cs.wikipedia.org/wiki/SQL_injection] -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // ŠPATNĚ!!! -\-- -
- -Jeśli `query()` nie powiedzie się, rzuci albo `Nette\Database\DriverException` albo jeden z jego potomków: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - naruszenie jakiegoś ograniczenia dla tabeli -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - nieprawidłowy klucz obcy -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - naruszenie ograniczenia NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - sprzeczny unikalny indeks - -Oprócz strony `query()` znajdują się na niej inne przydatne funkcje: - -```php -// zwróć tablicę asocjacyjną id => nazwa -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// zwraca wszystkie rekordy jako tablicę -$rows = $database->fetchAll('SELECT * FROM users'); - -// zwraca pojedynczy rekord -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// zwraca bezpośrednio wartość komórki -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -W przypadku niepowodzenia, wszystkie te metody rzucą `Nette\Database\DriverException`. - - -Wstawianie, aktualizacja i usuwanie .[#toc-insert-update-delete] -================================================================ - -Parametr, który wstawiamy do zapytania SQL może być również tablicą (w tym przypadku możliwe jest również użycie placeholdera `?` vynechat), což se hodí třeba pro sestavení příkazu `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // możemy tutaj pominąć znak zapytania - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // zwróć auto-increment wstawionego rekordu - -$id = $database->getInsertId($sequence); // lub wartość sekwencji -``` - -Multiple INSERT: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Jako parametry mogą być przekazywane pliki, obiekty DateTime lub [typy wyliczeniowe |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // nebo $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // vloží soubor - 'status' => State::New, // enum State -]); -``` - -Edycja zapisów: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // zwraca liczbę dotkniętych wierszy -``` - -Dla UPDATE możemy użyć operatorów `+=` i `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // uwaga += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Usuwanie: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // zwraca liczbę dotkniętych wierszy -``` - - -Pytania zaawansowane .[#toc-advanced-queries] -============================================= - -Wstawianie lub edycja rekordu, jeśli już istnieje: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Zauważ, że Nette Database rozpoznaje kontekst instrukcji SQL, w której wstawiony jest parametr z polem i odpowiednio buduje kod SQL. Zbudował więc `(id, name, year) VALUES (123, 'Jim', 1978)` z pierwszego pola, jednocześnie przekształcając drugie pole do postaci `name = 'Jim', year = 1978`. - -Możemy również wpłynąć na sortowanie za pomocą tablicy, w kluczach podamy kolumny, a wartością będzie boolean określający czy sortować w porządku rosnącym: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // vzestupně - 'name' => false, // sestupně -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Jeśli wykrywanie nie działa dla nietypowej konstrukcji, możesz określić formę budowy przez symbol wieloznaczny `?`, po którym następuje podpowiedź. Obsługiwane są następujące wskazówki: - -| (klucz1, klucz2, ...) VALUES (wartość1, wartość2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| lub | key1 = value1 OR key2 = value2 ... -|?order | key1 ASC, key2 DESC - -Klauzula WHERE używa operatora `?and`, więc warunki są połączone operatorem `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Które możemy łatwo zmienić na `OR` podając placeholder `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -W warunkach możemy używać operatorów: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -A także wyliczenia: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // výčet + operátor NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Możemy również wstawić do warunku fragment własnego kodu SQL, używając tzw. literału SQL: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Lub alternatywnie: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -Literał SQL może mieć również parametry: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Co pozwala nam na tworzenie ciekawych kombinacji: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Nazwa zmiennej .[#toc-variable-name] -==================================== - -Istnieje również placeholder `?name`, którego używasz, jeśli nazwa tabeli lub kolumny jest zmienną. (Uważaj, aby nie pozwolić użytkownikowi manipulować zawartością takiej zmiennej): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transakcja .[#toc-transactions] -=============================== - -Istnieją trzy metody pracy z transakcjami: - -```php -$database->beginTransaction(); // rozpoczęcie transakcji - -$database->commit(); // commit - -$database->rollback(); // rollback -``` - -Metoda `transaction()` zapewnia elegancki sposób przekazywania wywołania zwrotnego, które jest wykonywane w transakcji. Jeśli podczas wykonywania zostanie rzucony wyjątek, transakcja jest odrzucana; jeśli wszystko pójdzie dobrze, transakcja jest popełniana. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Jak widać, metoda `transaction()` zwraca wartość zwrotną wywołania zwrotnego. - -Callback `transaction()` może być również zagnieżdżony, co upraszcza implementację niezależnych repozytoriów. +{{redirect: guide}} diff --git a/database/pt/core.texy b/database/pt/core.texy index a3a5df1e0a..096e5311b0 100644 --- a/database/pt/core.texy +++ b/database/pt/core.texy @@ -1,350 +1 @@ -Núcleo do banco de dados -************************ - -.[perex] -Nette Database Core é a camada de abstração do banco de dados e fornece a funcionalidade do núcleo. - - -Instalação .[#toc-installation] -=============================== - -Baixe e instale o pacote usando [o Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Conexão e configuração .[#toc-connection-and-configuration] -=========================================================== - -Para conectar-se ao banco de dados, basta criar uma instância da classe [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -O parâmetro `$dsn` (nome da fonte de dados) é [o mesmo que o utilizado pela DOP |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], por exemplo `host=127.0.0.1;dbname=test`. Em caso de falha, ele lança `Nette\Database\ConnectionException`. - -Entretanto, uma maneira mais sofisticada oferece [configuração de aplicação |configuration]. Acrescentaremos uma seção `database` e ela cria os objetos necessários e um painel de banco de dados na barra [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -O objeto de conexão que [recebemos como um serviço de um container DI |dependency-injection:passing-dependencies], por exemplo: - -```php -class Model -{ - // pass Nette\Database\Explorer para trabalhar com a camada Database Explorer\Database - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Para mais informações, consulte a [configuração do banco de dados |configuration]. - - -Consultas .[#toc-queries] -========================= - -Para consultar o banco de dados utilize o método `query()` que retorna o [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // devolve o número de filas se for conhecido -``` - -.[note] -Sobre o `ResultSet` é possível iterar apenas uma vez, se precisarmos iterar várias vezes, é necessário converter o resultado para a matriz através do método `fetchAll()`. - -Você pode facilmente adicionar parâmetros à consulta, anote o ponto de interrogação: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids is array -``` -
- -AVISO, nunca concatenar cordas para evitar [vulnerabilidade de injeção SQL |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -Em caso de falha `query()` lança ou `Nette\Database\DriverException` ou um de seus descendentes: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - violação de qualquer restrição -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - chave estrangeira inválida -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - violação da condição NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflito de índice único - -Além de `query()`, existem outros métodos úteis: - -```php -// retorna a matriz associativa id => nome -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// devolve todas as filas como matriz -$rows = $database->fetchAll('SELECT * FROM users'); - -// retorna em fila única -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// retornar campo único -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -Em caso de falha, todos esses métodos jogam `Nette\Database\DriverException.` - - -Inserir, atualizar e excluir .[#toc-insert-update-delete] -========================================================= - -O parâmetro que inserimos na consulta SQL também pode ser o array (nesse caso é possível pular a declaração wildcard `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // aqui pode ser omitido o ponto de interrogação - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // devolve o auto-incremento da linha inserida - -$id = $database->getInsertId($seqüência); // ou valor da seqüência -``` - -Inserção múltipla: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Também podemos passar arquivos, objetos DateTime ou [enumerações |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // or $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserts file contents - 'status' => State::New, // enum State -]); -``` - -Atualização de linhas: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // devolve o número de filas afetadas -``` - -Para a atualização, podemos utilizar os operadores `+=` e `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Eliminação: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // returns the number of affected rows -``` - - -Consultas avançadas .[#toc-advanced-queries] -============================================ - -Inserir ou atualizar, se já existir: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Observe que o Nette Database reconhece o contexto SQL no qual o parâmetro da matriz é inserido e constrói o código SQL de acordo. Assim, a partir do primeiro array ele gera `(id, name, year) VALUES (123, 'Jim', 1978)`, enquanto o segundo converte para `name = 'Jim', year = 1978`. - -Também podemos descrever a ordenação usando matriz, em chaves estão os nomes das colunas e os valores são booleanos que determinam se a ordenação deve ser feita em ordem ascendente: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascendente - 'name' => false, // decrescente -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Se a detecção não funcionou, você pode especificar a forma da montagem com um curinga `?` seguido de uma dica. Estas dicas são suportadas: - -| ?valores | (chave1, chave2, ...) VALORES (valor1, valor2, ...) -| ?set | chave1 = valor1, chave2 = valor2, ... -| ?e | chave1 = valor1 E chave2 = valor2 ... -| ?ou | chave1 = valor1 OU chave2 = valor2 ... -| ?ordem | chave1 ASC, chave2 DESC - -A cláusula WHERE utiliza o operador `?and`, portanto as condições estão vinculadas por `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -O que pode ser facilmente alterado para `OR`, utilizando o wildcard `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Podemos utilizar os operadores em condições: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -E também enumerações: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Também podemos incluir uma peça de código SQL personalizada usando o chamado SQL literal: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternativamente: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literal também pode ter seus parâmetros: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Graças a isso, podemos criar combinações interessantes: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Nome da variável .[#toc-variable-name] -====================================== - -Há um wildcard `?name` que você utiliza se o nome da tabela ou nome da coluna for uma variável. (Cuidado, não permita que o usuário manipule o conteúdo de tal variável): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transações .[#toc-transactions] -=============================== - -Há três métodos para lidar com as transações: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Uma maneira elegante é oferecida pelo método `transaction()`. Você passa o callback que é executado na transação. Se for lançada uma exceção durante a execução, a transação é descartada, se tudo correr bem, a transação é comprometida. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Como você pode ver, o método `transaction()` retorna o valor de retorno da ligação de retorno. - -A transação() também pode ser aninhada, o que simplifica a implementação de repositórios independentes. +{{redirect: guide}} diff --git a/database/ro/core.texy b/database/ro/core.texy index 4314a3fe2d..096e5311b0 100644 --- a/database/ro/core.texy +++ b/database/ro/core.texy @@ -1,350 +1 @@ -Baza de date de bază -******************** - -.[perex] -Nette Database Core este un strat de abstractizare a bazei de date și oferă funcționalitatea de bază. - - -Instalare .[#toc-installation] -============================== - -Descărcați și instalați pachetul folosind [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Conectare și configurare .[#toc-connection-and-configuration] -============================================================= - -Pentru a vă conecta la baza de date, creați pur și simplu o instanță a clasei [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Parametrul `$dsn` (numele sursei de date) este [același cu cel utilizat de PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], de exemplu `host=127.0.0.1;dbname=test`. În caz de eșec, se aruncă `Nette\Database\ConnectionException`. - -Cu toate acestea, o modalitate mai sofisticată oferă [configurarea aplicației |configuration]. Vom adăuga o secțiune `database` și aceasta creează obiectele necesare și un panou cu baza de date în bara [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Obiectul de conexiune pe care îl [primim ca serviciu de la un container DI |dependency-injection:passing-dependencies], de exemplu: - -```php -class Model -{ - // treceți Nette\Database\Explorer pentru a lucra cu stratul Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Pentru mai multe informații, consultați [configurarea bazei de date |configuration]. - - -Interogări .[#toc-queries] -========================== - -Pentru a interoga baza de date, utilizați metoda `query()` care returnează [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // returnează numărul de rânduri dacă este cunoscut -``` - -.[note] -Pe `ResultSet` este posibilă iterarea doar o singură dată, dacă trebuie să iterăm de mai multe ori, este necesar să convertim rezultatul în matrice prin metoda `fetchAll()`. - -Puteți adăuga cu ușurință parametri la interogare, rețineți semnul de întrebare: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids este o matrice -``` -
- -ATENȚIE, nu concatenați niciodată șiruri de caractere pentru a evita [vulnerabilitatea de injecție SQL |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -În caz de eșec, `query()` aruncă fie `Nette\Database\DriverException`, fie unul dintre descendenții săi: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - încălcarea oricărei constrângeri. -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - cheie străină invalidă -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - încălcare a condiției NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - conflict cu un indice unic - -În plus față de `query()`, există și alte metode utile: - -```php -// returnează matricea asociativă id => nume -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// returnează toate rândurile sub formă de matrice -$rows = $database->fetchAll('SELECT * FROM users'); - -// returnează un singur rând -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// returnează un singur câmp -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -În caz de eșec, toate aceste metode aruncă `Nette\Database\DriverException.` - - -Inserare, actualizare și ștergere .[#toc-insert-update-delete] -============================================================== - -Parametrul pe care îl introducem în interogarea SQL poate fi, de asemenea, matricea (caz în care este posibil să se omită declarația wildcard `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // aici poate fi omis semnul întrebării - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // returnează creșterea automată a rândului inserat - -$id = $database->getInsertId($sequence); // sau valoarea secvenței -``` - -Inserare multiplă: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -De asemenea, putem trece fișiere, obiecte DateTime sau [enumerări |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // sau $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserează conținutul fișierului - 'status' => State::New, // enum State -]); -``` - -Actualizarea rândurilor: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // returnează numărul de rânduri afectate -``` - -Pentru UPDATE, putem folosi operatorii `+=` și `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // notă += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Ștergere: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // returnează numărul de rânduri afectate -``` - - -Interogări avansate .[#toc-advanced-queries] -============================================ - -Inserare sau actualizare, dacă există deja: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Rețineți că Nette Database recunoaște contextul SQL în care este introdus parametrul de matrice și construiește codul SQL în consecință. Astfel, din primul array generează `(id, name, year) VALUES (123, 'Jim', 1978)`, în timp ce al doilea se convertește în `name = 'Jim', year = 1978`. - -De asemenea, putem descrie sortarea folosind array, în care cheile sunt nume de coloane, iar valorile sunt booleane care determină dacă se sortează în ordine crescătoare: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascendent - 'name' => false, // descrescător -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -În cazul în care detectarea nu a funcționat, puteți specifica forma ansamblului cu ajutorul unui wildcard `?` urmat de un indiciu. Aceste indicii sunt acceptate: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = valoare1, key2 = valoare2, ... -| ?and | key1 = valoare1 AND key2 = valoare2 ... -| ?or | key1 = valoare1 OR key2 = valoare2 ... -| ?order | key1 ASC, key2 DESC - -Clauza WHERE utilizează operatorul `?and`, astfel încât condițiile sunt legate prin `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Care poate fi ușor de schimbat în `OR` prin utilizarea caracterului wildcard `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Putem folosi operatori în condiții: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Și, de asemenea, enumerări: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumerare + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -De asemenea, putem include o bucată de cod SQL personalizat folosind așa-numitul literal SQL: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternativ: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -Literalul SQL poate avea, de asemenea, parametrii săi: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Datorită cărora putem crea combinații interesante: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Denumire variabilă .[#toc-variable-name] -======================================== - -Există un wildcard `?name` pe care îl utilizați dacă numele tabelului sau al coloanei este o variabilă. (Atenție, nu permiteți utilizatorului să manipuleze conținutul unei astfel de variabile): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Tranzacții .[#toc-transactions] -=============================== - -Există trei metode de tratare a tranzacțiilor: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -O modalitate elegantă este oferită de metoda `transaction()`. Se trece callback-ul care este executat în cadrul tranzacției. Dacă în timpul execuției se aruncă o excepție, tranzacția este abandonată, iar dacă totul merge bine, tranzacția este validată. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -După cum puteți vedea, metoda `transaction()` returnează valoarea de returnare a callback-ului. - -Tranzacția() poate fi, de asemenea, imbricata, ceea ce simplifică implementarea de depozite independente. +{{redirect: guide}} diff --git a/database/ru/core.texy b/database/ru/core.texy index 50d46cab53..096e5311b0 100644 --- a/database/ru/core.texy +++ b/database/ru/core.texy @@ -1,350 +1 @@ -Database Core -************* - -.[perex] -Nette Database Core является уровнем абстракции базы данных и обеспечивает основную функциональность. - - -Установка .[#toc-installation] -============================== - -Загрузите и установите пакет с помощью [Composer|best-practices:composer]: - -```shell -composer require nette/database -``` - - -Подключение и настройка .[#toc-connection-and-configuration] -============================================================ - -Чтобы подключиться к базе данных, просто создайте экземпляр класса [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Параметр `$dsn` (имя источника данных) — [такой же, как используется в PDO |https://www.php.net/manual/ru/pdo.construct.php#refsect1-pdo.construct-parameters], например `host=127.0.0.1;dbname=test`. В случае неудачи выбрасывается исключение `Nette\Database\ConnectionException`. - -Однако, более сложный способ предлагает [конфигурация приложения |configuration]. Мы добавим раздел `database`, и он создаст необходимые объекты и панель `Database` в панели отладки [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Объект соединения, который мы [получаем как сервис от DI-контейнера |dependency-injection:passing-dependencies], например: - -```php -class Model -{ - // передаем Nette\Database\Explorer для работы с уровнем Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Для получения дополнительной информации смотрите [конфигурацию базы данных|configuration]. - - -Запросы .[#toc-queries] -======================= - -Для запроса к базе данных используйте метод `query()`, который возвращает [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // возвращает количество строк, если оно известно -``` - -.[note] -Над `ResultSet` можно выполнить итерацию только один раз, если нам нужно выполнить итерацию несколько раз, необходимо преобразовать результат в массив с помощью метода `fetchAll()`. - -Вы можете легко добавить параметры в запрос, обратите внимание на знак вопроса: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids - массив -``` - -
-ВНИМАНИЕ, никогда не объединяйте строки во избежание [уязвимости через SQL-инъекции |https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // НЕПРАВИЛЬНО!!! -\-- -
- -В случае неудачи `query()` выбрасывает либо исключение `Nette\Database\DriverException`, либо одно из его дочерних исключений: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - нарушение любого из условий -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - недопустимый внешний ключ -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - нарушение условия NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - конфликт уникального индекса - -Помимо `query()`, существуют и другие полезные методы: - -```php -// возвращает ассоциативный массив id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// возвращает все строки в виде массива -$rows = $database->fetchAll('SELECT * FROM users'); - -// возвращает одну строку -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// возвращает одно поле -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -В случае неудачи все эти методы выбрасывают исключение `Nette\Database\DriverException`. - - -Вставка, обновление и удаление .[#toc-insert-update-delete] -=========================================================== - -Параметр, который мы вставляем в SQL-запрос, также может быть массивом (в этом случае можно пропустить подстановочный знак `?`), что может быть полезно для оператора `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // здесь может быть опущен знак вопроса - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // возвращает автоинкремент вставленной строки - -$id = $database->getInsertId($sequence); // или значение последовательности -``` - -Вставка нескольких значений: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Мы также можем передавать файлы, объекты DateTime или [перечисления |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // или $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // вставляет содержимое файла - 'status' => State::New, // enum State -]); -``` - -Обновление строк: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // возвращает количество затронутых строк -``` - -Для UPDATE мы можем использовать операторы `+=` и `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Удаление: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // возвращает количество затронутых строк -``` - - -Продвинутые запросы .[#toc-advanced-queries] -============================================ - -Вставка или обновление, если запись уже существует: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Обратите внимание, что Nette Database распознает SQL-контекст, в который вставлен параметр массива, и строит SQL-код соответствующим образом. Так, из первого массива он генерирует `(id, name, year) VALUES (123, 'Jim', 1978)`, а второй преобразует в `name = 'Jim', year = 1978`. - -Мы также можем описать сортировку с помощью массива, в котором ключами являются имена столбцов, а значениями — значения типа boolean, определяющие, следует ли сортировать в порядке возрастания: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // ascending - 'name' => false, // descending -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Если обнаружение не сработало, вы можете указать форму сборки с помощью подстановочного знака `?`, за которым следует подсказка. Поддерживаются следующие подсказки: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -В предложении WHERE используется оператор `?and`, поэтому условия связаны `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Который можно легко изменить на `OR`, используя подстановочный знак `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Мы можем использовать операторы в условиях: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -А также перечисления: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // перечисление + оператор NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Мы также можем включить часть пользовательского SQL-кода, используя так называемый SQL-литерал: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -В качестве альтернативы: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL-литерал также может иметь свои параметры: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Благодаря этому мы можем создавать интересные комбинации: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Имя переменной .[#toc-variable-name] -==================================== - -Существует подстановочный знак `?name', который используется, если имя таблицы или столбца является переменной. (Осторожно, не позволяйте пользователю манипулировать содержимым такой переменной): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Транзакции .[#toc-transactions] -=============================== - -Существует три метода работы с транзакциями: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Элегантный способ предлагает метод `transaction()`. Вы передаете обратный вызов, который выполняется в транзакции. Если во время выполнения возникает исключение, транзакция сбрасывается, если всё идет хорошо, транзакция фиксируется. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Как видите, метод `transaction()` возвращает возвращаемое значение обратного вызова. - -Транзакция() также может быть вложенной, что упрощает реализацию независимых хранилищ. +{{redirect: guide}} diff --git a/database/sl/core.texy b/database/sl/core.texy index 1f65ebf455..096e5311b0 100644 --- a/database/sl/core.texy +++ b/database/sl/core.texy @@ -1,350 +1 @@ -Jedro zbirke podatkov -********************* - -.[perex] -Nette Database Core je abstraktni sloj podatkovne zbirke in zagotavlja osnovne funkcionalnosti. - - -Namestitev .[#toc-installation] -=============================== - -Prenesite in namestite paket s [programom Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Priključitev in konfiguracija .[#toc-connection-and-configuration] -================================================================== - -Če se želite povezati s podatkovno zbirko, preprosto ustvarite primerek razreda [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Parameter `$dsn` (ime vira podatkov) je [enak tistemu, ki ga uporablja PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], npr. `host=127.0.0.1;dbname=test`. V primeru neuspeha se vrže `Nette\Database\ConnectionException`. - -Vendar pa bolj prefinjen način ponuja [konfiguracija aplikacije |configuration]. Dodamo razdelek `database` in ta ustvari zahtevane predmete in ploščo s podatkovno bazo v vrstici [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Objekt povezave [prejmemo kot storitev iz vsebnika DI |dependency-injection:passing-dependencies], na primer: - -```php -class Model -{ - // predajte Nette\Database\Explorer za delo s slojem Raziskovalec podatkovne baze - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Za več informacij glejte [Konfiguracija podatkovne zbirke |configuration]. - - -Poizvedbe .[#toc-queries] -========================= - -Za poizvedovanje po zbirki podatkov uporabite metodo `query()`, ki vrne [nabor rezultatov (ResultSet) |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // vrne število vrstic, če je znano -``` - -.[note] -Nad `ResultSet` je mogoče iterirati samo enkrat, če pa moramo iterirati večkrat, je treba rezultat pretvoriti v polje prek metode `fetchAll()`. - -Poizvedbi lahko preprosto dodate parametre, pri čemer upoštevajte vprašalni znak: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids je polje -``` -
- -Opozorilo, nikoli ne združujte nizov, da se izognete [ranljivosti vbrizgavanja SQL |https://en.wikipedia.org/wiki/SQL_injection]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -V primeru neuspeha `query()` vrže `Nette\Database\DriverException` ali enega od njegovih potomcev: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - kršitev katere koli omejitve -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - neveljaven tuj ključ -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - kršitev pogoja NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - konflikt edinstvenega indeksa - -Poleg `query()` so na voljo še druge uporabne metode: - -```php -// vrne asociativno polje id => ime -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// vrne vse vrstice kot polje -$rows = $database->fetchAll('SELECT * FROM users'); - -// vrne posamezno vrstico -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// vrne posamezno polje -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -V primeru neuspeha vse te metode zavržejo `Nette\Database\DriverException.` - - -Vstavljanje, posodabljanje in brisanje .[#toc-insert-update-delete] -=================================================================== - -Parameter, ki ga vstavimo v poizvedbo SQL, je lahko tudi polje (v tem primeru je mogoče preskočiti nadomestno izjavo `?`), which may be useful for the `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // tukaj se lahko izpusti vprašalno znamenje - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // vrne samodejno povečanje vstavljene vrstice - -$id = $database->getInsertId($sequence); // ali vrednost zaporedja -``` - -Večkratno vstavljanje: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Vstavljamo lahko tudi datoteke, objekte DateTime ali [naštevanja |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // ali $databaza::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // vstavi vsebino datoteke - 'status' => State::New, // enum State -]); -``` - -Posodabljanje vrstic: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // vrne število prizadetih vrstic -``` - -Za UPDATE lahko uporabimo operatorja `+=` in `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // Opomba += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Brisanje: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // vrne število prizadetih vrstic -``` - - -Napredne poizvedbe .[#toc-advanced-queries] -=========================================== - -Vstavljanje ali posodabljanje, če že obstaja: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Upoštevajte, da podatkovna baza Nette prepozna kontekst SQL, v katerem je vstavljen parameter polja, in v skladu s tem sestavi kodo SQL. Tako iz prvega polja ustvari `(id, name, year) VALUES (123, 'Jim', 1978)`, medtem ko drugo pretvori v `name = 'Jim', year = 1978`. - -Sortiranje lahko opišemo tudi z uporabo polja, pri čemer so ključi imena stolpcev, vrednosti pa logične vrednosti, ki določajo, ali naj se sortira v naraščajočem vrstnem redu: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // naraščajoče - 'name' => false, // padajoče -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Če zaznavanje ni delovalo, lahko določite obliko sklopa z nadomestnim znakom `?`, ki mu sledi namig. Ti namigi so podprti: - -| (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -V stavku WHERE je uporabljen operator `?and`, zato so pogoji povezani s `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -To lahko z uporabo nadomestnega znaka `?or` preprosto spremenite v `OR`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -V pogojih lahko uporabljamo operatorje: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -in tudi naštevanja: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // naštevanje + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Vključimo lahko tudi del kode SQL po meri z uporabo tako imenovanega literala SQL: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Druga možnost: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literal ima lahko tudi svoje parametre: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Zaradi tega lahko ustvarimo zanimive kombinacije: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Ime spremenljivke .[#toc-variable-name] -======================================= - -Obstaja nadomestni znak `?name`, ki ga uporabite, če je ime tabele ali stolpca spremenljivka. (Pazite, da uporabniku ne dovolite, da bi manipuliral z vsebino take spremenljivke): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Transakcije .[#toc-transactions] -================================ - -Obstajajo trije načini obravnavanja transakcij: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Eleganten način ponuja metoda `transaction()`. Predate povratni klic, ki se izvede v transakciji. Če se med izvajanjem vrže izjema, se transakcija opusti, če je vse v redu, se transakcija izvede. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Kot lahko vidite, metoda `transaction()` vrne povratno vrednost povratnega klica. - -Metoda transaction() je lahko tudi vgnezdena, kar poenostavi izvajanje neodvisnih skladišč. +{{redirect: guide}} diff --git a/database/tr/core.texy b/database/tr/core.texy index 5532d29906..096e5311b0 100644 --- a/database/tr/core.texy +++ b/database/tr/core.texy @@ -1,350 +1 @@ -Veritabanı Çekirdeği -******************** - -.[perex] -Nette Database Core, veritabanı soyutlama katmanıdır ve temel işlevsellik sağlar. - - -Kurulum .[#toc-installation] -============================ - -[Composer'ı |best-practices:composer] kullanarak paketi indirin ve yükleyin: - -```shell -composer require nette/database -``` - - -Bağlantı ve Yapılandırma .[#toc-connection-and-configuration] -============================================================= - -Veritabanına bağlanmak için [api:Nette\Database\Connection] sınıfının bir örneğini oluşturmanız yeterlidir: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -`$dsn` (veri kaynağı adı) parametresi [PDO tarafından kullanılanla aynıdır |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], örneğin `host=127.0.0.1;dbname=test`. Başarısızlık durumunda `Nette\Database\ConnectionException` atar. - -Ancak, daha sofistike bir yol [uygulama yapılandırması |configuration] sunar. Bir `database` bölümü ekleyeceğiz ve [Tracy |tracy:] çubuğunda gerekli nesneleri ve bir veritabanı paneli oluşturacak. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Örneğin [bir DI konteynerinden servis olarak aldığımız |dependency-injection:passing-dependencies] bağlantı nesnesi: - -```php -class Model -{ - // Veritabanı Gezgini katmanı ile çalışmak için Nette\Database\Explorer'ı geçirin - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Daha fazla bilgi için, bkz. [veritabanı yapılandırması |configuration]. - - -Sorgular .[#toc-queries] -======================== - -Veritabanını sorgulamak için [ResultSet |api:Nette\Database\ResultSet] döndüren `query()` yöntemini kullanın. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // biliniyorsa satır sayısını döndürür -``` - -.[note] -`ResultSet` üzerinden sadece bir kez yineleme yapmak mümkündür, birden fazla kez yineleme yapmamız gerekirse `fetchAll()` metodu ile sonucu diziye dönüştürmek gerekir. - -Sorguya kolayca parametre ekleyebilirsiniz, soru işaretine dikkat edin: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids bir dizidir -``` -
- -UYARI, [SQL enjeksiyonu açığından |https://en.wikipedia.org/wiki/SQL_injection] kaçınmak için asla dizeleri birleştirmeyin! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!! -\-- -
- -Başarısızlık durumunda `query()`, `Nette\Database\DriverException` ya da onun soyundan gelenlerden birini fırlatır: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - herhangi bir kısıtlamanın ihlali -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - geçersiz yabancı anahtar -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - NOT NULL koşulunun ihlali -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - benzersiz dizin çakışması - -`query()` adresine ek olarak, başka faydalı yöntemler de vardır: - -```php -// id => name ilişkisel dizisini döndürür -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// tüm satırları dizi olarak döndürür -$rows = $database->fetchAll('SELECT * FROM users'); - -// tek satır döndürür -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// tek alan döndür -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -Başarısızlık durumunda, tüm bu yöntemler `Nette\Database\DriverException.` - - -Ekle, Güncelle ve Sil .[#toc-insert-update-delete] -================================================== - -SQL sorgusuna eklediğimiz parametre dizi de olabilir (bu durumda joker karakter `?`), which may be useful for the `INSERT` ifadesini atlamak mümkündür: - -```php -$database->query('INSERT INTO users ?', [ // burada soru işareti atlanabilir - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // eklenen satırın otomatik artışını döndürür - -id = $database->getInsertId($sequence); // veya sıra değeri -``` - -Çoklu ekleme: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Ayrıca dosyaları, DateTime nesnelerini veya [numaralandırmaları |https://www.php.net/enumerations] da aktarabiliriz: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // or $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // inserts file contents - 'status' => State::New, // enum State -]); -``` - -Satırlar güncelleniyor: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // etkilenen satır sayısını döndürür -``` - -UPDATE için `+=` ve `-=` operatörlerini kullanabiliriz: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Siliniyor: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // etkilenen satır sayısını döndürür -``` - - -Gelişmiş Sorgular .[#toc-advanced-queries] -========================================== - -Zaten mevcutsa ekleyin veya güncelleyin: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Nette Database'in dizi parametresinin eklendiği SQL bağlamını tanıdığını ve SQL kodunu buna göre oluşturduğunu unutmayın. Böylece, ilk diziden `(id, name, year) VALUES (123, 'Jim', 1978)` üretirken, ikincisini `name = 'Jim', year = 1978`'a dönüştürür. - -Sıralamayı dizi kullanarak da tanımlayabiliriz, anahtarlar sütun adlarıdır ve değerler artan sırada sıralanıp sıralanmayacağını belirleyen boolean'dır: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // artan - 'name' => false, // azalan -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Algılama işe yaramadıysa, derlemenin biçimini bir joker karakter `?` ve ardından bir ipucu ile belirtebilirsiniz. Bu ipuçları desteklenir: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | anahtar1 = değer1, anahtar2 = değer2, ... -| ?ve | anahtar1 = değer1 VE anahtar2 = değer2 ... -| ?or | key1 = value1 OR key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -WHERE cümlesi `?and` operatörünü kullanır, böylece koşullar `AND` ile birbirine bağlanır: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Bu, `?or` joker karakteri kullanılarak kolayca `OR` olarak değiştirilebilir: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Operatörleri koşullar içinde kullanabiliriz: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -Ve ayrıca numaralandırmalar: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // enumeration + operator NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Ayrıca SQL literal olarak adlandırılan özel bir SQL kodu parçası da ekleyebiliriz: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Alternatif olarak: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL literalinin parametreleri de olabilir: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Bu sayede ilginç kombinasyonlar yaratabiliriz: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Değişken Adı .[#toc-variable-name] -================================== - -Tablo adı veya sütun adı bir değişken ise kullanabileceğiniz bir `?name` joker karakteri vardır. (Dikkat edin, kullanıcının böyle bir değişkenin içeriğini değiştirmesine izin vermeyin): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -İşlemler .[#toc-transactions] -============================= - -İşlemlerle ilgilenmek için üç yöntem vardır: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -`transaction()` yöntemi zarif bir yol sunar. Transaction içinde çalıştırılan geri çağırmayı iletirsiniz. Yürütme sırasında bir istisna atılırsa, işlem düşürülür, her şey yolunda giderse işlem işlenir. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Gördüğünüz gibi, `transaction()` yöntemi geri aramanın dönüş değerini döndürür. - -transaction() da iç içe geçebilir, bu da bağımsız depoların uygulanmasını basitleştirir. +{{redirect: guide}} diff --git a/database/uk/core.texy b/database/uk/core.texy index fb2022e9f7..096e5311b0 100644 --- a/database/uk/core.texy +++ b/database/uk/core.texy @@ -1,350 +1 @@ -Ядро бази даних -*************** - -.[perex] -Nette Database Core є рівнем абстракції бази даних і забезпечує основну функціональність. - - -Встановлення .[#toc-installation] -================================= - -Завантажте та встановіть пакет за допомогою [Composer |best-practices:composer]: - -```shell -composer require nette/database -``` - - -Підключення та налаштування .[#toc-connection-and-configuration] -================================================================ - -Щоб підключитися до бази даних, просто створіть екземпляр класу [api:Nette\Database\Connection]: - -```php -$database = new Nette\Database\Connection($dsn, $user, $password); -``` - -Параметр `$dsn` (ім'я джерела даних) - [такий самий, як використовується в PDO |https://www.php.net/manual/ru/pdo.construct.php#refsect1-pdo.construct-parameters], наприклад `host=127.0.0.1;dbname=test`. У разі невдачі викидається виняток `Nette\Database\ConnectionException`. - -Однак, більш складний спосіб пропонує [конфігурація програми |configuration]. Ми додамо розділ `database`, і він створить необхідні об'єкти та панель `Database` в панелі налагодження [Tracy |tracy:]. - -```neon -database: - dsn: 'mysql:host=127.0.0.1;dbname=test' - user: root - password: password -``` - -Об'єкт з'єднання, який ми [отримуємо як сервіс від DI-контейнера |dependency-injection:passing-dependencies], наприклад: - -```php -class Model -{ - // передаємо Nette\Database\Explorer для роботи з рівнем Database Explorer - public function __construct( - private Nette\Database\Connection $database, - ) { - } -} -``` - -Для отримання додаткової інформації дивіться [конфігурацію бази даних |configuration]. - - -Запити .[#toc-queries] -====================== - -Для запиту до бази даних використовуйте метод `query()`, який повертає [ResultSet |api:Nette\Database\ResultSet]. - -```php -$result = $database->query('SELECT * FROM users'); - -foreach ($result as $row) { - echo $row->id; - echo $row->name; -} - -echo $result->getRowCount(); // повертає кількість рядків, якщо вона відома -``` - -.[note] -Над `ResultSet` можна виконати ітерацію тільки один раз, якщо нам потрібно виконати ітерацію кілька разів, необхідно перетворити результат у масив за допомогою методу `fetchAll()`. - -Ви можете легко додати параметри в запит, зверніть увагу на знак питання: - -```php -$database->query('SELECT * FROM users WHERE name = ?', $name); - -$database->query('SELECT * FROM users WHERE name = ? AND active = ?', $name, $active); - -$database->query('SELECT * FROM users WHERE id IN (?)', $ids); // $ids - масив -``` -
- -УВАГА, ніколи не об'єднуйте рядки, щоб уникнути [уразливості через SQL-ін'єкції |https://ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D0%B5_SQL-%D0%BA%D0%BE%D0%B4%D0%B0]! -/-- -$db->query('SELECT * FROM users WHERE name = ' . $name); // НЕПРАВИЛЬНО!!! -\-- -
- -У разі невдачі `query()` викидає або виняток `Nette\Database\DriverException`, або одне з його дочірніх винятків: - -- [ConstraintViolationException |api:Nette\Database\ConstraintViolationException] - порушення будь-якої з умов -- [ForeignKeyConstraintViolationException |api:Nette\Database\ForeignKeyConstraintViolationException] - неприпустимий зовнішній ключ -- [NotNullConstraintViolationException |api:Nette\Database\NotNullConstraintViolationException] - порушення умови NOT NULL -- [UniqueConstraintViolationException |api:Nette\Database\UniqueConstraintViolationException] - конфлікт унікального індексу - -Крім `query()`, існують і інші корисні методи: - -```php -// повертає асоціативний масив id => name -$pairs = $database->fetchPairs('SELECT id, name FROM users'); - -// повертає всі рядки у вигляді масиву -$rows = $database->fetchAll('SELECT * FROM users'); - -// повертає один рядок -$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id); - -// повертає одне поле -$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id); -``` - -У разі невдачі всі ці методи викидають виняток `Nette\Database\DriverException`. - - -Вставка, оновлення та видалення .[#toc-insert-update-delete] -============================================================ - -Параметр, який ми вставляємо в SQL-запит, також може бути масивом (у цьому випадку можна пропустити знак підстановки `?`), что может быть полезно для оператора `INSERT`: - -```php -$database->query('INSERT INTO users ?', [ // тут може бути опущений знак питання - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978) - -$id = $database->getInsertId(); // повертає автоінкремент вставленого рядка - -$id = $database->getInsertId($sequence); // або значення послідовності -``` - -Вставка декількох значень: - -```php -$database->query('INSERT INTO users', [ - [ - 'name' => 'Jim', - 'year' => 1978, - ], [ - 'name' => 'Jack', - 'year' => 1987, - ], -]); -// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987) -``` - -Ми також можемо передавати файли, об'єкти DateTime або [перерахування |https://www.php.net/enumerations]: - -```php -$database->query('INSERT INTO users', [ - 'name' => $name, - 'created' => new DateTime, // або $database::literal('NOW()') - 'avatar' => fopen('image.gif', 'r'), // вставляє вміст файлу - 'status' => State::New, // enum State -]); -``` - -Оновлення рядків: - -```php -$result = $database->query('UPDATE users SET', [ - 'name' => $name, - 'year' => $year, -], 'WHERE id = ?', $id); -// UPDATE users SET `name` = 'Jim', `year` = 1978 WHERE id = 123 - -echo $result->getRowCount(); // повертає кількість порушених рядків -``` - -Для UPDATE ми можемо використовувати оператори `+=` і `-=`: - -```php -$database->query('UPDATE users SET', [ - 'age+=' => 1, // note += -], 'WHERE id = ?', $id); -// UPDATE users SET `age` = `age` + 1 -``` - -Видалення: - -```php -$result = $database->query('DELETE FROM users WHERE id = ?', $id); -echo $result->getRowCount(); // повертає кількість порушених рядків -``` - - -Просунуті запити .[#toc-advanced-queries] -========================================= - -Вставка або оновлення, якщо запис уже існує: - -```php -$database->query('INSERT INTO users', [ - 'id' => $id, - 'name' => $name, - 'year' => $year, -], 'ON DUPLICATE KEY UPDATE', [ - 'name' => $name, - 'year' => $year, -]); -// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978) -// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978 -``` - -Зверніть увагу, що Nette Database розпізнає SQL-контекст, у який вставлено параметр масиву, і будує SQL-код відповідним чином. Так, з першого масиву він генерує `(id, name, year) VALUES (123, 'Jim', 1978)`, а другий перетворює на `name = 'Jim', year = 1978`. - -Ми також можемо описати сортування за допомогою масиву, в якому ключами є імена стовпців, а значеннями - значення типу boolean, що визначають, чи слід сортувати в порядку зростання: - -```php -$database->query('SELECT id FROM author ORDER BY', [ - 'id' => true, // за зростанням - 'name' => false, // за спаданням -]); -// SELECT id FROM author ORDER BY `id`, `name` DESC -``` - -Якщо виявлення не спрацювало, ви можете вказати форму збірки за допомогою знака підстановки `?`, за яким слідує підказка. Підтримуються такі підказки: - -| ?values | (key1, key2, ...) VALUES (value1, value2, ...) -| ?set | key1 = value1, key2 = value2, ... -| ?and | key1 = value1 AND key2 = value2 ... -| ?or | key1 = value1 АБО key2 = value2 ... -| ?order | key1 ASC, key2 DESC - -У реченні WHERE використовується оператор `?and`, тому умови пов'язані `AND`: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978 -``` - -Який можна легко змінити на `OR`, використовуючи знак підстановки `?or`: - -```php -$result = $database->query('SELECT * FROM users WHERE ?or', [ - 'name' => $name, - 'year' => $year, -]); -// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978 -``` - -Ми можемо використовувати оператори в умовах: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name <>' => $name, - 'year >' => $year, -]); -// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978 -``` - -А також перерахування: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => ['Jim', 'Jack'], - 'role NOT IN' => ['admin', 'owner'], // перерахування + оператор NOT IN -]); -// SELECT * FROM users WHERE -// `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner') -``` - -Ми також можемо включити частину користувацького SQL-коду, використовуючи так званий SQL-літерал: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - 'year >' => $database::literal('YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR()) -``` - -Як альтернативу: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > YEAR()'), -]); -// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR()) -``` - -SQL-літерал також може мати свої параметри: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('year > ? AND year < ?', $min, $max), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (year > 1978 AND year < 2017) -``` - -Завдяки цьому ми можемо створювати цікаві комбінації: - -```php -$result = $database->query('SELECT * FROM users WHERE', [ - 'name' => $name, - $database::literal('?or', [ - 'active' => true, - 'role' => $role, - ]), -]); -// SELECT * FROM users WHERE `name` = 'Jim' AND (`active` = 1 OR `role` = 'admin') -``` - - -Ім'я змінної .[#toc-variable-name] -================================== - -Існує знак підстановки `?name', який використовується, якщо ім'я таблиці або стовпця є змінною. (Обережно, не дозволяйте користувачеві маніпулювати вмістом такої змінної): - -```php -$table = 'blog.users'; -$column = 'name'; -$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name); -// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim' -``` - - -Транзакції .[#toc-transactions] -=============================== - -Існує три методи роботи з транзакціями: - -```php -$database->beginTransaction(); - -$database->commit(); - -$database->rollback(); -``` - -Елегантний спосіб пропонує метод `transaction()`. Ви передаєте зворотний виклик, який виконується в транзакції. Якщо під час виконання виникає виняток, транзакція скидається, якщо все йде добре, транзакція фіксується. - -```php -$id = $database->transaction(function ($database) { - $database->query('DELETE FROM ...'); - $database->query('INSERT INTO ...'); - // ... - return $database->getInsertId(); -}); -``` - -Як бачите, метод `transaction()` повертає значення зворотного виклику, що повертається. - -Транзакція() також може бути вкладеною, що спрощує реалізацію незалежних сховищ. +{{redirect: guide}}