Veritabanı Çekirdeği
Nette Database Core, veritabanı soyutlama katmanıdır ve temel işlevsellik sağlar.
Kurulum
Composer'ı kullanarak paketi indirin ve yükleyin:
composer require nette/database
Bağlantı ve Yapılandırma
Veritabanına bağlanmak için Nette\Database\Connection sınıfının bir örneğini oluşturmanız yeterlidir:
$database = new Nette\Database\Connection($dsn, $user, $password);
$dsn
(veri kaynağı adı) parametresi PDO tarafından kullanılanla
aynıdır, örneğin host=127.0.0.1;dbname=test
. Başarısızlık durumunda
Nette\Database\ConnectionException
atar.
Ancak, daha sofistike bir yol uygulama yapılandırması sunar.
Bir database
bölümü ekleyeceğiz ve Tracy çubuğunda gerekli nesneleri
ve bir veritabanı paneli oluşturacak.
database:
dsn: 'mysql:host=127.0.0.1;dbname=test'
user: root
password: password
Örneğin bir DI konteynerinden servis olarak aldığımız bağlantı nesnesi:
class Model
{
// Veritabanı Gezgini katmanı ile çalışmak için Nette\Database\Explorer'ı geçirin
public function __construct(
private Nette\Database\Connection $database,
) {
}
}
Daha fazla bilgi için, bkz. veritabanı yapılandırması.
Sorgular
Veritabanını sorgulamak için ResultSet
döndüren query()
yöntemini kullanın.
$result = $database->query('SELECT * FROM users');
foreach ($result as $row) {
echo $row->id;
echo $row->name;
}
echo $result->getRowCount(); // biliniyorsa satır sayısını döndürür
ResultSet
üzerinden sadece bir kez yineleme yapmak mümkündür, birden fazla kez yineleme yapmamız
gerekirse fetchAll()
metodu ile sonucu diziye dönüştürmek gerekir.
Sorguya kolayca parametre ekleyebilirsiniz, soru işaretine dikkat edin:
$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 bir dizidir
UYARI, SQL enjeksiyonu açığından kaçınmak için asla dizeleri birleştirmeyin!
$db->query('SELECT * FROM users WHERE name = ' . $name); // WRONG!!!
Başarısızlık durumunda query()
, Nette\Database\DriverException
ya da onun soyundan gelenlerden
birini fırlatır:
- ConstraintViolationException – herhangi bir kısıtlamanın ihlali
- ForeignKeyConstraintViolationException – geçersiz yabancı anahtar
- NotNullConstraintViolationException – NOT NULL koşulunun ihlali
- UniqueConstraintViolationException – benzersiz dizin çakışması
query()
adresine ek olarak, başka faydalı yöntemler de vardır:
// id => name ilişkisel dizisini döndürür
$pairs = $database->fetchPairs('SELECT id, name FROM users');
// tüm satırları dizi olarak döndürür
$rows = $database->fetchAll('SELECT * FROM users');
// tek satır döndürür
$row = $database->fetch('SELECT * FROM users WHERE id = ?', $id);
// tek alan döndür
$name = $database->fetchField('SELECT name FROM users WHERE id = ?', $id);
Başarısızlık durumunda, tüm bu yöntemler Nette\Database\DriverException.
Ekle, Güncelle ve Sil
SQL sorgusuna eklediğimiz parametre dizi de olabilir (bu durumda joker karakter ?
), which may be useful for the
INSERT
ifadesini atlamak mümkündür:
$database->query('INSERT INTO users ?', [ // burada soru işareti atlanabilir
'name' => $name,
'year' => $year,
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978)
$id = $database->getInsertId(); // eklenen satırın otomatik artışını döndürür
id = $database->getInsertId($sequence); // veya sıra değeri
Çoklu ekleme:
$database->query('INSERT INTO users', [
[
'name' => 'Jim',
'year' => 1978,
], [
'name' => 'Jack',
'year' => 1987,
],
]);
// INSERT INTO users (`name`, `year`) VALUES ('Jim', 1978), ('Jack', 1987)
Ayrıca dosyaları, DateTime nesnelerini veya numaralandırmaları da aktarabiliriz:
$database->query('INSERT INTO users', [
'name' => $name,
'created' => new DateTime, // or $database::literal('NOW()')
'avatar' => fopen('image.gif', 'r'), // inserts file contents
'status' => State::New, // enum State
]);
Satırlar güncelleniyor:
$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(); // etkilenen satır sayısını döndürür
UPDATE için +=
ve -=
operatörlerini kullanabiliriz:
$database->query('UPDATE users SET', [
'age+=' => 1, // note +=
], 'WHERE id = ?', $id);
// UPDATE users SET `age` = `age` + 1
Siliniyor:
$result = $database->query('DELETE FROM users WHERE id = ?', $id);
echo $result->getRowCount(); // etkilenen satır sayısını döndürür
Gelişmiş Sorgular
Zaten mevcutsa ekleyin veya güncelleyin:
$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'in dizi parametresinin eklendiği SQL bağlamını tanıdığını ve SQL kodunu buna göre oluşturduğunu
unutmayın. Böylece, ilk diziden (id, name, year) VALUES (123, 'Jim', 1978)
üretirken, ikincisini
name = 'Jim', year = 1978
'a dönüştürür.
Sıralamayı dizi kullanarak da tanımlayabiliriz, anahtarlar sütun adlarıdır ve değerler artan sırada sıralanıp sıralanmayacağını belirleyen boolean'dır:
$database->query('SELECT id FROM author ORDER BY', [
'id' => true, // artan
'name' => false, // azalan
]);
// SELECT id FROM author ORDER BY `id`, `name` DESC
Algılama işe yaramadıysa, derlemenin biçimini bir joker karakter ?
ve ardından bir ipucu ile
belirtebilirsiniz. Bu ipuçları desteklenir:
?values | (key1, key2, …) VALUES (value1, value2, …) |
?set | anahtar1 = değer1, anahtar2 = değer2, … |
?ve | anahtar1 = değer1 VE anahtar2 = değer2 … |
?or | key1 = value1 OR key2 = value2 … |
?order | key1 ASC, key2 DESC |
WHERE cümlesi ?and
operatörünü kullanır, böylece koşullar AND
ile birbirine bağlanır:
$result = $database->query('SELECT * FROM users WHERE', [
'name' => $name,
'year' => $year,
]);
// SELECT * FROM users WHERE `name` = 'Jim' AND `year` = 1978
Bu, ?or
joker karakteri kullanılarak kolayca OR
olarak değiştirilebilir:
$result = $database->query('SELECT * FROM users WHERE ?or', [
'name' => $name,
'year' => $year,
]);
// SELECT * FROM users WHERE `name` = 'Jim' OR `year` = 1978
Operatörleri koşullar içinde kullanabiliriz:
$result = $database->query('SELECT * FROM users WHERE', [
'name <>' => $name,
'year >' => $year,
]);
// SELECT * FROM users WHERE `name` <> 'Jim' AND `year` > 1978
Ve ayrıca numaralandırmalar:
$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')
Ayrıca SQL literal olarak adlandırılan özel bir SQL kodu parçası da ekleyebiliriz:
$result = $database->query('SELECT * FROM users WHERE', [
'name' => $name,
'year >' => $database::literal('YEAR()'),
]);
// SELECT * FROM users WHERE (`name` = 'Jim') AND (`year` > YEAR())
Alternatif olarak:
$result = $database->query('SELECT * FROM users WHERE', [
'name' => $name,
$database::literal('year > YEAR()'),
]);
// SELECT * FROM users WHERE (`name` = 'Jim') AND (year > YEAR())
SQL literalinin parametreleri de olabilir:
$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)
Bu sayede ilginç kombinasyonlar yaratabiliriz:
$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')
Değişken Adı
Tablo adı veya sütun adı bir değişken ise kullanabileceğiniz bir ?name
joker karakteri vardır. (Dikkat
edin, kullanıcının böyle bir değişkenin içeriğini değiştirmesine izin vermeyin):
$table = 'blog.users';
$column = 'name';
$database->query('SELECT * FROM ?name WHERE ?name = ?', $table, $column, $name);
// SELECT * FROM `blog`.`users` WHERE `name` = 'Jim'
İşlemler
İşlemlerle ilgilenmek için üç yöntem vardır:
$database->beginTransaction();
$database->commit();
$database->rollback();
transaction()
yöntemi zarif bir yol sunar. Transaction içinde çalıştırılan geri çağırmayı iletirsiniz.
Yürütme sırasında bir istisna atılırsa, işlem düşürülür, her şey yolunda giderse işlem işlenir.
$id = $database->transaction(function ($database) {
$database->query('DELETE FROM ...');
$database->query('INSERT INTO ...');
// ...
return $database->getInsertId();
});
Gördüğünüz gibi, transaction()
yöntemi geri aramanın dönüş değerini döndürür.
transaction() da iç içe geçebilir, bu da bağımsız depoların uygulanmasını basitleştirir.
Yansıma
Nette Database, Nette\Database\Reflection sınıfı aracılığıyla veritabanı yapısını incelemek için araçlar sağlar. Bu sınıf tablolar, sütunlar, dizinler ve yabancı anahtarlar hakkında bilgi almanızı sağlar. Yansımayı şemalar oluşturmak, veritabanlarıyla çalışan esnek uygulamalar oluşturmak veya genel veritabanı araçları oluşturmak için kullanabilirsiniz.
Bir veritabanı bağlantı örneğinden bir yansıma nesnesi elde edebilirsiniz:
$reflection = $database->getReflection();
Tablolarla Çalışma
Yansımayı kullanarak, veritabanındaki tüm tablolar üzerinde yineleme yapabilirsiniz:
// Tüm tabloların adlarını listeleyin
foreach ($reflection->tables as $tableName => $table) {
echo $tableName . "\n";
}
// Bir tablonun var olup olmadığını kontrol edin
if ($reflection->hasTable('users')) {
echo "The 'users' table exists";
}
// Belirli bir tabloyu alma
$table = $reflection->getTable('users');
Kolon Bilgileri
Her tablo için sütunları hakkında ayrıntılı bilgi alabilirsiniz:
// Tüm sütunlar üzerinde yinele
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";
}
// Belirli bir sütunu alma
$idColumn = $table->getColumn('id');
Dizinler ve Birincil Anahtarlar
Reflection, dizinler ve birincil anahtarlar hakkında bilgi sağlar:
$listColumnNames = fn(array $columns) => implode(', ', array_map(fn($col) => $col->name, $columns));
// Tüm dizinleri listele
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";
}
// Birincil anahtarı al
if ($table->primaryKey) {
echo "Primary key: " . $listColumnNames($table->primaryKey->columns) . "\n";
}
Yabancı Anahtarlar
Yabancı anahtarlar hakkında da bilgi alabilirsiniz:
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";
}