Nette Documentation Preview

syntax
Nette Database
**************

.[perex]
Nette Database to wydajna i elegancka warstwa bazodanowa dla PHP z naciskiem na prostotę i inteligentne funkcje. Oferuje dwa sposoby pracy z bazą danych - [Explorer |Explorer] dla szybkiego rozwoju aplikacji, lub [Dostęp SQL |SQL way] dla bezpośredniej pracy z zapytaniami.

<div class="grid gap-3">
<div>


[Dostęp SQL |SQL way]
=====================
- Bezpieczne sparametryzowane zapytania
- Dokładna kontrola nad formą zapytań SQL
- Gdy piszesz złożone zapytania z zaawansowanymi funkcjami
- Optymalizujesz wydajność za pomocą specyficznych funkcji SQL

</div>

<div>


[Explorer |Explorer]
====================
- Rozwijasz szybko bez pisania SQL
- Intuicyjna praca z relacjami między tabelami
- Docenisz automatyczną optymalizację zapytań
- Odpowiednie do szybkiej i wygodnej pracy z bazą danych

</div>

</div>


Instalacja
==========

Bibliotekę można pobrać i zainstalować za pomocą narzędzia [Composer|best-practices:composer]:

```shell
composer require nette/database
```


Obsługiwane bazy danych
=======================

Nette Database obsługuje następujące bazy danych:

|* Serwer bazy danych |* Nazwa DSN  |* Wsparcie w Explorer
|---------------------|-------------|-----------------------
| MySQL (>= 5.1)      | mysql       | TAK
| PostgreSQL (>= 9.0) | pgsql       | TAK
| Sqlite 3 (>= 3.8)   | sqlite      | TAK
| Oracle              | oci         | -
| MS SQL (PDO_SQLSRV) | sqlsrv      | TAK
| MS SQL (PDO_DBLIB)  | mssql       | -
| ODBC                | odbc        | -


Dwa podejścia do bazy danych
============================

Nette Database daje Ci wybór: możesz pisać zapytania SQL bezpośrednio (dostęp SQL) lub pozwolić na ich automatyczne generowanie (Explorer). Zobaczmy, jak oba podejścia rozwiązują te same zadania:

[Dostęp SQL|sql way] - Zapytania SQL

```php
// wstawienie rekordu
$database->query('INSERT INTO books', [
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// pobranie rekordów: autorzy książek
$result = $database->query('
	SELECT authors.*, COUNT(books.id) AS books_count
	FROM authors
	LEFT JOIN books ON authors.id = books.author_id
	WHERE authors.active = 1
	GROUP BY authors.id
');

// wypisanie (nie jest optymalne, generuje N dodatkowych zapytań)
foreach ($result as $author) {
	$books = $database->query('
		SELECT * FROM books
		WHERE author_id = ?
		ORDER BY published_at DESC
	', $author->id);

	echo "Autor $author->name napisał $author->books_count książek:\n";

	foreach ($books as $book) {
		echo "- $book->title\n";
	}
}
```

[Podejście Explorer|explorer] - automatyczne generowanie SQL

```php
// wstawienie rekordu
$database->table('books')->insert([
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// pobranie rekordów: autorzy książek
$authors = $database->table('authors')
	->where('active', 1);

// wypisanie (automatycznie generuje tylko 2 zoptymalizowane zapytania)
foreach ($authors as $author) {
	$books = $author->related('books')
		->order('published_at DESC');

	echo "Autor $author->name napisał {$books->count()} książek:\n";

	foreach ($books as $book) {
		echo "- $book->title\n";
	}
}
```

Podejście Explorer generuje i optymalizuje zapytania SQL automatycznie. W podanym przykładzie podejście SQL wygeneruje N+1 zapytań (jedno dla autorów, a następnie jedno dla książek każdego autora), podczas gdy Explorer automatycznie optymalizuje zapytania i wykonuje tylko dwa - jedno dla autorów i jedno dla wszystkich ich książek.

Oba podejścia można dowolnie łączyć w aplikacji w zależności od potrzeb.


Połączenie i konfiguracja
=========================

Aby połączyć się z bazą danych, wystarczy utworzyć instancję klasy [api:Nette\Database\Connection]:

```php
$database = new Nette\Database\Connection($dsn, $user, $password);
```

Parametr `$dsn` (data source name) jest taki sam, [jakiego używa 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`.

Jednak wygodniejszy sposób oferuje [konfiguracja aplikacji |configuration], gdzie wystarczy dodać sekcję `database`, a zostaną utworzone potrzebne obiekty oraz panel bazy danych w pasku [Tracy |tracy:].

```neon
database:
	dsn: 'mysql:host=127.0.0.1;dbname=test'
	user: root
	password: password
```

Następnie obiekt połączenia [uzyskujemy jako usługę z kontenera DI |dependency-injection:passing-dependencies], np.:

```php
class Model
{
	public function __construct(
		// lub Nette\Database\Explorer
		private Nette\Database\Connection $database,
	) {
	}
}
```

Więcej informacji o [konfiguracji bazy danych|configuration].


Ręczne tworzenie Explorera
--------------------------

Jeśli nie używasz kontenera Nette DI, możesz utworzyć instancję `Nette\Database\Explorer` ręcznie:

```php
// połączenie z bazą danych
$connection = new Nette\Database\Connection('mysql:host=127.0.0.1;dbname=mydatabase', 'user', 'password');
// magazyn dla cache, implementuje Nette\Caching\Storage, np.:
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp/dir');
// zajmuje się refleksją struktury bazy danych
$structure = new Nette\Database\Structure($connection, $storage);
// definiuje reguły mapowania nazw tabel, kolumn i kluczy obcych
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
$explorer = new Nette\Database\Explorer($connection, $structure, $conventions, $storage);
```


Zarządzanie połączeniem
=======================

Podczas tworzenia obiektu `Connection` połączenie jest nawiązywane automatycznie. Jeśli chcesz odłożyć połączenie, użyj trybu lazy - włączysz go w [konfiguracji|configuration] ustawiając `lazy`, lub w ten sposób:

```php
$database = new Nette\Database\Connection($dsn, $user, $password, ['lazy' => true]);
```

Do zarządzania połączeniem użyj metod `connect()`, `disconnect()` i `reconnect()`.
- `connect()` tworzy połączenie, jeśli jeszcze nie istnieje, przy czym może rzucić wyjątek `Nette\Database\ConnectionException`.
- `disconnect()` rozłącza bieżące połączenie z bazą danych.
- `reconnect()` wykonuje rozłączenie i ponowne połączenie z bazą danych. Ta metoda również może rzucić wyjątek `Nette\Database\ConnectionException`.

Ponadto możesz śledzić zdarzenia związane z połączeniem za pomocą zdarzenia `onConnect`, które jest tablicą callbacków wywoływanych po nawiązaniu połączenia z bazą danych.

```php
// wykonuje się po połączeniu z bazą danych
$database->onConnect[] = function($database) {
	echo "Połączono z bazą danych";
};
```


Pasek Debugowania Tracy
=======================

Jeśli używasz [Tracy |tracy:], panel Database w pasku Debugowania aktywuje się automatycznie, wyświetlając wszystkie wykonane zapytania, ich parametry, czas wykonania oraz miejsce w kodzie, gdzie zostały wywołane.

[* db-panel.webp *]

Nette Database

Nette Database to wydajna i elegancka warstwa bazodanowa dla PHP z naciskiem na prostotę i inteligentne funkcje. Oferuje dwa sposoby pracy z bazą danych – Explorer dla szybkiego rozwoju aplikacji, lub Dostęp SQL dla bezpośredniej pracy z zapytaniami.

Dostęp SQL

  • Bezpieczne sparametryzowane zapytania
  • Dokładna kontrola nad formą zapytań SQL
  • Gdy piszesz złożone zapytania z zaawansowanymi funkcjami
  • Optymalizujesz wydajność za pomocą specyficznych funkcji SQL

Explorer

  • Rozwijasz szybko bez pisania SQL
  • Intuicyjna praca z relacjami między tabelami
  • Docenisz automatyczną optymalizację zapytań
  • Odpowiednie do szybkiej i wygodnej pracy z bazą danych

Instalacja

Bibliotekę można pobrać i zainstalować za pomocą narzędzia Composer:

composer require nette/database

Obsługiwane bazy danych

Nette Database obsługuje następujące bazy danych:

Serwer bazy danych Nazwa DSN Wsparcie w Explorer
MySQL (>= 5.1) mysql TAK
PostgreSQL (>= 9.0) pgsql TAK
Sqlite 3 (>= 3.8) sqlite TAK
Oracle oci
MS SQL (PDO_SQLSRV) sqlsrv TAK
MS SQL (PDO_DBLIB) mssql
ODBC odbc

Dwa podejścia do bazy danych

Nette Database daje Ci wybór: możesz pisać zapytania SQL bezpośrednio (dostęp SQL) lub pozwolić na ich automatyczne generowanie (Explorer). Zobaczmy, jak oba podejścia rozwiązują te same zadania:

Dostęp SQL – Zapytania SQL

// wstawienie rekordu
$database->query('INSERT INTO books', [
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// pobranie rekordów: autorzy książek
$result = $database->query('
	SELECT authors.*, COUNT(books.id) AS books_count
	FROM authors
	LEFT JOIN books ON authors.id = books.author_id
	WHERE authors.active = 1
	GROUP BY authors.id
');

// wypisanie (nie jest optymalne, generuje N dodatkowych zapytań)
foreach ($result as $author) {
	$books = $database->query('
		SELECT * FROM books
		WHERE author_id = ?
		ORDER BY published_at DESC
	', $author->id);

	echo "Autor $author->name napisał $author->books_count książek:\n";

	foreach ($books as $book) {
		echo "- $book->title\n";
	}
}

Podejście Explorer – automatyczne generowanie SQL

// wstawienie rekordu
$database->table('books')->insert([
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// pobranie rekordów: autorzy książek
$authors = $database->table('authors')
	->where('active', 1);

// wypisanie (automatycznie generuje tylko 2 zoptymalizowane zapytania)
foreach ($authors as $author) {
	$books = $author->related('books')
		->order('published_at DESC');

	echo "Autor $author->name napisał {$books->count()} książek:\n";

	foreach ($books as $book) {
		echo "- $book->title\n";
	}
}

Podejście Explorer generuje i optymalizuje zapytania SQL automatycznie. W podanym przykładzie podejście SQL wygeneruje N+1 zapytań (jedno dla autorów, a następnie jedno dla książek każdego autora), podczas gdy Explorer automatycznie optymalizuje zapytania i wykonuje tylko dwa – jedno dla autorów i jedno dla wszystkich ich książek.

Oba podejścia można dowolnie łączyć w aplikacji w zależności od potrzeb.

Połączenie i konfiguracja

Aby połączyć się z bazą danych, wystarczy utworzyć instancję klasy Nette\Database\Connection:

$database = new Nette\Database\Connection($dsn, $user, $password);

Parametr $dsn (data source name) jest taki sam, jakiego używa PDO, np. host=127.0.0.1;dbname=test. W przypadku niepowodzenia rzuca wyjątek Nette\Database\ConnectionException.

Jednak wygodniejszy sposób oferuje konfiguracja aplikacji, gdzie wystarczy dodać sekcję database, a zostaną utworzone potrzebne obiekty oraz panel bazy danych w pasku Tracy.

database:
	dsn: 'mysql:host=127.0.0.1;dbname=test'
	user: root
	password: password

Następnie obiekt połączenia uzyskujemy jako usługę z kontenera DI, np.:

class Model
{
	public function __construct(
		// lub Nette\Database\Explorer
		private Nette\Database\Connection $database,
	) {
	}
}

Więcej informacji o konfiguracji bazy danych.

Ręczne tworzenie Explorera

Jeśli nie używasz kontenera Nette DI, możesz utworzyć instancję Nette\Database\Explorer ręcznie:

// połączenie z bazą danych
$connection = new Nette\Database\Connection('mysql:host=127.0.0.1;dbname=mydatabase', 'user', 'password');
// magazyn dla cache, implementuje Nette\Caching\Storage, np.:
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp/dir');
// zajmuje się refleksją struktury bazy danych
$structure = new Nette\Database\Structure($connection, $storage);
// definiuje reguły mapowania nazw tabel, kolumn i kluczy obcych
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
$explorer = new Nette\Database\Explorer($connection, $structure, $conventions, $storage);

Zarządzanie połączeniem

Podczas tworzenia obiektu Connection połączenie jest nawiązywane automatycznie. Jeśli chcesz odłożyć połączenie, użyj trybu lazy – włączysz go w konfiguracji ustawiając lazy, lub w ten sposób:

$database = new Nette\Database\Connection($dsn, $user, $password, ['lazy' => true]);

Do zarządzania połączeniem użyj metod connect(), disconnect() i reconnect().

  • connect() tworzy połączenie, jeśli jeszcze nie istnieje, przy czym może rzucić wyjątek Nette\Database\ConnectionException.
  • disconnect() rozłącza bieżące połączenie z bazą danych.
  • reconnect() wykonuje rozłączenie i ponowne połączenie z bazą danych. Ta metoda również może rzucić wyjątek Nette\Database\ConnectionException.

Ponadto możesz śledzić zdarzenia związane z połączeniem za pomocą zdarzenia onConnect, które jest tablicą callbacków wywoływanych po nawiązaniu połączenia z bazą danych.

// wykonuje się po połączeniu z bazą danych
$database->onConnect[] = function($database) {
	echo "Połączono z bazą danych";
};

Pasek Debugowania Tracy

Jeśli używasz Tracy, panel Database w pasku Debugowania aktywuje się automatycznie, wyświetlając wszystkie wykonane zapytania, ich parametry, czas wykonania oraz miejsce w kodzie, gdzie zostały wywołane.