Πυρήνας βάσης δεδομένων

Το Nette Database Core είναι ένα επίπεδο αφαίρεσης βάσεων δεδομένων και παρέχει βασική λειτουργικότητα.

Εγκατάσταση

Κατεβάστε και εγκαταστήστε το πακέτο χρησιμοποιώντας το Composer:

composer require nette/database

Composer: Σύνδεση και διαμόρφωση

Για να συνδεθείτε στη βάση δεδομένων, απλώς δημιουργήστε μια περίπτωση της κλάσης Nette\Database\Connection:

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

Η παράμετρος $dsn (όνομα πηγής δεδομένων) είναι η ίδια που χρησιμοποιείται από το PDO, π.χ. 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
{
	// περάστε το Nette\Database\Explorer για να εργαστείτε με το επίπεδο Database Explorer
	public function __construct(
		private Nette\Database\Connection $database,
	) {
	}
}

Για περισσότερες πληροφορίες, ανατρέξτε στη διαμόρφωση της βάσης δεδομένων.

Ερωτήματα

Για να κάνετε ερώτημα στη βάση δεδομένων χρησιμοποιήστε τη μέθοδο query() που επιστρέφει ResultSet.

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

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

echo $result->getRowCount(); // επιστρέφει τον αριθμό των γραμμών αν είναι γνωστός

Πάνω από το ResultSet είναι δυνατόν να γίνει επανάληψη μόνο μία φορά, αν χρειαστεί να γίνει επανάληψη πολλές φορές, είναι απαραίτητο να μετατρέψουμε το αποτέλεσμα σε πίνακα μέσω της μεθόδου fetchAll().

Μπορείτε εύκολα να προσθέσετε παραμέτρους στο ερώτημα, σημειώστε το ερωτηματικό:

$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 είναι πίνακας

ΠΡΟΕΙΔΟΠΟΙΗΣΗ, μην συνδέετε ποτέ συμβολοσειρές για να αποφύγετε την ευπάθεια SQL injection!

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

Σε περίπτωση αποτυχίας το query() πετάει είτε το Nette\Database\DriverException είτε έναν από τους απογόνους του:

Εκτός από το query(), υπάρχουν και άλλες χρήσιμες μέθοδοι:

// επιστρέφει τον συσχετιστικό πίνακα id => name
$pairs = $database->fetchPairs('SELECT id, name FROM users');

// επιστρέφει όλες τις γραμμές ως πίνακα
$rows = $database->fetchAll('SELECT * FROM users');

// επιστρέφει μία μόνο γραμμή
$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id);

// επιστρέφει ένα μόνο πεδίο
$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id);

Σε περίπτωση αποτυχίας, όλες αυτές οι μέθοδοι ρίχνουν Nette\Database\DriverException.

Εισαγωγή, ενημέρωση και διαγραφή

Η παράμετρος που εισάγουμε στο ερώτημα SQL μπορεί επίσης να είναι ο πίνακας (σε αυτή την περίπτωση είναι δυνατόν να παραλείψουμε τη δήλωση μπαλαντέρ ?), which may be useful for the INSERT:

$database->query('INSERT INTO users ?', [ // εδώ μπορεί να παραλειφθεί το ερωτηματικό
	'name' => $name,
	'year' => $year,
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978)

$id = $database->getInsertId(); // επιστρέφει την αυτόματη αύξηση της εισαγόμενης γραμμής

$id = $database->getInsertId($sequence); // ή τιμή ακολουθίας

Πολλαπλή εισαγωγή:

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

DateTime ή απαριθμήσεις:

$database->query('INSERT INTO users', [
	'name' => $name,
	'created' => new DateTime, // ή $database::literal('NOW()')
	'avatar' => fopen('image.gif', 'r'), // Εισάγει τα περιεχόμενα του αρχείου
	'status' => State::New, // enum Κατάσταση
]);

Ενημέρωση γραμμών:

$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(); // επιστρέφει τον αριθμό των επηρεαζόμενων γραμμών

Για UPDATE, μπορούμε να χρησιμοποιήσουμε τους τελεστές += και -=:

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

Διαγραφή:

$result = $database->query('DELETE FROM users WHERE id = ?', $id);
echo $result->getRowCount(); // επιστρέφει τον αριθμό των επηρεαζόμενων γραμμών

Ερωτήματα για προχωρημένους

Εισαγωγή ή ενημέρωση, εάν υπάρχει ήδη:

$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

Σημειώστε ότι η Nette Database αναγνωρίζει το πλαίσιο SQL στο οποίο εισάγεται η παράμετρος του πίνακα και δημιουργεί τον κώδικα SQL ανάλογα. Έτσι, από τον πρώτο πίνακα παράγει το (id, name, year) VALUES (123, 'Jim', 1978), ενώ ο δεύτερος μετατρέπεται σε name = 'Jim', year = 1978.

Μπορούμε επίσης να περιγράψουμε την ταξινόμηση χρησιμοποιώντας array, στο keys είναι ονόματα στηλών και values είναι boolean που καθορίζει αν θα γίνει ταξινόμηση σε αύξουσα σειρά:

$database->query('SELECT id FROM author ORDER BY', [
	'id' => true, // αύξουσα
	'name' => false, // φθίνουσα
]);
// SELECT id FROM author ORDER BY `id`, `name` DESC

Εάν η ανίχνευση δεν λειτούργησε, μπορείτε να καθορίσετε τη μορφή της συνέλευσης με ένα μπαλαντέρ ? ακολουθούμενο από μια υπόδειξη. Αυτές οι υποδείξεις υποστηρίζονται:

?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

Η ρήτρα WHERE χρησιμοποιεί τον τελεστή ?and έτσι ώστε οι συνθήκες να συνδέονται με το AND:

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

Το οποίο μπορεί εύκολα να αλλάξει σε OR με τη χρήση του μπαλαντέρ ?or:

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

Μπορούμε να χρησιμοποιήσουμε τελεστές σε συνθήκες:

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

Και επίσης απαριθμήσεις:

$result = $database->query('SELECT * FROM users WHERE', [
	'name' => ['Jim', 'Jack'],
	'role NOT IN' => ['admin', 'owner'], // απαρίθμηση + τελεστής NOT IN
]);
// SELECT * FROM users WHERE
//   `name` IN ('Jim', 'Jack') AND `role` NOT IN ('admin', 'owner')

Μπορούμε επίσης να συμπεριλάβουμε ένα κομμάτι προσαρμοσμένου κώδικα SQL χρησιμοποιώντας το λεγόμενο SQL literal:

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

Εναλλακτικά:

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

SQL literal μπορεί επίσης να έχει τις παραμέτρους του:

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

Χάρη σε αυτό μπορούμε να δημιουργήσουμε ενδιαφέροντες συνδυασμούς:

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

Όνομα μεταβλητής

Υπάρχει ένα μπαλαντέρ ?name που χρησιμοποιείτε αν το όνομα του πίνακα ή της στήλης είναι μεταβλητή. (Προσοχή, μην επιτρέψετε στο χρήστη να χειριστεί το περιεχόμενο μιας τέτοιας μεταβλητής):

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

Συναλλαγές

Υπάρχουν τρεις μέθοδοι για την αντιμετώπιση των συναλλαγών:

$database->beginTransaction();

$database->commit();

$database->rollback();

Η μέθοδος transaction() προσφέρει έναν κομψό τρόπο. Περνάτε το callback που εκτελείται στη συναλλαγή. Εάν κατά την εκτέλεση εκσφενδονιστεί μια εξαίρεση, η συναλλαγή εγκαταλείπεται, ενώ εάν όλα πάνε καλά, η συναλλαγή δεσμεύεται.

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

Όπως μπορείτε να δείτε, η μέθοδος transaction() επιστρέφει την τιμή επιστροφής του callback.

Η transaction() μπορεί επίσης να είναι εμφωλευμένη, γεγονός που απλοποιεί την υλοποίηση ανεξάρτητων αποθετηρίων.

έκδοση: 4.0