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:

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";
}
versiyon: 4.0