Database Explorer
Explorer, veritabanıyla çalışmak için sezgisel ve etkili bir yol sunar. Tablolar arasındaki ilişkileri ve sorgu optimizasyonunu otomatik olarak halleder, böylece uygulamanıza odaklanabilirsiniz. Ayarlama yapmadan hemen çalışır. SQL sorguları üzerinde tam kontrol sahibi olmanız gerekiyorsa, SQL yaklaşımını kullanabilirsiniz.
- Verilerle çalışmak doğal ve anlaşılması kolaydır
- Yalnızca gerekli verileri yükleyen optimize edilmiş SQL sorguları oluşturur
- JOIN sorguları yazmaya gerek kalmadan ilgili verilere kolay erişim sağlar
- Herhangi bir yapılandırma veya varlık oluşturma olmadan anında çalışır
Explorer ile Nette\Database\Explorer
nesnesinin table()
metodunu çağırarak başlarsınız (bağlantı ayrıntıları Bağlantı ve yapılandırma bölümünde
bulunabilir):
$books = $explorer->table('book'); // 'book' tablo adıdır
Metot, bir SQL sorgusunu temsil eden bir Selection nesnesi döndürür. Sonuçları
filtrelemek ve sıralamak için bu nesneye ek metotlar zincirleyebiliriz. Sorgu, veri talep etmeye başladığımızda
oluşturulur ve yürütülür. Örneğin, bir foreach
döngüsüyle. Her satır bir ActiveRow nesnesiyle temsil edilir:
foreach ($books as $book) {
echo $book->title; // 'title' sütununu yazdır
echo $book->author_id; // 'author_id' sütununu yazdır
}
Explorer, tablolar arasındaki ilişkilerle çalışmayı önemli ölçüde kolaylaştırır. Aşağıdaki örnek, ilişkili tablolardan (kitaplar ve yazarları) verilerin ne kadar kolay listelenebileceğini gösterir. Herhangi bir JOIN sorgusu yazmamıza gerek olmadığına dikkat edin, Nette bunları bizim için oluşturur:
$books = $explorer->table('book');
foreach ($books as $book) {
echo 'Kitap: ' . $book->title;
echo 'Yazar: ' . $book->author->name; // 'author' tablosuna JOIN oluşturur
}
Nette Database Explorer, sorguları mümkün olduğunca verimli olacak şekilde optimize eder. Yukarıdaki örnek, 10 veya 10.000 kitap işliyor olsak da yalnızca iki SELECT sorgusu gerçekleştirir.
Ek olarak, Explorer kodda hangi sütunların kullanıldığını izler ve veritabanından yalnızca bunları yükleyerek daha fazla performans tasarrufu sağlar. Bu davranış tamamen otomatik ve uyarlanabilirdir. Daha sonra kodu değiştirir ve ek sütunlar kullanmaya başlarsanız, Explorer sorguları otomatik olarak ayarlar. Hiçbir şey ayarlamanıza veya hangi sütunlara ihtiyacınız olacağını düşünmenize gerek yok – bırakın Nette halletsin.
Filtreleme ve sıralama
Selection
sınıfı, veri seçimini filtrelemek ve sıralamak için metotlar sağlar.
where($condition, ...$params) |
WHERE koşulu ekler. Birden çok koşul AND operatörü ile birleştirilir |
whereOr(array $conditions) |
OR operatörü ile birleştirilmiş bir WHERE koşulları grubu ekler |
wherePrimary($value) |
Birincil anahtara göre WHERE koşulu ekler |
order($columns, ...$params) |
ORDER BY sıralamasını ayarlar |
select($columns, ...$params) |
Yüklenecek sütunları belirtir |
limit($limit, $offset = null) |
Satır sayısını sınırlar (LIMIT) ve isteğe bağlı olarak OFFSET ayarlar |
page($page, $itemsPerPage, &$total = null) |
Sayfalamayı ayarlar |
group($columns, ...$params) |
Satırları gruplar (GROUP BY) |
having($condition, ...$params) |
Gruplanmış satırları filtrelemek için HAVING koşulu ekler |
Metotlar zincirlenebilir (sözde akıcı arayüz):
$table->where(...)->order(...)->limit(...)
.
Bu metotlarda, ilişkili tablolardaki verilere erişmek için özel bir gösterim de kullanabilirsiniz.
Kaçış ve tanımlayıcılar
Metotlar parametreleri otomatik olarak kaçar ve tanımlayıcıları (tablo ve sütun adları) tırnak içine alır, böylece SQL injection'u önler. Doğru çalışması için birkaç kurala uymak gerekir:
- Anahtar kelimeleri, fonksiyon adlarını, prosedürleri vb. büyük harflerle yazın.
- Sütun ve tablo adlarını küçük harflerle yazın.
- Karakter dizilerini her zaman parametreler aracılığıyla ekleyin.
where('name = ' . $name); // KRİTİK GÜVENLİK AÇIĞI: SQL injection
where('name LIKE "%search%"'); // YANLIŞ: otomatik tırnak içine almayı zorlaştırır
where('name LIKE ?', '%search%'); // DOĞRU: parametre aracılığıyla eklenen değer
where('name like ?', $name); // YANLIŞ: `name` `like` ? oluşturur
where('name LIKE ?', $name); // DOĞRU: `name` LIKE ? oluşturur
where('LOWER(name) = ?', $value);// DOĞRU: LOWER(`name`) = ? oluşturur
where (string|array $condition, …$parameters): static
Sonuçları WHERE koşullarıyla filtreler. Güçlü yanı, farklı değer tipleriyle akıllıca çalışması ve SQL operatörlerini otomatik olarak seçmesidir.
Temel kullanım:
$table->where('id', $value); // WHERE `id` = 123
$table->where('id > ?', $value); // WHERE `id` > 123
$table->where('id = ? OR name = ?', $id, $name); // WHERE `id` = 1 OR `name` = 'Jon Snow'
Uygun operatörlerin otomatik olarak algılanması sayesinde, farklı özel durumlarla uğraşmamıza gerek kalmaz. Nette bunları bizim için halleder:
$table->where('id', 1); // WHERE `id` = 1
$table->where('id', null); // WHERE `id` IS NULL
$table->where('id', [1, 2, 3]); // WHERE `id` IN (1, 2, 3)
// operatör olmadan yer tutucu soru işareti de kullanılabilir:
$table->where('id ?', 1); // WHERE `id` = 1
Metot, negatif koşulları ve boş dizileri de doğru şekilde işler:
$table->where('id', []); // WHERE `id` IS NULL AND FALSE -- hiçbir şey bulmaz
$table->where('id NOT', []); // WHERE `id` IS NULL OR TRUE -- her şeyi bulur
$table->where('NOT (id ?)', []); // WHERE NOT (`id` IS NULL AND FALSE) -- her şeyi bulur
// $table->where('NOT id ?', $ids); Dikkat - bu sözdizimi desteklenmiyor
Parametre olarak başka bir tablodan sonuç da iletebiliriz – bir alt sorgu oluşturulur:
// WHERE `id` IN (SELECT `id` FROM `tableName`)
$table->where('id', $explorer->table($tableName));
// WHERE `id` IN (SELECT `col` FROM `tableName`)
$table->where('id', $explorer->table($tableName)->select('col'));
Koşulları, öğeleri AND ile birleştirilecek bir dizi olarak da iletebiliriz:
// WHERE (`price_final` < `price_original`) AND (`stock_count` > `min_stock`)
$table->where([
'price_final < price_original',
'stock_count > min_stock',
]);
Dizide anahtar ⇒ değer çiftleri kullanabiliriz ve Nette yine doğru operatörleri otomatik olarak seçer:
// WHERE (`status` = 'active') AND (`id` IN (1, 2, 3))
$table->where([
'status' => 'active',
'id' => [1, 2, 3],
]);
Dizide, yer tutucu soru işaretleri ve birden çok parametre içeren SQL ifadelerini birleştirebiliriz. Bu, tam olarak tanımlanmış operatörlere sahip karmaşık koşullar için uygundur:
// WHERE (`age` > 18) AND (ROUND(`score`, 2) > 75.5)
$table->where([
'age > ?' => 18,
'ROUND(score, ?) > ?' => [2, 75.5], // iki parametreyi dizi olarak iletiriz
]);
Birden çok where()
çağrısı, koşulları otomatik olarak AND ile birleştirir.
whereOr (array $parameters): static
where()
gibi koşullar ekler, ancak farkı bunları OR kullanarak birleştirmesidir:
// WHERE (`status` = 'active') OR (`deleted` = 1)
$table->whereOr([
'status' => 'active',
'deleted' => true,
]);
Burada da daha karmaşık ifadeler kullanabiliriz:
// WHERE (`price` > 1000) OR (`price_with_tax` > 1500)
$table->whereOr([
'price > ?' => 1000,
'price_with_tax > ?' => 1500,
]);
wherePrimary (mixed $key): static
Tablonun birincil anahtarı için bir koşul ekler:
// WHERE `id` = 123
$table->wherePrimary(123);
// WHERE `id` IN (1, 2, 3)
$table->wherePrimary([1, 2, 3]);
Tablonun bileşik bir birincil anahtarı varsa (örneğin foo_id
, bar_id
), bunu bir dizi olarak
iletiriz:
// WHERE `foo_id` = 1 AND `bar_id` = 5
$table->wherePrimary(['foo_id' => 1, 'bar_id' => 5])->fetch();
// WHERE (`foo_id`, `bar_id`) IN ((1, 5), (2, 3))
$table->wherePrimary([
['foo_id' => 1, 'bar_id' => 5],
['foo_id' => 2, 'bar_id' => 3],
])->fetchAll();
order (string $columns, …$parameters): static
Satırların döndürüleceği sırayı belirler. Bir veya daha fazla sütuna göre, azalan veya artan sırada veya özel bir ifadeye göre sıralayabiliriz:
$table->order('created'); // ORDER BY `created`
$table->order('created DESC'); // ORDER BY `created` DESC
$table->order('priority DESC, created'); // ORDER BY `priority` DESC, `created`
$table->order('status = ? DESC', 'active'); // ORDER BY `status` = 'active' DESC
select (string $columns, …$parameters): static
Veritabanından döndürülecek sütunları belirtir. Varsayılan olarak, Nette Database Explorer yalnızca kodda gerçekten
kullanılan sütunları döndürür. Bu nedenle select()
metodunu, belirli ifadeleri döndürmemiz gereken durumlarda
kullanırız:
// SELECT *, DATE_FORMAT(`created_at`, "%d.%m.%Y") AS `formatted_date`
$table->select('*, DATE_FORMAT(created_at, ?) AS formatted_date', '%d.%m.%Y');
AS
ile tanımlanan takma adlar daha sonra ActiveRow nesnesinin özellikleri olarak kullanılabilir:
foreach ($table as $row) {
echo $row->formatted_date; // takma ada erişim
}
limit (?int $limit, ?int $offset = null): static
Döndürülen satır sayısını sınırlar (LIMIT) ve isteğe bağlı olarak bir ofset ayarlamaya izin verir:
$table->limit(10); // LIMIT 10 (ilk 10 satırı döndürür)
$table->limit(10, 20); // LIMIT 10 OFFSET 20
Sayfalama için page()
metodunu kullanmak daha uygundur.
page (int $page, int $itemsPerPage, &$numOfPages = null): static
Sonuçların sayfalanmasını kolaylaştırır. Sayfa numarasını (1'den başlayarak sayılır) ve sayfa başına öğe sayısını kabul eder. İsteğe bağlı olarak, toplam sayfa sayısının saklanacağı bir değişkene referans iletilebilir:
$numOfPages = null;
$table->page(page: 3, itemsPerPage: 10, $numOfPages);
echo "Toplam sayfa sayısı: $numOfPages";
group (string $columns, …$parameters): static
Satırları belirtilen sütunlara göre gruplar (GROUP BY). Genellikle toplama fonksiyonlarıyla birlikte kullanılır:
// Her kategorideki ürün sayısını sayar
$table->select('category_id, COUNT(*) AS count')
->group('category_id');
having (string $having, …$parameters): static
Gruplanmış satırları filtrelemek için bir koşul ayarlar (HAVING). group()
metodu ve toplama
fonksiyonlarıyla birlikte kullanılabilir:
// 100'den fazla ürünü olan kategorileri bulur
$table->select('category_id, COUNT(*) AS count')
->group('category_id')
->having('count > ?', 100);
Veri okuma
Veritabanından veri okumak için birkaç kullanışlı metodumuz var:
foreach ($table as $key => $row) |
Tüm satırlar üzerinde yinelenir, $key birincil anahtar değeridir, $row bir ActiveRow
nesnesidir |
$row = $table->get($key) |
Birincil anahtara göre tek bir satır döndürür |
$row = $table->fetch() |
Geçerli satırı döndürür ve işaretçiyi bir sonrakine taşır |
$array = $table->fetchPairs() |
Sonuçlardan ilişkisel bir dizi oluşturur |
$array = $table->fetchAll() |
Tüm satırları dizi olarak döndürür |
count($table) |
Selection nesnesindeki satır sayısını döndürür |
ActiveRow nesnesi yalnızca okuma amaçlıdır. Bu, özelliklerinin değerlerini değiştiremeyeceğiniz anlamına gelir. Bu kısıtlama, veri tutarlılığını sağlar ve beklenmedik yan etkileri önler. Veriler veritabanından yüklenir ve herhangi bir değişiklik açıkça ve kontrollü bir şekilde yapılmalıdır.
foreach
– tüm satırlar üzerinde yineleme
Bir sorguyu yürütmenin ve satırları almanın en kolay yolu, bir foreach
döngüsünde yinelemektir. SQL
sorgusunu otomatik olarak çalıştırır.
$books = $explorer->table('book');
foreach ($books as $key => $book) {
// $key birincil anahtar değeridir, $book ActiveRow'dur
echo "$book->title ({$book->author->name})";
}
get ($key): ?ActiveRow
SQL sorgusunu yürütür ve birincil anahtara göre satırı veya mevcut değilse null
döndürür.
$book = $explorer->table('book')->get(123); // ID 123 olan ActiveRow'u veya null döndürür
if ($book) {
echo $book->title;
}
fetch(): ?ActiveRow
Bir satır döndürür ve dahili işaretçiyi bir sonrakine taşır. Başka satır yoksa null
döndürür.
$books = $explorer->table('book');
while ($book = $books->fetch()) {
$this->processBook($book);
}
fetchPairs (string|int|null $key = null, string|int|null $value = null): array
Sonuçları ilişkisel bir dizi olarak döndürür. İlk argüman, dizide anahtar olarak kullanılacak sütun adını belirtir, ikinci argüman değer olarak kullanılacak sütun adını belirtir:
$authors = $explorer->table('author')->fetchPairs('id', 'name');
// [1 => 'John Doe', 2 => 'Jane Doe', ...]
Yalnızca ilk parametreyi belirtirsek, değer tüm satır, yani ActiveRow
nesnesi olacaktır:
$authors = $explorer->table('author')->fetchPairs('id');
// [1 => ActiveRow(id: 1, ...), 2 => ActiveRow(id: 2, ...), ...]
Yinelenen anahtarlar durumunda, son satırdan gelen değer kullanılır. Anahtar olarak null
kullanıldığında,
dizi sıfırdan başlayarak sayısal olarak dizine eklenir (o zaman çakışma olmaz):
$authors = $explorer->table('author')->fetchPairs(null, 'name');
// [0 => 'John Doe', 1 => 'Jane Doe', ...]
fetchPairs (Closure $callback): array
Alternatif olarak, parametre olarak her satır için ya değerin kendisini ya da bir anahtar-değer çiftini döndürecek bir geri arama (callback) belirtebilirsiniz.
$titles = $explorer->table('book')
->fetchPairs(fn($row) => "$row->title ({$row->author->name})");
// ['İlk kitap (Jan Novák)', ...]
// Geri arama ayrıca bir anahtar & değer çifti içeren bir dizi de döndürebilir:
$titles = $explorer->table('book')
->fetchPairs(fn($row) => [$row->title, $row->author->name]);
// ['İlk kitap' => 'Jan Novák', ...]
fetchAll(): array
Tüm satırları, anahtarların birincil anahtar değerleri olduğu ActiveRow
nesnelerinin ilişkisel bir dizisi
olarak döndürür.
$allBooks = $explorer->table('book')->fetchAll();
// [1 => ActiveRow(id: 1, ...), 2 => ActiveRow(id: 2, ...), ...]
count(): int
Parametresiz count()
metodu, Selection
nesnesindeki satır sayısını döndürür:
$table->where('category', 1);
$count = $table->count();
$count = count($table); // alternatif
Dikkat, parametreli count()
veritabanında COUNT toplama fonksiyonunu gerçekleştirir, aşağıya bakın.
ActiveRow::toArray(): array
ActiveRow
nesnesini, anahtarların sütun adları ve değerlerin karşılık gelen veriler olduğu ilişkisel bir
diziye dönüştürür.
$book = $explorer->table('book')->get(1);
$bookArray = $book->toArray();
// $bookArray ['id' => 1, 'title' => '...', 'author_id' => ..., ...] olacaktır
Toplama
Selection
sınıfı, toplama fonksiyonlarını (COUNT, SUM, MIN, MAX, AVG vb.) kolayca gerçekleştirmek için
metotlar sağlar.
count($expr) |
Satır sayısını sayar |
min($expr) |
Sütundaki minimum değeri döndürür |
max($expr) |
Sütundaki maksimum değeri döndürür |
sum($expr) |
Sütundaki değerlerin toplamını döndürür |
aggregation($function) |
Herhangi bir toplama fonksiyonunun gerçekleştirilmesini sağlar. Örn. AVG() , GROUP_CONCAT() |
count (string $expr): int
COUNT fonksiyonuyla bir SQL sorgusu gerçekleştirir ve sonucu döndürür. Metot, belirli bir koşula kaç satırın karşılık geldiğini bulmak için kullanılır:
$count = $table->count('*'); // SELECT COUNT(*) FROM `table`
$count = $table->count('DISTINCT column'); // SELECT COUNT(DISTINCT `column`) FROM `table`
Dikkat, count() parametresiz yalnızca Selection
nesnesindeki satır sayısını
döndürür.
min (string $expr) ve max(string $expr)
min()
ve max()
metotları, belirtilen sütun veya ifadedeki minimum ve maksimum değeri
döndürür:
// SELECT MAX(`price`) FROM `products` WHERE `active` = 1
$maxPrice = $products->where('active', true)
->max('price');
sum (string $expr)
Belirtilen sütun veya ifadedeki değerlerin toplamını döndürür:
// SELECT SUM(`price` * `items_in_stock`) FROM `products` WHERE `active` = 1
$totalPrice = $products->where('active', true)
->sum('price * items_in_stock');
aggregation (string $function, ?string $groupFunction = null)
Herhangi bir toplama fonksiyonunun gerçekleştirilmesini sağlar.
// kategorideki ürünlerin ortalama fiyatı
$avgPrice = $products->where('category_id', 1)
->aggregation('AVG(price)');
// ürün etiketlerini tek bir karakter dizisinde birleştirir
$tags = $products->where('id', 1)
->aggregation('GROUP_CONCAT(tag.name) AS tags')
->fetch()
->tags;
Zaten bir toplama fonksiyonu ve gruplamadan (örneğin, gruplanmış satırlar üzerinde SUM(değer)
) kaynaklanan
sonuçları toplamamız gerekiyorsa, ikinci argüman olarak bu ara sonuçlara uygulanacak toplama fonksiyonunu belirtiriz:
// Her kategori için stoktaki ürünlerin toplam fiyatını hesaplar ve ardından bu fiyatları toplar.
$totalPrice = $products->select('category_id, SUM(price * stock) AS category_total')
->group('category_id')
->aggregation('SUM(category_total)', 'SUM');
Bu örnekte, önce her kategorideki ürünlerin toplam fiyatını hesaplarız
(SUM(price * stock) AS category_total
) ve sonuçları category_id
'ye göre gruplarız. Ardından, bu ara
toplamları category_total
toplamak için aggregation('SUM(category_total)', 'SUM')
kullanırız.
İkinci argüman 'SUM'
, ara sonuçlara SUM fonksiyonunun uygulanması gerektiğini söyler.
Ekleme, Güncelleme ve Silme
Nette Database Explorer, veri eklemeyi, güncellemeyi ve silmeyi basitleştirir. Belirtilen tüm metotlar, bir hata durumunda
Nette\Database\DriverException
istisnası fırlatır.
Selection::insert (iterable $data)
Tabloya yeni kayıtlar ekler.
Tek bir kayıt ekleme:
Yeni kaydı, anahtarların tablodaki sütun adlarına karşılık geldiği ilişkisel bir dizi veya yinelenebilir bir nesne (örneğin, formlarda kullanılan ArrayHash) olarak iletiriz.
Tablonun tanımlanmış bir birincil anahtarı varsa, metot veritabanı düzeyinde yapılan olası değişiklikleri
(tetikleyiciler, varsayılan sütun değerleri, otomatik artan sütun hesaplamaları) yansıtmak için veritabanından yeniden
yüklenen bir ActiveRow
nesnesi döndürür. Bu, veri tutarlılığını sağlar ve nesne her zaman veritabanındaki
güncel verileri içerir. Benzersiz bir birincil anahtarı yoksa, iletilen verileri dizi biçiminde döndürür.
$row = $explorer->table('users')->insert([
'name' => 'John Doe',
'email' => 'john.doe@example.com',
]);
// $row, ActiveRow örneğidir ve eklenen satırın tam verilerini içerir,
// otomatik olarak oluşturulan ID ve tetikleyiciler tarafından yapılan olası değişiklikler dahil
echo $row->id; // Yeni eklenen kullanıcının ID'sini yazdırır
echo $row->created_at; // Tetikleyici tarafından ayarlandıysa oluşturma zamanını yazdırır
Aynı anda birden çok kayıt ekleme:
insert()
metodu, tek bir SQL sorgusu kullanarak birden çok kayıt eklemeye izin verir. Bu durumda, eklenen satır
sayısını döndürür.
$insertedRows = $explorer->table('users')->insert([
[
'name' => 'John',
'year' => 1994,
],
[
'name' => 'Jack',
'year' => 1995,
],
]);
// INSERT INTO `users` (`name`, `year`) VALUES ('John', 1994), ('Jack', 1995)
// $insertedRows 2 olacaktır
Parametre olarak, veri seçimi içeren bir Selection
nesnesi de iletilebilir.
$newUsers = $explorer->table('potential_users')
->where('approved', 1)
->select('name, email');
$insertedRows = $explorer->table('users')->insert($newUsers);
Özel değerler ekleme:
Değer olarak dosyaları, DateTime nesnelerini veya SQL değişmezlerini de iletebiliriz:
$explorer->table('users')->insert([
'name' => 'John',
'created_at' => new DateTime, // veritabanı formatına dönüştürür
'avatar' => fopen('image.jpg', 'rb'), // dosyanın ikili içeriğini ekler
'uuid' => $explorer::literal('UUID()'), // UUID() fonksiyonunu çağırır
]);
Selection::update (iterable $data): int
Belirtilen filtreye göre tablodaki satırları günceller. Gerçekte değiştirilen satır sayısını döndürür.
Değiştirilecek sütunları, anahtarların tablodaki sütun adlarına karşılık geldiği ilişkisel bir dizi veya yinelenebilir bir nesne (örneğin, formlarda kullanılan ArrayHash) olarak iletiriz:
$affected = $explorer->table('users')
->where('id', 10)
->update([
'name' => 'John Smith',
'year' => 1994,
]);
// UPDATE `users` SET `name` = 'John Smith', `year` = 1994 WHERE `id` = 10
Sayısal değerleri değiştirmek için +=
ve -=
operatörlerini kullanabiliriz:
$explorer->table('users')
->where('id', 10)
->update([
'points+=' => 1, // 'points' sütununun değerini 1 artırır
'coins-=' => 1, // 'coins' sütununun değerini 1 azaltır
]);
// UPDATE `users` SET `points` = `points` + 1, `coins` = `coins` - 1 WHERE `id` = 10
Selection::delete(): int
Belirtilen filtreye göre tablodan satırları siler. Silinen satır sayısını döndürür.
$count = $explorer->table('users')
->where('id', 10)
->delete();
// DELETE FROM `users` WHERE `id` = 10
update()
ve delete()
çağırırken, where()
kullanarak
değiştirilecek/silinecek satırları belirtmeyi unutmayın. where()
kullanmazsanız, işlem tüm tablo üzerinde
gerçekleştirilir!
ActiveRow::update (iterable $data): bool
ActiveRow
nesnesi tarafından temsil edilen veritabanı satırındaki verileri günceller. Parametre olarak,
güncellenecek verileri içeren yinelenebilir bir değer alır (anahtarlar sütun adlarıdır). Sayısal değerleri değiştirmek
için +=
ve -=
operatörlerini kullanabiliriz:
Güncelleme yapıldıktan sonra, ActiveRow
veritabanı düzeyinde yapılan olası değişiklikleri (örneğin
tetikleyiciler) yansıtmak için otomatik olarak veritabanından yeniden yüklenir. Metot, yalnızca verilerde gerçek bir
değişiklik yapıldıysa true döndürür.
$article = $explorer->table('article')->get(1);
$article->update([
'views += 1', // görüntülenme sayısını artırırız
]);
echo $article->views; // Geçerli görüntülenme sayısını yazdırır
Bu metot, veritabanındaki yalnızca belirli bir satırı günceller. Birden çok satırı toplu olarak güncellemek için Selection::update() metodunu kullanın.
ActiveRow::delete()
ActiveRow
nesnesi tarafından temsil edilen satırı veritabanından siler.
$book = $explorer->table('book')->get(1);
$book->delete(); // ID 1 olan kitabı siler
Bu metot, veritabanındaki yalnızca belirli bir satırı siler. Birden çok satırı toplu olarak silmek için Selection::delete() metodunu kullanın.
Tablolar arasındaki ilişkiler
İlişkisel veritabanlarında, veriler birden çok tabloya bölünür ve yabancı anahtarlar kullanılarak birbirine bağlanır. Nette Database Explorer, bu ilişkilerle çalışmak için devrim niteliğinde bir yol sunar – JOIN sorguları yazmadan ve herhangi bir şeyi yapılandırmaya veya oluşturmaya gerek kalmadan.
İlişkilerle çalışmayı göstermek için bir kitap veritabanı örneği kullanacağız (GitHub'da bulabilirsiniz). Veritabanında şu tablolarımız var:
author
– yazarlar ve çevirmenler (sütunlarid
,name
,web
,born
)book
– kitaplar (sütunlarid
,author_id
,translator_id
,title
,sequel_id
)tag
– etiketler (sütunlarid
,name
)book_tag
– kitaplar ve etiketler arasındaki ilişki tablosu (sütunlarbook_id
,tag_id
)

Kitap veritabanı örneğimizde, birkaç ilişki tipi buluruz (model gerçekliğe göre basitleştirilmiş olsa da):
- Bire çok 1:N – her kitabın bir yazarı vardır, bir yazar birkaç kitap yazabilir
- Sıfıra çok 0:N – kitabın bir çevirmeni olabilir, bir çevirmen birkaç kitap çevirebilir
- Sıfıra bir 0:1 – kitabın bir devamı olabilir
- Çoka çok M:N – kitabın birkaç etiketi olabilir ve bir etiket birkaç kitaba atanabilir
Bu ilişkilerde her zaman bir üst ve bir alt tablo bulunur. Örneğin, yazar ve kitap arasındaki ilişkide,
author
tablosu üst, book
tablosu alttır – bir kitabın her zaman bir yazara “ait olduğunu”
düşünebiliriz. Bu, veritabanı yapısında da kendini gösterir: alt book
tablosu, üst author
tablosuna başvuran author_id
yabancı anahtarını içerir.
Yazarlarının adları da dahil olmak üzere kitapları listelememiz gerekiyorsa, iki seçeneğimiz vardır. Ya verileri JOIN kullanarak tek bir SQL sorgusuyla alırız:
SELECT book.*, author.name FROM book LEFT JOIN author ON book.author_id = author.id
Ya da verileri iki adımda yükleriz – önce kitapları, sonra yazarlarını – ve sonra bunları PHP'de birleştiririz:
SELECT * FROM book;
SELECT * FROM author WHERE id IN (1, 2, 3); -- alınan kitapların yazar kimlikleri
İkinci yaklaşım, şaşırtıcı olsa da aslında daha verimlidir. Veriler yalnızca bir kez yüklenir ve önbellekte daha iyi kullanılabilir. Nette Database Explorer tam olarak bu şekilde çalışır – her şeyi perde arkasında halleder ve size zarif bir API sunar:
$books = $explorer->table('book');
foreach ($books as $book) {
echo 'başlık: ' . $book->title;
echo 'yazan: ' . $book->author->name; // $book->author, 'author' tablosundan bir kayıttır
echo 'çeviren: ' . $book->translator?->name;
}
Üst tabloya erişim
Üst tabloya erişim basittir. Bunlar kitabın bir yazarı var veya kitabın bir çevirmeni olabilir gibi
ilişkilerdir. İlgili kaydı ActiveRow nesnesinin özelliği aracılığıyla alırız – adı, id
olmadan
yabancı anahtar sütununun adına karşılık gelir:
$book = $explorer->table('book')->get(1);
echo $book->author->name; // author_id sütununa göre yazarı bulur
echo $book->translator?->name; // translator_id'ye göre çevirmeni bulur
$book->author
özelliğine eriştiğimizde, Explorer book
tablosunda adı author
karakter dizisini içeren bir sütun arar (yani author_id
). Bu sütundaki değere göre, author
tablosundan karşılık gelen kaydı yükler ve ActiveRow
olarak döndürür. Benzer şekilde,
translator_id
sütununu kullanan $book->translator
da çalışır. translator_id
sütunu
null
içerebileceğinden, kodda ?->
operatörünü kullanırız.
Alternatif bir yol, iki argüman alan ref()
metodudur: hedef tablo adı ve birleştirme sütunu adı ve bir
ActiveRow
örneği veya null
döndürür:
echo $book->ref('author', 'author_id')->name; // yazara bağlantı
echo $book->ref('author', 'translator_id')->name; // çevirmene bağlantı
ref()
metodu, tablo aynı ada sahip bir sütun içerdiği için (yani author
) özellik üzerinden
erişim kullanılamadığında kullanışlıdır. Diğer durumlarda, daha okunabilir olan özellik üzerinden erişim
kullanılması önerilir.
Explorer, veritabanı sorgularını otomatik olarak optimize eder. Bir döngüde kitapları dolaşırken ve ilgili kayıtlarına (yazarlar, çevirmenler) erişirken, Explorer her kitap için ayrı bir sorgu oluşturmaz. Bunun yerine, her ilişki tipi için yalnızca bir SELECT gerçekleştirir, bu da veritabanı yükünü önemli ölçüde azaltır. Örneğin:
$books = $explorer->table('book');
foreach ($books as $book) {
echo $book->title . ': ';
echo $book->author->name;
echo $book->translator?->name;
}
Bu kod, veritabanına yalnızca şu üç yıldırım hızında sorguyu çağırır:
SELECT * FROM `book`;
SELECT * FROM `author` WHERE (`id` IN (1, 2, 3)); -- seçilen kitapların author_id sütunundan kimlikler
SELECT * FROM `author` WHERE (`id` IN (2, 3)); -- seçilen kitapların translator_id sütunundan kimlikler
Birleştirme sütununu bulma mantığı, Conventions uygulaması tarafından belirlenir. Yabancı anahtarları analiz eden ve mevcut tablo ilişkileriyle kolayca çalışmanıza olanak tanıyan DiscoveredConventions kullanmanızı öneririz.
Alt tabloya erişim
Alt tabloya erişim ters yönde çalışır. Şimdi bu yazar hangi kitapları yazdı veya bu çevirmen hangi
kitapları çevirdi diye soruyoruz. Bu tür bir sorgu için, ilgili kayıtlarla bir Selection
döndüren
related()
metodunu kullanırız. Bir örneğe bakalım:
$author = $explorer->table('author')->get(1);
// Yazarın tüm kitaplarını yazdırır
foreach ($author->related('book.author_id') as $book) {
echo "Yazdı: $book->title";
}
// Yazarın çevirdiği tüm kitapları yazdırır
foreach ($author->related('book.translator_id') as $book) {
echo "Çevirdi: $book->title";
}
related()
metodu, birleştirmeyi nokta gösterimiyle tek bir argüman olarak veya iki ayrı argüman olarak
kabul eder:
$author->related('book.translator_id'); // tek argüman
$author->related('book', 'translator_id'); // iki argüman
Explorer, üst tablonun adına göre doğru birleştirme sütununu otomatik olarak algılayabilir. Bu durumda, kaynak tablonun
adı author
olduğu için book.author_id
sütunu üzerinden birleştirme yapılır:
$author->related('book'); // book.author_id kullanır
Birden fazla olası bağlantı varsa, Explorer bir AmbiguousReferenceKeyException istisnası fırlatır.
related()
metodunu elbette bir döngüde birden çok kaydı dolaşırken de kullanabiliriz ve Explorer bu durumda
da sorguları otomatik olarak optimize eder:
$authors = $explorer->table('author');
foreach ($authors as $author) {
echo $author->name . ' yazdı:';
foreach ($author->related('book') as $book) {
echo $book->title;
}
}
Bu kod yalnızca iki yıldırım hızında SQL sorgusu oluşturur:
SELECT * FROM `author`;
SELECT * FROM `book` WHERE (`author_id` IN (1, 2, 3)); -- seçilen yazarların kimlikleri
Çoka çok ilişki
Çoka çok (M:N) ilişkisi için bir ilişki tablosunun (bizim durumumuzda book_tag
) varlığı gereklidir, bu
tablo iki yabancı anahtar sütunu (book_id
, tag_id
) içerir. Bu sütunların her biri, birleştirilen
tablolardan birinin birincil anahtarına başvurur. İlgili verileri almak için önce related('book_tag')
kullanarak
ilişki tablosundan kayıtları alırız ve ardından hedef verilere devam ederiz:
$book = $explorer->table('book')->get(1);
// kitaba atanan etiketlerin adlarını yazdırır
foreach ($book->related('book_tag') as $bookTag) {
echo $bookTag->tag->name; // ilişki tablosu üzerinden etiketin adını yazdırır
}
$tag = $explorer->table('tag')->get(1);
// veya tersi: bu etiketle işaretlenmiş kitapların adlarını yazdırır
foreach ($tag->related('book_tag') as $bookTag) {
echo $bookTag->book->title; // kitabın adını yazdırır
}
Explorer yine SQL sorgularını verimli bir forma optimize eder:
SELECT * FROM `book`;
SELECT * FROM `book_tag` WHERE (`book_tag`.`book_id` IN (1, 2, ...)); -- seçilen kitapların kimlikleri
SELECT * FROM `tag` WHERE (`tag`.`id` IN (1, 2, ...)); -- book_tag'de bulunan etiketlerin kimlikleri
İlişkili tablolar üzerinden sorgulama
where()
, select()
, order()
ve group()
metotlarında, diğer tablolardaki
sütunlara erişmek için özel gösterimler kullanabiliriz. Explorer gerekli JOIN'leri otomatik olarak oluşturur.
Nokta gösterimi (üst_tablo.sütun
), alt tablo açısından 1:N ilişkisi için kullanılır:
$books = $explorer->table('book');
// Yazarı 'Jon' ile başlayan kitapları bulur
$books->where('author.name LIKE ?', 'Jon%');
// Kitapları yazar adına göre azalan sırada sıralar
$books->order('author.name DESC');
// Kitap adını ve yazar adını yazdırır
$books->select('book.title, author.name');
İki nokta üst üste gösterimi (:alt_tablo.sütun
), üst tablo açısından 1:N ilişkisi için
kullanılır:
$authors = $explorer->table('author');
// Başlığında 'PHP' geçen bir kitap yazan yazarları bulur
$authors->where(':book.title LIKE ?', '%PHP%');
// Her yazar için kitap sayısını sayar
$authors->select('*, COUNT(:book.id) AS book_count')
->group('author.id');
Yukarıdaki örnekte iki nokta üst üste gösterimi (:book.title
) ile yabancı anahtar sütunu belirtilmemiştir.
Explorer, üst tablonun adına göre doğru sütunu otomatik olarak algılar. Bu durumda, kaynak tablonun adı author
olduğu için book.author_id
sütunu üzerinden birleştirme yapılır. Birden fazla olası bağlantı varsa,
Explorer bir AmbiguousReferenceKeyException
istisnası fırlatır.
Birleştirme sütunu parantez içinde açıkça belirtilebilir:
// Başlığında 'PHP' geçen bir kitabı çeviren yazarları bulur
$authors->where(':book(translator_id).title LIKE ?', '%PHP%');
Gösterimler, birden çok tablo üzerinden erişim için zincirlenebilir:
// 'PHP' etiketiyle işaretlenmiş kitapların yazarlarını bulur
$authors->where(':book:book_tag.tag.name', 'PHP')
->group('author.id');
JOIN koşullarını genişletme
joinWhere()
metodu, SQL'de tabloları birleştirirken ON
anahtar kelimesinden sonra belirtilen
koşulları genişletir.
Belirli bir çevirmen tarafından çevrilen kitapları bulmak istediğimizi varsayalım:
// 'David' adlı çevirmen tarafından çevrilen kitapları bulur
$books = $explorer->table('book')
->joinWhere('translator', 'translator.name', 'David');
// LEFT JOIN author translator ON book.translator_id = translator.id AND (translator.name = 'David')
joinWhere()
koşulunda, where()
metodunda olduğu gibi aynı yapıları kullanabiliriz –
operatörler, yer tutucu soru işaretleri, değer dizileri veya SQL ifadeleri.
Daha karmaşık, birden çok JOIN içeren sorgular için tablo takma adları tanımlayabiliriz:
$tags = $explorer->table('tag')
->joinWhere(':book_tag.book.author', 'book_author.born < ?', 1950)
->alias(':book_tag.book.author', 'book_author');
// LEFT JOIN `book_tag` ON `tag`.`id` = `book_tag`.`tag_id`
// LEFT JOIN `book` ON `book_tag`.`book_id` = `book`.`id`
// LEFT JOIN `author` `book_author` ON `book`.`author_id` = `book_author`.`id`
// AND (`book_author`.`born` < 1950)
where()
metodunun koşulları WHERE
yan tümcesine eklerken, joinWhere()
metodunun
tabloları birleştirirken ON
yan tümcesindeki koşulları genişlettiğine dikkat edin.