Nette Documentation Preview

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

.[perex]
Nette Database е мощно и елегантно ниво за работа с бази данни за PHP с акцент върху простотата и интелигентните функции. Предлага два начина за работа с базата данни - [Explorer |Explorer] за бърза разработка на приложения или [SQL достъп |SQL way] за директна работа със заявки.

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


[SQL достъп |SQL way]
=====================
- Безопасни параметризирани заявки
- Прецизен контрол върху формата на SQL заявките
- Когато пишете сложни заявки с разширени функции
- Оптимизирате производителността с помощта на специфични SQL функции

</div>

<div>


[Explorer |Explorer]
====================
- Разработвате бързо без писане на SQL
- Интуитивна работа с релациите между таблиците
- Ще оцените автоматичната оптимизация на заявките
- Подходящо за бърза и удобна работа с базата данни

</div>

</div>


Инсталация
==========

Можете да изтеглите и инсталирате библиотеката с помощта на инструмента [Composer|best-practices:composer]:

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


Поддържани бази данни
=====================

Nette Database поддържа следните бази данни:

|* Сървър на база данни  |* DSN име  |* Поддръжка в Explorer
|---------------------|-------------|-----------------------
| MySQL (>= 5.1)      | mysql       | ДА
| PostgreSQL (>= 9.0) | pgsql       | ДА
| Sqlite 3 (>= 3.8)   | sqlite      | ДА
| Oracle              | oci         | -
| MS SQL (PDO_SQLSRV) | sqlsrv      | ДА
| MS SQL (PDO_DBLIB)  | mssql       | -
| ODBC                | odbc        | -


Два подхода към базата данни
============================

Nette Database ви дава избор: можете или да пишете SQL заявки директно (SQL достъп), или да ги оставите да се генерират автоматично (Explorer). Нека видим как двата подхода решават едни и същи задачи:

[SQL достъп|sql way] - SQL заявки

```php
// вмъкване на запис
$database->query('INSERT INTO books', [
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// получаване на записи: автори на книги
$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
');

// изход (не е оптимален, генерира N допълнителни заявки)
foreach ($result as $author) {
	$books = $database->query('
		SELECT * FROM books
		WHERE author_id = ?
		ORDER BY published_at DESC
	', $author->id);

	echo "Автор $author->name е написал $author->books_count книги:\n";

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

[Explorer достъп|explorer] - автоматично генериране на SQL

```php
// вмъкване на запис
$database->table('books')->insert([
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// получаване на записи: автори на книги
$authors = $database->table('authors')
	->where('active', 1);

// изход (автоматично генерира само 2 оптимизирани заявки)
foreach ($authors as $author) {
	$books = $author->related('books')
		->order('published_at DESC');

	echo "Автор $author->name е написал {$books->count()} книги:\n";

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

Explorer достъпът генерира и оптимизира SQL заявките автоматично. В дадения пример SQL достъпът ще генерира N+1 заявки (една за авторите и след това по една за книгите на всеки автор), докато Explorer автоматично оптимизира заявките и изпълнява само две - една за авторите и една за всички техни книги.

Двата подхода могат да се комбинират свободно в приложението според нуждите.


Свързване и конфигурация
========================

За да се свържете с базата данни, е достатъчно да създадете инстанция на класа [api:Nette\Database\Connection]:

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

Параметърът `$dsn` (data source name) е същият, [както се използва от PDO |https://www.php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters], напр. `mysql: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
{
	public function __construct(
		// или Nette\Database\Explorer
		private Nette\Database\Connection $database,
	) {
	}
}
```

Повече информация за [конфигурацията на базата данни |configuration].


Ръчно създаване на Explorer
---------------------------

Ако не използвате Nette DI контейнер, можете да създадете инстанция на `Nette\Database\Explorer` ръчно:

```php
// свързване с базата данни
$connection = new Nette\Database\Connection('mysql:host=127.0.0.1;dbname=mydatabase', 'user', 'password');
// хранилище за кеш, имплементира Nette\Caching\Storage, напр.:
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp/dir');
// грижи се за рефлексията на структурата на базата данни
$structure = new Nette\Database\Structure($connection, $storage);
// дефинира правила за мапиране на имената на таблици, колони и външни ключове
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
$explorer = new Nette\Database\Explorer($connection, $structure, $conventions, $storage);
```


Управление на връзката
======================

При създаване на обект `Connection` автоматично се осъществява връзка. Ако искате да отложите връзката, използвайте lazy режим - можете да го включите в [конфигурацията |configuration], като зададете `lazy: true`, или по следния начин:

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

За управление на връзката използвайте методите `connect()`, `disconnect()` и `reconnect()`.
- `connect()` създава връзка, ако все още не съществува, като може да хвърли изключение `Nette\Database\ConnectionException`.
- `disconnect()` прекъсва текущата връзка с базата данни.
- `reconnect()` извършва прекъсване и последващо повторно свързване с базата данни. Този метод също може да хвърли изключение `Nette\Database\ConnectionException`.

Освен това можете да следите събитията, свързани с връзката, с помощта на събитието `onConnect`, което е масив от callback-ове, които се извикват след установяване на връзка с базата данни.

```php
// изпълнява се след свързване с базата данни
$database->onConnect[] = function($database) {
	echo "Свързано с базата данни";
};
```


Tracy Debug Bar
===============

Ако използвате [Tracy |tracy:], автоматично се активира панелът Database в Debug лентата, който показва всички изпълнени заявки, техните параметри, времето за изпълнение и мястото в кода, където са били извикани.

[* db-panel.webp *]

Nette Database

Nette Database е мощно и елегантно ниво за работа с бази данни за PHP с акцент върху простотата и интелигентните функции. Предлага два начина за работа с базата данни – Explorer за бърза разработка на приложения или SQL достъп за директна работа със заявки.

SQL достъп

  • Безопасни параметризирани заявки
  • Прецизен контрол върху формата на SQL заявките
  • Когато пишете сложни заявки с разширени функции
  • Оптимизирате производителността с помощта на специфични SQL функции

Explorer

  • Разработвате бързо без писане на SQL
  • Интуитивна работа с релациите между таблиците
  • Ще оцените автоматичната оптимизация на заявките
  • Подходящо за бърза и удобна работа с базата данни

Инсталация

Можете да изтеглите и инсталирате библиотеката с помощта на инструмента Composer:

composer require nette/database

Поддържани бази данни

Nette Database поддържа следните бази данни:

Сървър на база данни DSN име Поддръжка в Explorer
MySQL (>= 5.1) mysql ДА
PostgreSQL (>= 9.0) pgsql ДА
Sqlite 3 (>= 3.8) sqlite ДА
Oracle oci
MS SQL (PDO_SQLSRV) sqlsrv ДА
MS SQL (PDO_DBLIB) mssql
ODBC odbc

Два подхода към базата данни

Nette Database ви дава избор: можете или да пишете SQL заявки директно (SQL достъп), или да ги оставите да се генерират автоматично (Explorer). Нека видим как двата подхода решават едни и същи задачи:

SQL достъп – SQL заявки

// вмъкване на запис
$database->query('INSERT INTO books', [
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// получаване на записи: автори на книги
$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
');

// изход (не е оптимален, генерира N допълнителни заявки)
foreach ($result as $author) {
	$books = $database->query('
		SELECT * FROM books
		WHERE author_id = ?
		ORDER BY published_at DESC
	', $author->id);

	echo "Автор $author->name е написал $author->books_count книги:\n";

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

Explorer достъп – автоматично генериране на SQL

// вмъкване на запис
$database->table('books')->insert([
	'author_id' => $authorId,
	'title' => $bookData->title,
	'published_at' => new DateTime,
]);

// получаване на записи: автори на книги
$authors = $database->table('authors')
	->where('active', 1);

// изход (автоматично генерира само 2 оптимизирани заявки)
foreach ($authors as $author) {
	$books = $author->related('books')
		->order('published_at DESC');

	echo "Автор $author->name е написал {$books->count()} книги:\n";

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

Explorer достъпът генерира и оптимизира SQL заявките автоматично. В дадения пример SQL достъпът ще генерира N+1 заявки (една за авторите и след това по една за книгите на всеки автор), докато Explorer автоматично оптимизира заявките и изпълнява само две – една за авторите и една за всички техни книги.

Двата подхода могат да се комбинират свободно в приложението според нуждите.

Свързване и конфигурация

За да се свържете с базата данни, е достатъчно да създадете инстанция на класа Nette\Database\Connection:

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

Параметърът $dsn (data source name) е същият, както се използва от PDO, напр. mysql:host=127.0.0.1;dbname=test. В случай на неуспех, хвърля изключение Nette\Database\ConnectionException.

Въпреки това, по-удобен начин предлага конфигурацията на приложението, където е достатъчно да добавите секция database и ще се създадат необходимите обекти, както и панелът за база данни в лентата на Tracy .

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

След това получаваме обекта на връзката като сървис от DI контейнера, напр.:

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

Повече информация за конфигурацията на базата данни.

Ръчно създаване на Explorer

Ако не използвате Nette DI контейнер, можете да създадете инстанция на Nette\Database\Explorer ръчно:

// свързване с базата данни
$connection = new Nette\Database\Connection('mysql:host=127.0.0.1;dbname=mydatabase', 'user', 'password');
// хранилище за кеш, имплементира Nette\Caching\Storage, напр.:
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp/dir');
// грижи се за рефлексията на структурата на базата данни
$structure = new Nette\Database\Structure($connection, $storage);
// дефинира правила за мапиране на имената на таблици, колони и външни ключове
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
$explorer = new Nette\Database\Explorer($connection, $structure, $conventions, $storage);

Управление на връзката

При създаване на обект Connection автоматично се осъществява връзка. Ако искате да отложите връзката, използвайте lazy режим – можете да го включите в конфигурацията, като зададете lazy: true, или по следния начин:

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

За управление на връзката използвайте методите connect(), disconnect() и reconnect().

  • connect() създава връзка, ако все още не съществува, като може да хвърли изключение Nette\Database\ConnectionException.
  • disconnect() прекъсва текущата връзка с базата данни.
  • reconnect() извършва прекъсване и последващо повторно свързване с базата данни. Този метод също може да хвърли изключение Nette\Database\ConnectionException.

Освен това можете да следите събитията, свързани с връзката, с помощта на събитието onConnect, което е масив от callback-ове, които се извикват след установяване на връзка с базата данни.

// изпълнява се след свързване с базата данни
$database->onConnect[] = function($database) {
	echo "Свързано с базата данни";
};

Tracy Debug Bar

Ако използвате Tracy, автоматично се активира панелът Database в Debug лентата, който показва всички изпълнени заявки, техните параметри, времето за изпълнение и мястото в кода, където са били извикани.