Nette Documentation Preview

syntax
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
```

<div class=warning>
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Ě!!!
\--
</div>

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ářů.


Reflexe .{data-version:3.2.1}
=============================

Nette Database poskytuje nástroje pro introspekci databázové struktury pomocí třídy [api:Nette\Database\Reflection]. Ta umožňuje získávat informace o tabulkách, sloupcích, indexech a cizích klíčích. Reflexi můžete využít ke generování schémat, vytváření flexibilních aplikací pracujících s databází nebo obecných databázových nástrojů.

Objekt reflexe získáme z instance připojení k databázi:

```php
$reflection = $database->getReflection();
```


Práce s tabulkami
-----------------

Pomocí reflexe můžeme procházet všechny tabulky v databázi:

```php
// Výpis názvů všech tabulek
foreach ($reflection->tables as $tableName => $table) {
    echo $tableName . "\n";
}

// Ověření existence tabulky
if ($reflection->hasTable('users')) {
    echo "Tabulka users existuje";
}

// Získání konkrétní tabulky
$table = $reflection->getTable('users');
```


Informace o sloupcích
---------------------

Pro každou tabulku můžeme získat detailní informace o jejích sloupcích:

```php
// Procházení všech sloupců
foreach ($table->columns as $column) {
    echo "Sloupec: " . $column->name . "\n";
    echo "Typ: " . $column->nativeType . "\n";
    echo "Může být NULL: " . ($column->nullable ? 'Ano' : 'Ne') . "\n";
    echo "Výchozí hodnota: " . ($column->default ?? 'Není') . "\n";
    echo "Je primární klíč: " . ($column->primary ? 'Ano' : 'Ne') . "\n";
    echo "Je auto-increment: " . ($column->autoIncrement ? 'Ano' : 'Ne') . "\n";
}

// Získání konkrétního sloupce
$idColumn = $table->getColumn('id');
```


Indexy a primární klíče
-----------------------

Reflection poskytuje informace o indexech a primárních klíčích:

```php
$vypisNazvySloupcu = fn(array $columns) => implode(', ', array_map(fn($col) => $col->name, $columns));

// Výpis všech indexů
foreach ($table->indexes as $index) {
    echo "Index: " . ($index->name ?? 'Nepojmenovaný') . "\n";
    echo "Sloupce: " . $vypisNazvySloupcu($index->columns) . "\n";
    echo "Je unikátní: " . ($index->unique ? 'Ano' : 'Ne') . "\n";
    echo "Je primární klíč: " . ($index->primary ? 'Ano' : 'Ne') . "\n";
}

// Získání primárního klíče
if ($table->primaryKey) {
    echo "Primární klíč: " . $vypisNazvySloupcu($table->primaryKey->columns) . "\n";
}
```


Cizí klíče
----------

Můžeme také získat informace o cizích klíčích:

```php
foreach ($table->foreignKeys as $fk) {
    echo "Cizí klíč: " . ($fk->name ?? 'Nepojmenovaný') . "\n";
    echo "Lokální sloupce: " . $vypisNazvySloupcu($fk->localColumns) . "\n";
    echo "Odkazuje na tabulku: {$fk->foreignTable->name}\n";
    echo "Odkazuje na sloupce: " . $vypisNazvySloupcu($fk->foreignColumns) . "\n";
}
```

Database Core

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:

composer require nette/database

Připojení a konfigurace

Pro připojení k databázi stačí vytvořit instanci třídy Nette\Database\Connection:

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

Parametr $dsn (data source name) je stejný, jaký používá PDO, 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, kam stačí přidat sekci database a vytvoří se potřebné objekty a také databázový panel v Tracy baru.

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, např.:

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.

Dotazy

Databázové dotazy pokládáme metodou query(), která vrací ResultSet.

$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

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:

$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
$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ů:

Kromě query() jsou tu další užitečné funkce:

// 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:

$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:

$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:

$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ů:

$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 -=:

$database->query('UPDATE users SET', [
	'age+=' => 1, // všimněte si +=
], 'WHERE id = ?', $id);
// UPDATE users SET `age` = `age` + 1

Mazání:

$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:

$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ě:

$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:

$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:

$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:

$result = $database->query('SELECT * FROM users WHERE', [
	'name <>' => $name,
	'year >' => $year,
]);
// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978

A také výčty:

$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:

$result = $database->query('SELECT * FROM users WHERE', [
	'name' => $name,
	'year >' => $database::literal('YEAR()'),
]);
// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR())

Nebo alternativě:

$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:

$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:

$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é):

$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:

$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í.

$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ářů.

Reflexe

Nette Database poskytuje nástroje pro introspekci databázové struktury pomocí třídy Nette\Database\Reflection. Ta umožňuje získávat informace o tabulkách, sloupcích, indexech a cizích klíčích. Reflexi můžete využít ke generování schémat, vytváření flexibilních aplikací pracujících s databází nebo obecných databázových nástrojů.

Objekt reflexe získáme z instance připojení k databázi:

$reflection = $database->getReflection();

Práce s tabulkami

Pomocí reflexe můžeme procházet všechny tabulky v databázi:

// Výpis názvů všech tabulek
foreach ($reflection->tables as $tableName => $table) {
    echo $tableName . "\n";
}

// Ověření existence tabulky
if ($reflection->hasTable('users')) {
    echo "Tabulka users existuje";
}

// Získání konkrétní tabulky
$table = $reflection->getTable('users');

Informace o sloupcích

Pro každou tabulku můžeme získat detailní informace o jejích sloupcích:

// Procházení všech sloupců
foreach ($table->columns as $column) {
    echo "Sloupec: " . $column->name . "\n";
    echo "Typ: " . $column->nativeType . "\n";
    echo "Může být NULL: " . ($column->nullable ? 'Ano' : 'Ne') . "\n";
    echo "Výchozí hodnota: " . ($column->default ?? 'Není') . "\n";
    echo "Je primární klíč: " . ($column->primary ? 'Ano' : 'Ne') . "\n";
    echo "Je auto-increment: " . ($column->autoIncrement ? 'Ano' : 'Ne') . "\n";
}

// Získání konkrétního sloupce
$idColumn = $table->getColumn('id');

Indexy a primární klíče

Reflection poskytuje informace o indexech a primárních klíčích:

$vypisNazvySloupcu = fn(array $columns) => implode(', ', array_map(fn($col) => $col->name, $columns));

// Výpis všech indexů
foreach ($table->indexes as $index) {
    echo "Index: " . ($index->name ?? 'Nepojmenovaný') . "\n";
    echo "Sloupce: " . $vypisNazvySloupcu($index->columns) . "\n";
    echo "Je unikátní: " . ($index->unique ? 'Ano' : 'Ne') . "\n";
    echo "Je primární klíč: " . ($index->primary ? 'Ano' : 'Ne') . "\n";
}

// Získání primárního klíče
if ($table->primaryKey) {
    echo "Primární klíč: " . $vypisNazvySloupcu($table->primaryKey->columns) . "\n";
}

Cizí klíče

Můžeme také získat informace o cizích klíčích:

foreach ($table->foreignKeys as $fk) {
    echo "Cizí klíč: " . ($fk->name ?? 'Nepojmenovaný') . "\n";
    echo "Lokální sloupce: " . $vypisNazvySloupcu($fk->localColumns) . "\n";
    echo "Odkazuje na tabulku: {$fk->foreignTable->name}\n";
    echo "Odkazuje na sloupce: " . $vypisNazvySloupcu($fk->foreignColumns) . "\n";
}