SQL Yolu
Nette Veritabanı ile iki şekilde çalışabilirsiniz: SQL sorguları yazarak (SQL yolu) veya SQL'in otomatik olarak oluşturulmasına izin vererek(Explorer yolu). SQL yolu, yapıları üzerinde tam kontrol sahibi olurken güvenli bir şekilde sorgular oluşturmanıza olanak tanır.
Veritabanı bağlantısı kurulumu hakkında ayrıntılar için Bağlantı ve Yapılandırma bölümüne bakın.
Temel Sorgulama
query()
yöntemi veritabanı sorgularını yürütür ve sonucu temsil eden bir ResultSet nesnesi döndürür. Sorgu başarısız
olursa, yöntem bir istisna atar. Bir foreach
döngüsü
kullanarak sorgu sonucu boyunca döngü yapabilir veya yardımcı fonksiyonlardan birini
kullanabilirsiniz.
$result = $database->query('SELECT * FROM users');
foreach ($result as $row) {
echo $row->id;
echo $row->name;
}
SQL sorgularına güvenli bir şekilde değer eklemek için parametrelendirilmiş sorgular kullanın. Nette Database bunu çok basit hale getirir: SQL sorgusuna virgül ve değer eklemeniz yeterlidir.
$database->query('SELECT * FROM users WHERE name = ?', $name);
Birden fazla parametre için SQL sorgusunu parametrelerle iç içe geçirebilirsiniz:
$database->query('SELECT * FROM users WHERE name = ?', $name, 'AND age > ?', $age);
Ya da önce tüm SQL sorgusunu yazın ve ardından tüm parametreleri ekleyin:
$database->query('SELECT * FROM users WHERE name = ? AND age > ?', $name, $age);
SQL Enjeksiyonuna Karşı Koruma
Parametrelendirilmiş sorgular kullanmak neden önemlidir? Çünkü sizi, saldırganların veritabanı verilerini manipüle etmek veya bunlara erişmek için kötü niyetli SQL komutları enjekte edebildiği SQL enjeksiyon saldırılarından korurlar.
**Asla değişkenleri doğrudan bir SQL sorgusuna eklemeyin! SQL enjeksiyonuna karşı kendinizi korumak için her zaman parametrelendirilmiş sorgular kullanın.
// ❌ GÜVENLİ OLMAYAN KOD - SQL enjeksiyonuna karşı savunmasız
$database->query("SELECT * FROM users WHERE name = '$name'");
// ✅ Güvenli parametrelendirilmiş sorgu
$database->query('SELECT * FROM users WHERE name = ?', $name);
Potansiyel güvenlik riskleri hakkında bilgi sahibi olduğunuzdan emin olun.
Sorgu Teknikleri
NEREDE Koşullar
WHERE
koşullarını, anahtarların sütun adları ve değerlerin karşılaştırılacak veriler olduğu bir
ilişkisel dizi olarak yazabilirsiniz. Nette Database, değer türüne göre en uygun SQL operatörünü otomatik
olarak seçer.
$database->query('SELECT * FROM users WHERE', [
'name' => 'John',
'active' => true,
]);
// WHERE `name` = 'John' AND `active` = 1
Operatörü anahtarda açıkça da belirtebilirsiniz:
$database->query('SELECT * FROM users WHERE', [
'age >' => 25, // > operatörünü kullanır
'name LIKE' => '%John%', // LIKE operatörünü kullanır
'email NOT LIKE' => '%example.com%', // NOT LIKE işlecini kullanır
]);
// WHERE `age` > 25 AND `name` LIKE '%John%' AND `email` NOT LIKE '%example.com%'
null
değerleri veya diziler gibi özel durumlar otomatik olarak ele alınır:
$database->query('SELECT * FROM products WHERE', [
'name' => 'Laptop', // = operatörünü kullanır
'category_id' => [1, 2, 3], // IN kullanır
'description' => null, // kullanır IS NULL
]);
// WHERE `name` = 'Laptop' AND `category_id` IN (1, 2, 3) AND `description` IS NULL
Negatif koşullar için NOT
operatörünü kullanın:
$database->query('SELECT * FROM products WHERE', [
'name NOT' => 'Laptop', // <> operatörünü kullanır
'category_id NOT' => [1, 2, 3], // NOT IN kullanır
'description NOT' => null, // uses IS NOT NULL
'id' => [], // atlandı
]);
// WHERE `name` <> 'Laptop' AND `category_id` NOT IN (1, 2, 3) AND `description` IS NOT NULL
Varsayılan olarak, koşullar AND
operatörü kullanılarak birleştirilir. Bu davranışı ?or yer tutucusunu kullanarak değiştirebilirsiniz.
ORDER BY Kurallar
ORDER BY
cümlesi, anahtarların sütunları temsil ettiği ve değerlerin artan sırayı gösteren boolean'lar
olduğu bir dizi olarak tanımlanabilir:
$database->query('SELECT id FROM author ORDER BY', [
'id' => true, // artan
'name' => false, // azalan
]);
// SELECT id FROM author ORDER BY `id`, `name` DESC
Veri Ekleme (INSERT)
Kayıt eklemek için SQL INSERT
deyimini kullanın.
$values = [
'name' => 'John Doe',
'email' => 'john@example.com',
];
$database->query('INSERT INTO users ?', $values);
$userId = $database->getInsertId();
getInsertId()
yöntemi, son eklenen satırın kimliğini döndürür. Bazı veritabanları için (örneğin
PostgreSQL), $database->getInsertId($sequenceId)
adresini kullanarak sıra adını belirtmeniz gerekir.
Dosyalar, DateTime nesneleri veya enum türleri gibi özel değerleri de parametre olarak aktarabilirsiniz.
Aynı anda birden fazla kayıt ekleme:
$database->query('INSERT INTO users ?', [
['name' => 'User 1', 'email' => 'user1@mail.com'],
['name' => 'User 2', 'email' => 'user2@mail.com'],
]);
Toplu INSERT gerçekleştirmek çok daha hızlıdır çünkü birden fazla ayrı sorgu yerine yalnızca tek bir veritabanı sorgusu yürütülür.
Güvenlik Notu: Doğrulanmamış verileri asla $values
olarak kullanmayın. Olası riskler hakkında bilgi edinin.
Veri Güncelleme (UPDATE)
Kayıtları güncellemek için SQL UPDATE
deyimini kullanın.
// Tek bir kaydı güncelleme
$values = [
'name' => 'John Smith',
];
$result = $database->query('UPDATE users SET ? WHERE id = ?', $values, 1);
Etkilenen satır sayısını $result->getRowCount()
adresini kullanarak kontrol edebilirsiniz.
+=
ve -=
operatörlerini UPDATE
adresinde kullanabilirsiniz:
$database->query('UPDATE users SET ? WHERE id = ?', [
'login_count+=' => 1, // increment login_count
], 1);
Zaten mevcut olan bir kaydı eklemek veya güncellemek için ON DUPLICATE KEY UPDATE
tekniğini kullanın:
$values = [
'name' => $name,
'year' => $year,
];
$database->query('INSERT INTO users ? ON DUPLICATE KEY UPDATE ?',
$values + ['id' => $id],
$values,
);
// INSERT INTO users (`id`, `name`, `year`) VALUES (123, 'Jim', 1978)
// ON DUPLICATE KEY UPDATE `name` = 'Jim', `year` = 1978
Nette Database'in dizi içeren bir parametrenin kullanıldığı SQL komutunun bağlamını tanıdığını ve SQL kodunu buna
göre oluşturduğunu unutmayın. Örneğin, ilk diziden (id, name, year) VALUES (123, 'Jim', 1978)
oluştururken,
ikincisini name = 'Jim', year = 1978
'a dönüştürür. Bu konu SQL oluşturmak
için ipuçları bölümünde daha ayrıntılı olarak ele alınmaktadır.
Veri Silme (DELETE)
Kayıtları silmek için SQL DELETE
deyimini kullanın. Silinen satır sayısı ile örnek:
$count = $database->query('DELETE FROM users WHERE id = ?', 1)
->getRowCount();
SQL Oluşturma İpuçları
SQL yer tutucuları, parametre değerlerinin SQL ifadelerine nasıl dahil edileceğini kontrol etmenize olanak tanır:
İpucu | Açıklama | Otomatik Olarak Şunun İçin Kullanılır |
---|---|---|
?name |
Tablo veya sütun adları için kullanılır | – |
?values |
(key, ...) VALUES (value, ...) |
INSERT ... ? oluşturur, REPLACE ... ? |
?set |
Atamaları oluşturur key = value, ... |
SET ? , KEY UPDATE ? |
?and |
Bir dizideki koşulları AND |
WHERE ? ile birleştirir, HAVING ? |
?or |
Bir dizideki koşulları OR ile birleştirir |
– |
?order |
ORDER BY cümlesini oluşturur |
ORDER BY ? , GROUP BY ? |
Tablo veya sütun adlarını dinamik olarak eklemek için ?name
yer tutucusunu kullanın. Nette Veritabanı,
veritabanının kurallarına göre uygun kaçış sağlar (örneğin, MySQL için backtick içine alma).
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name WHERE id = 1', $column, $table);
// SELECT `name` FROM `users` WHERE id = 1 (MySQL'de)
Uyarı: ?name
yer tutucusunu yalnızca doğrulanmış tablo ve sütun adları için kullanın. Aksi
takdirde, güvenlik açıkları riskiyle karşı
karşıya kalırsınız.
Nette SQL sorgularını oluştururken akıllı otomatik algılama kullandığından (tablonun üçüncü sütununa bakın)
diğer ipuçlarını belirtmek genellikle gerekli değildir. Ancak, AND
yerine OR
kullanarak koşulları
birleştirmek istediğiniz durumlarda bunları kullanabilirsiniz:
$database->query('SELECT * FROM users WHERE ?or', [
'name' => 'John',
'email' => 'john@example.com',
]);
// SELECT * FROM users WHERE `name` = 'John' OR `email` = 'john@example.com'
Özel Değerler
Standart skaler tiplere (örneğin, string
, int
, bool
) ek olarak, özel değerleri de
parametre olarak aktarabilirsiniz:
- Dosyalar: Bir dosyanın ikili içeriğini eklemek için
fopen('file.png', 'r')
adresini kullanın. - Tarih ve Saat:
DateTime
nesneleri otomatik olarak veritabanının tarih biçimine dönüştürülür. - Enum Değerleri:
enum
örnekleri karşılık gelen değerlerine dönüştürülür. - SQL Literals:
Connection::literal('NOW()')
kullanılarak oluşturulan bunlar doğrudan sorguya eklenir.
$database->query('INSERT INTO articles ?', [
'title' => 'My Article',
'published_at' => new DateTime,
'content' => fopen('image.png', 'r'),
'state' => Status::Draft,
]);
datetime
türü için yerel desteği olmayan veritabanları için (örneğin, SQLite ve Oracle),
DateTime
değerleri formatDateTime
yapılandırma seçeneğine göre dönüştürülür (varsayılan:
Unix zaman damgası için U
).
SQL Literatürleri
Bazı durumlarda, ham SQL kodunu bir dize olarak ele almadan veya kaçış yapmadan bir değer olarak eklemeniz gerekebilir.
Bunun için, Connection::literal()
yöntemi kullanılarak oluşturulabilen Nette\Database\SqlLiteral
sınıfının nesnelerini kullanın.
$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 değişmezleri parametre de içerebilir:
$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, esnek kombinasyonlara olanak sağlar:
$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')
Veri Getirme
SELECT Sorguları için Kısayollar
Veri alımını basitleştirmek için Connection
sınıfı, query()
çağrısını sonraki bir
fetch*()
çağrısıyla birleştiren birkaç kısayol sağlar. Bu yöntemler query()
ile aynı
parametreleri, yani bir SQL sorgusu ve isteğe bağlı parametreleri kabul eder.
fetch*()
yöntemlerinin ayrıntılı bir açıklaması aşağıda bulunabilir.
fetch($sql, ...$params): ?Row |
Sorguyu çalıştırır ve ilk satırı bir Row nesnesi olarak getirir. |
fetchAll($sql, ...$params): array |
Sorguyu çalıştırır ve tüm satırları Row nesnelerinden oluşan bir dizi olarak getirir. |
fetchPairs($sql, ...$params): array |
Sorguyu çalıştırır ve ilk sütunun anahtar, ikincisinin değer olduğu bir ilişkisel dizi getirir. |
fetchField($sql, ...$params): mixed |
Sorguyu çalıştırır ve ilk satırdaki ilk hücrenin değerini getirir. |
fetchList($sql, ...$params): ?array |
Sorguyu yürütür ve ilk satırı dizinlenmiş bir dizi olarak getirir. |
Örnek:
// fetchField() - ilk hücrenin değerini döndürür
$count = $database->query('SELECT COUNT(*) FROM articles')
->fetchField();
foreach
– Satırlar Üzerinde Yineleme
Bir sorgu yürütüldükten sonra, sonuçlar üzerinde çeşitli şekillerde yineleme yapmanıza olanak tanıyan bir ResultSet nesnesi döndürülür. Satırları
getirmenin en basit ve bellek açısından en verimli yolu, bir foreach
döngüsünde yinelemektir. Bu yöntem
satırları teker teker işler ve tüm verilerin bir kerede bellekte depolanmasını önler.
$result = $database->query('SELECT * FROM users');
foreach ($result as $row) {
echo $row->id;
echo $row->name;
//...
}
ResultSet
yalnızca bir kez yinelenebilir. Üzerinde birden çok kez yineleme yapmanız gerekiyorsa,
önce verileri bir diziye yüklemeniz, örneğin fetchAll()
yöntemini kullanmanız gerekir.
fetch(): ?Row
Sorguyu çalıştırır ve Row
nesnesi olarak tek bir satır getirir. Başka satır yoksa null
döndürür. Bu yöntem dahili işaretçiyi bir sonraki satıra ilerletir.
$result = $database->query('SELECT * FROM users');
$row = $result->fetch(); // ilk satırı getirir
if ($row) {
echo $row->name;
}
fetchAll(): array
Kalan tüm satırları ResultSet
adresinden Row
nesnelerinden oluşan bir dizi olarak getirir.
$result = $database->query('SELECT * FROM users');
$rows = $result->fetchAll(); // tüm satırları getirir
foreach ($rows as $row) {
echo $row->name;
}
fetchPairs (string|int|null $key = null, string|int|null $value = null): array
Sonuçları ilişkisel bir dizi olarak getirir. İlk bağımsız değişken anahtar olarak kullanılacak sütunu, ikincisi ise değer olarak kullanılacak sütunu belirtir:
$result = $database->query('SELECT id, name FROM users');
$names = $result->fetchPairs('id', 'name');
// [1 => 'John Doe', 2 => 'Jane Doe', ...]
Yalnızca ilk parametre sağlanırsa, değer tüm satır olacaktır (bir Row
nesnesi olarak):
$rows = $result->fetchPairs('id');
// [1 => Satır(id: 1, ad: 'John'), 2 => Satır(id: 2, ad: 'Jane'), ...]
Anahtar olarak null
geçilirse, dizi sıfırdan başlayarak sayısal olarak indekslenecektir:
$names = $result->fetchPairs(null, 'name');
// [0 => 'John Doe', 1 => 'Jane Doe', ...]
fetchPairs (Closure $callback): array
Alternatif olarak, her satır için anahtar-değer çiftlerini veya değerleri belirleyen bir geri arama sağlayabilirsiniz.
$result = $database->query('SELECT * FROM users');
$items = $result->fetchPairs(fn($row) => "$row->id - $row->name");
// ['1 - John', '2 - Jane', ...]
// Geri arama ayrıca anahtar ve değer çifti içeren bir dizi de döndürebilir:
$names = $result->fetchPairs(fn($row) => [$row->name, $row->age]);
// ['John' => 46, 'Jane' => 21, ...]
fetchField(): mixed
Geçerli satırdaki ilk hücrenin değerini getirir. Daha fazla satır yoksa, null
döndürür. Bu yöntem dahili
işaretçiyi bir sonraki satıra ilerletir.
$result = $database->query('SELECT name FROM users');
$name = $result->fetchField(); // ilk satırdaki adı getirir
fetchList(): ?array
Satırı indeksli bir dizi olarak getirir. Daha fazla satır yoksa, null
döndürür. Bu yöntem dahili
işaretçiyi bir sonraki satıra ilerletir.
$result = $database->query('SELECT name, email FROM users');
$row = $result->fetchList(); // ['John', 'john@example.com']
getRowCount(): ?int
Son UPDATE
veya DELETE
sorgusundan etkilenen satır sayısını döndürür. SELECT
sorguları için getirilen satır sayısını döndürür, ancak bu her zaman bilinmeyebilir; bu gibi durumlarda null
döndürür.
getColumnCount(): ?int
ResultSet
adresindeki sütun sayısını döndürür.
Sorgu Bilgileri
En son yürütülen sorgu hakkındaki ayrıntıları almak için şunu kullanın:
echo $database->getLastQueryString(); // SQL sorgusunu çıktılar
$result = $database->query('SELECT * FROM articles');
echo $result->getQueryString(); // SQL sorgusunu çıktılar
echo $result->getTime(); // saniye cinsinden yürütme süresini verir
Sonucu bir HTML tablosu olarak görüntülemek için şunu kullanın:
$result = $database->query('SELECT * FROM articles');
$result->dump();
Sütun türleri hakkındaki bilgileri ResultSet
adresinden de alabilirsiniz:
$result = $database->query('SELECT * FROM articles');
$types = $result->getColumnTypes();
foreach ($types as $column => $type) {
echo "$column is of type $type->type"; // örneğin, 'id int türündedir'
}
Sorgu Günlüğü
Özel sorgu günlüğü uygulayabilirsiniz. onQuery
olayı, her sorgu yürütüldükten sonra çağrılan bir geri
çağırma dizisidir:
$database->onQuery[] = function ($database, $result) use ($logger) {
$logger->info('Query: ' . $result->getQueryString());
$logger->info('Time: ' . $result->getTime());
if ($result->getRowCount() > 1000) {
$logger->warning('Large result set: ' . $result->getRowCount() . ' rows');
}
};