Jedro zbirke podatkov

Nette Database Core je abstraktni sloj podatkovne zbirke in zagotavlja osnovne funkcionalnosti.

Namestitev

Prenesite in namestite paket s programom Composer:

composer require nette/database

Priključitev in konfiguracija

Če se želite povezati s podatkovno zbirko, preprosto ustvarite primerek razreda Nette\Database\Connection:

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

Parameter $dsn (ime vira podatkov) je enak tistemu, ki ga uporablja PDO, npr. host=127.0.0.1;dbname=test. V primeru neuspeha se vrže Nette\Database\ConnectionException.

Vendar pa bolj prefinjen način ponuja konfiguracija aplikacije. Dodamo razdelek database in ta ustvari zahtevane predmete in ploščo s podatkovno bazo v vrstici Tracy.

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

Objekt povezave prejmemo kot storitev iz vsebnika DI, na primer:

class Model
{
	// predajte Nette\Database\Explorer za delo s slojem Raziskovalec podatkovne baze
	public function __construct(
		private Nette\Database\Connection $database,
	) {
	}
}

Za več informacij glejte Konfiguracija podatkovne zbirke.

Poizvedbe

Za poizvedovanje po zbirki podatkov uporabite metodo query(), ki vrne nabor rezultatov (ResultSet).

$result = $database->query('SELECT * FROM users');

foreach ($result as $row) {
	echo $row->id;
	echo $row->name;
}

echo $result->getRowCount(); // vrne število vrstic, če je znano

Nad ResultSet je mogoče iterirati samo enkrat, če pa moramo iterirati večkrat, je treba rezultat pretvoriti v polje prek metode fetchAll().

Poizvedbi lahko preprosto dodate parametre, pri čemer upoštevajte vprašalni znak:

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

Opozorilo, nikoli ne združujte nizov, da se izognete ranljivosti vbrizgavanja SQL!

$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!!

V primeru neuspeha query() vrže Nette\Database\DriverException ali enega od njegovih potomcev:

Poleg query() so na voljo še druge uporabne metode:

// vrne asociativno polje id => ime
$pairs = $database->fetchPairs('SELECT id, name FROM users');

// vrne vse vrstice kot polje
$rows = $database->fetchAll('SELECT * FROM users');

// vrne posamezno vrstico
$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id);

// vrne posamezno polje
$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id);

V primeru neuspeha vse te metode zavržejo Nette\Database\DriverException.

Vstavljanje, posodabljanje in brisanje

Parameter, ki ga vstavimo v poizvedbo SQL, je lahko tudi polje (v tem primeru je mogoče preskočiti nadomestno izjavo ?), which may be useful for the INSERT:

$database->query('INSERT INTO users ?', [ // tukaj se lahko izpusti vprašalno znamenje
	'name' => $name,
	'year' => $year,
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978)

$id = $database->getInsertId(); // vrne samodejno povečanje vstavljene vrstice

$id = $database->getInsertId($sequence); // ali vrednost zaporedja

Večkratno vstavljanje:

$database->query('INSERT INTO users', [
	[
		'name' => 'Jim',
		'year' => 1978,
	], [
		'name' => 'Jack',
		'year' => 1987,
	],
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987)

Vstavljamo lahko tudi datoteke, objekte DateTime ali naštevanja:

$database->query('INSERT INTO users', [
	'name' => $name,
	'created' => new DateTime, // ali $databaza::literal('NOW()')
	'avatar' => fopen('image.gif', 'r'), // vstavi vsebino datoteke
	'status' => State::New, // enum State
]);

Posodabljanje vrstic:

$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(); // vrne število prizadetih vrstic

Za UPDATE lahko uporabimo operatorja += in -=:

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

Brisanje:

$result = $database->query('DELETE FROM users WHERE id = ?', $id);
echo $result->getRowCount(); // vrne število prizadetih vrstic

Napredne poizvedbe

Vstavljanje ali posodabljanje, če že obstaja:

$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

Upoštevajte, da podatkovna baza Nette prepozna kontekst SQL, v katerem je vstavljen parameter polja, in v skladu s tem sestavi kodo SQL. Tako iz prvega polja ustvari (id, name, year) VALUES (123, 'Jim', 1978), medtem ko drugo pretvori v name = 'Jim', year = 1978.

Sortiranje lahko opišemo tudi z uporabo polja, pri čemer so ključi imena stolpcev, vrednosti pa logične vrednosti, ki določajo, ali naj se sortira v naraščajočem vrstnem redu:

$database->query('SELECT id FROM author ORDER BY', [
	'id' => true, // naraščajoče
	'name' => false, // padajoče
]);
// SELECT id FROM author ORDER BY `id`, `name` DESC

Če zaznavanje ni delovalo, lahko določite obliko sklopa z nadomestnim znakom ?, ki mu sledi namig. Ti namigi so podprti:

(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 stavku WHERE je uporabljen operator ?and, zato so pogoji povezani s AND:

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

To lahko z uporabo nadomestnega znaka ?or preprosto spremenite v OR:

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

V pogojih lahko uporabljamo operatorje:

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

in tudi naštevanja:

$result = $database->query('SELECT * FROM users WHERE', [
	'name' => ['Jim', 'Jack'],
	'role NOT IN' => ['admin', 'owner'], // naštevanje + operator NOT IN
]);
// SELECT * FROM users WHERE
//   `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner')

Vključimo lahko tudi del kode SQL po meri z uporabo tako imenovanega literala SQL:

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

Druga možnost:

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

SQL literal ima lahko tudi svoje parametre:

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

Zaradi tega lahko ustvarimo zanimive kombinacije:

$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')

Ime spremenljivke

Obstaja nadomestni znak ?name, ki ga uporabite, če je ime tabele ali stolpca spremenljivka. (Pazite, da uporabniku ne dovolite, da bi manipuliral z vsebino take spremenljivke):

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

Transakcije

Obstajajo trije načini obravnavanja transakcij:

$database->beginTransaction();

$database->commit();

$database->rollback();

Eleganten način ponuja metoda transaction(). Predate povratni klic, ki se izvede v transakciji. Če se med izvajanjem vrže izjema, se transakcija opusti, če je vse v redu, se transakcija izvede.

$id = $database->transaction(function ($database) {
	$database->query('DELETE FROM ...');
	$database->query('INSERT INTO ...');
	// ...
	return $database->getInsertId();
});

Kot lahko vidite, metoda transaction() vrne povratno vrednost povratnega klica.

Metoda transaction() je lahko tudi vgnezdena, kar poenostavi izvajanje neodvisnih skladišč.

različica: 4.0