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:
- ConstraintViolationException – kršitev katere koli omejitve
- ForeignKeyConstraintViolationException – neveljaven tuj ključ
- NotNullConstraintViolationException – kršitev pogoja NOT NULL
- UniqueConstraintViolationException – konflikt edinstvenega indeksa
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šč.