Nette Database

Nette Database to potężna i elegancka warstwa bazodanowa dla PHP, skupiona na prostocie i sprytnych funkcjach. Oferuje dwa sposoby pracy z bazą danych: Explorer do szybkiego tworzenia aplikacji albo podejście SQL do bezpośredniej pracy z zapytaniami.

Podejście SQL

  • Bezpieczne, parametryzowane zapytania
  • Precyzyjna kontrola nad strukturą zapytania SQL
  • Gdy piszesz złożone zapytania z zaawansowanymi funkcjami
  • Optymalizacja wydajności za pomocą konkretnych funkcji SQL

Explorer

  • Szybkie tworzenie bez pisania SQL
  • Intuicyjna praca z relacjami między tabelami
  • Korzyść z automatycznej optymalizacji zapytań
  • Odpowiedni do szybkiej i wygodnej pracy z bazą danych

Instalacja

Pobierz i zainstaluj bibliotekę za pomocą Composera:

composer require nette/database

Obsługiwane bazy danych

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

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

Dwa podejścia do pracy z bazą danych

Nette Database daje Ci wybór: możesz albo pisać zapytania SQL bezpośrednio (podejście SQL), albo pozwolić je generować automatycznie (Explorer). Zobaczmy, jak oba podejścia radzą sobie z tymi samymi zadaniami:

Podejście 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 (nieoptymalne, 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 powyższym przykładzie podejście SQL generuje N+1 zapytań (jedno na autorów, a potem po jednym na książki każdego autora), podczas gdy Explorer automatycznie optymalizuje zapytania i wykonuje tylko dwa: jedno na autorów i jedno na wszystkie ich książki.

Oba podejścia można w aplikacji swobodnie łączyć według potrzeb.

Połączenie i konfiguracja

Żeby 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, jak używany przez PDO, np. host=127.0.0.1;dbname=test. W razie niepowodzenia rzuca Nette\Database\ConnectionException.

Wygodniejszą metodę oferuje jednak konfiguracja aplikacji, gdzie wystarczy dodać sekcję database. Utworzy to potrzebne obiekty, a także panel bazy danych w pasku Tracy.

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

Obiekt połączenia można potem uzyskać jako usługę z kontenera DI, np.:

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

Więcej informacji o konfiguracji bazy danych.

Ręczne utworzenie Explorera

Jeśli nie używasz kontenera DI Nette, 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 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

Przy utworzeniu obiektu Connection połączenie nawiązywane jest automatycznie. Jeśli chcesz połączenie opóźnić, użyj trybu lazy: włączysz go w konfiguracji ustawieniem lazy albo tak:

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

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

  • connect() tworzy połączenie, jeśli jeszcze nie istnieje, i może rzucić 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ć Nette\Database\ConnectionException.

Poza tym możesz monitorować 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";
};

Podobnie działa zdarzenie onQuery: jest to tablica callbacków wywoływanych po każdym wykonanym zapytaniu (a także wtedy, gdy zapytanie się nie powiedzie), przydatna do logowania albo profilowania.

Tracy Debug Bar

Jeśli używasz Tracy, panel Database w Debug Barze aktywuje się automatycznie. Wyświetla wszystkie wykonane zapytania, ich parametry, czas wykonania i miejsce w kodzie, z którego zostały wywołane.

wersja: 4.x