Adatbázis mag

A Nette Database Core az adatbázis absztrakciós rétege, és alapvető funkciókat biztosít.

Telepítés

Töltse le és telepítse a csomagot a Composer segítségével:

composer require nette/database

Csatlakozás és konfiguráció

Az adatbázishoz való csatlakozáshoz egyszerűen hozzon létre egy példányt a Nette\Database\Connection osztályból:

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

A $dsn (adatforrás neve) paraméter ugyanaz, mint amit a PDO használ, 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. Hozzáadunk egy database szakaszt, és ez létrehozza a szükséges objektumokat és egy adatbázis panelt a Tracy sávban.

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:

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ó.

Lekérdezések

Az adatbázis lekérdezéséhez használja a query() módszert, amely ResultSet-et ad vissza.

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

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:

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

A query() mellett vannak más hasznos módszerek is:

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

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:

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

$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 is átadhatunk:

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

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

$database->query('UPDATE users SET', [
	'age+=' => 1, // note +=
], 'WHERE id = ?', $id);
// UPDATE users SET `age` = `age` + 1

Törlés:

$result = $database->query('DELETE FROM users WHERE id = ?', $id);
echo $result->getRowCount(); // visszaadja az érintett sorok számát.

Speciális lekérdezések

Beszúrás vagy frissítés, ha már létezik:

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

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

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

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

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

És felsorolásokat is:

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

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

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

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

$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

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

$table = 'blog.users';
$column = 'name';
$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name);
// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim'

Tranzakciók

A tranzakciók kezelésére három módszer áll rendelkezésre:

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

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

Reflection

A Nette Database a Nette\Database\Reflection osztályon keresztül eszközöket biztosít az adatbázis szerkezetének áttekintéséhez. Ez az osztály lehetővé teszi a táblákról, oszlopokról, indexekről és idegen kulcsokról szóló információk lekérdezését. A reflexiót használhatja sémák létrehozására, adatbázisokkal dolgozó rugalmas alkalmazások létrehozására vagy általános adatbázis-eszközök készítésére.

A reflection objektumot egy adatbázis-kapcsolati példányból szerezheti meg:

$reflection = $database->getReflection();

Munka táblázatokkal

A tükrözés segítségével az adatbázis összes tábláján végig tudsz menni:

// Az összes táblázat nevének felsorolása
foreach ($reflection->tables as $tableName => $table) {
    echo $tableName . "\n";
}

// Ellenőrizze, hogy létezik-e táblázat
if ($reflection->hasTable('users')) {
    echo "The 'users' table exists";
}

// Egy adott táblázat lekérdezése
$table = $reflection->getTable('users');

Oszlop információk

Az egyes táblák oszlopairól részletes információkat kaphat:

// Ismétlés az összes oszlopon
foreach ($table->columns as $column) {
    echo "Column: " . $column->name . "\n";
    echo "Type: " . $column->nativeType . "\n";
    echo "Nullable: " . ($column->nullable ? 'Yes': 'No') . "\n";
    echo "Default value: " . ($column->default ?? 'None') . "\n";
    echo "Primary key: " . ($column->primary ? 'Yes': 'No') . "\n";
    echo "Auto-increment: " . ($column->autoIncrement ? 'Yes': 'No') . "\n";
}

// Egy adott oszlop kinyerése
$idColumn = $table->getColumn('id');

Indexek és elsődleges kulcsok

A Reflection az indexekről és az elsődleges kulcsokról nyújt információt:

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

// Az összes index felsorolása
foreach ($table->indexes as $index) {
    echo "Index: " . ($index->name ?? 'Unnamed') . "\n";
    echo "Columns: " . $listColumnNames($index->columns) . "\n";
    echo "Unique: " . ($index->unique ? 'Yes': 'No') . "\n";
    echo "Primary key: " . ($index->primary ? 'Yes': 'No') . "\n";
}

// Az elsődleges kulcs kinyerése
if ($table->primaryKey) {
    echo "Primary key: " . $listColumnNames($table->primaryKey->columns) . "\n";
}

Idegen kulcsok

Az idegen kulcsokról is tájékozódhat:

foreach ($table->foreignKeys as $fk) {
    echo "Foreign key: " . ($fk->name ?? 'Unnamed') . "\n";
    echo "Local columns: " . $listColumnNames($fk->localColumns) . "\n";
    echo "References table: {$fk->foreignTable->name}\n";
    echo "References columns: " . $listColumnNames($fk->foreignColumns) . "\n";
}
verzió: 4.0