# WDB ile Sorgulama

https://dev.wisecp.com/tr/wdb-ile-sorgulama

Tek bir sorgu kurucusu, iki giriş noktası ve tamamlanmadan hiçbir şeyi değiştirmeyen bir zincir.

## Genel Bakış

Sorgular, SQL'i bir dizeye yazarak değil çağrıları zincirleyerek kurulur: zincir, ifadenin yazıldığı sırayla okunur ve argüman olarak geçtiğiniz her değer yapıştırılmaz, bağlanır.

`WDB` statik bir cephedir. Metotlarının her biri, model katmanının tuttuğu tek `Database` nesnesine yönlenir; yani statik biçim ile bir modelin `$this->db`'si aynı bağlantı ve aynı kurucu durumudur.

## Referans

### Giriş Noktaları

- **WDB::**: Statik cephe; yardımcılar, operation'lar, modüller ve kancalar için. Her çağrı aşağıdaki nesneye yönlenir.
- **$this->db**: Bir modelin içindeki aynı nesne; `Models` üzerindeki tembel getter süreç başına bir kez kurar. Bir zincir bir biçimde başlatılıp diğerinde sürdürülebilir.
- **Database**: Kurucunun kendisi. Statik sarmalayıcısı olmayan metotlara (`whereGroup`, `getCount`, `pushState`) zincirin döndürdüğü nesne üzerinden erişilir.

### Okuma

```php
// Kolonları adlandırın. "*", tablonun sonradan büyüdüğü her şeyi çağıranlarınıza verir.
public static function select($arg = "*");              // boş/yanlış bir $arg "*" olur
public static function from($arg = '');                 // "users_products" | "users_products AS t"
public static function join($type, $table, $where);     // $type: "LEFT" | "INNER" | "RIGHT" - " JOIN " önüne yapıştırılır
public static function where($column, $mark = '', $value = '', $logical = '');
public static function group_by($arg = '');             // ham ifade, bağlanmaz
public static function order_by($arg);                  // ham ifade, bağlanmaz
public static function limit($arg1, $arg2 = null);      // limit(25) -> LIMIT 0,25 · limit(50, 25) -> LIMIT 50,25
public static function build($isthis = false);          // bool: eşleşen satır > 0 · $isthis = true Database nesnesini döner

// Çekiciler build()'in bıraktığı statement'ı ya da elle verdiğinizi okur.
public static function fetch_assoc($statement = false); // satır listesi, her biri kolon => değer; eşleşme yoksa []
public static function getAssoc($statement = false);    // tek satır, kolon => değer; satır yoksa false
public static function fetch_object($statement = false);// aynı liste, stdClass nesneleri olarak
public static function getObject($statement = false);   // tek satır stdClass olarak; satır yoksa false
public static function rowCounter($statement = false);  // int: son statement'ın dokunduğu satır sayısı
```

### where() Neleri Kabul Eder

İkinci argüman ifadeye olduğu gibi yazılır; yani kurucunun sahip olduğu bir listeden gelen anahtar kelime değil, bir SQL operatörüdür. Üç biçim özel olarak ele alınır.

| $mark | $value | Üretilen SQL |
| --- | --- | --- |
| `'='` `'!='` | skaler; boş dize de bağlanır | `col = ?` |
| `'>'` `'<'` `'>='` `'<='` | skaler | `col > ?` |
| `'LIKE'` `'NOT LIKE'` | kendi `%` işaretini taşıyan skaler | `col LIKE ?` |
| `'IN'` `'NOT IN'` | **dizi**; eleman başına bir yer tutucu | `col IN (?,?,?)` |
| `'IS'` `'IS NOT'` | `'NULL'`; bağlanmaz, yapıştırılır | `col IS NULL` |
| `'IS NOT NULL'` | `''`; testin tamamı operatördür | `col IS NOT NULL` |
| verilmedi (`''`) | boş olmayan skaler | `col = ?` |

```php
// $logical yalnız 'AND', '&&', 'OR', '||' kabul eder. BU koşulu BİR SONRAKİNE bağlar;
// operatörsüz bırakılan bir koşula, sonraki koşul geldiğinde otomatik AND eklenir.
public static function where($column, $mark = '', $value = '', $logical = '');

// Parantez: statik sarmalayıcısı yok, zincirin döndürdüğü nesne üzerinden çağrılır.
// $logical grubun tamamını KENDİSİNDEN SONRAKİ koşula bağlar, tıpkı where()'in
// dördüncü argümanı gibi. Vermemek güvenlidir: grup bağlanabilir bir koşul olarak
// kaydedilir, sonraki koşul AND'i kendisi ekler. OR istiyorsanız verin.
public function whereGroup(callable $callback, string $logical = ''): self;
```

### Yazma

```php
public static function insert($table, $data);             // int etkilenen satır; SQL hatasında exception fırlatır
public static function lastID();                          // int: eklemenin ürettiği kimlik; bağlantı yoksa 0
public static function update($table = '', $data = []);   // $data boş değilse set()'i sizin yerinize çağırır
public static function set($data = [], $special = false); // $special = true değeri HAM yapıştırır: ['uses' => 'uses+1']
public static function save($isthis = false);             // bool: hata yok - hiçbir satır eşleşmese de TRUE
public static function delete($arg = '', $arg2 = '');     // delete("t") | delete("a", "a INNER JOIN b ON ...")
public static function run($isthis = false);              // bool: silinen satır > 0

// insert() ve update()/set() için $data kolon => değer biçimindedir. null değer SQL NULL,
// tam sayı integer, geri kalan her şey dize olarak bağlanır.
// limit() save() ve run() için de geçerlidir: başlangıçsız satır sayısı, limit(5000).
// order_by() sınırlı bir yazmanın hangi satırları alacağını belirler. İki zincir
// çalışmaz, istisna fırlatır — MySQL kabul etmiyor: update()->join() ve
// order_by()/limit() taşıyan çok tablolu delete("t", "tablo t").
```

### Ham İfadeler

```php
public static function query($statement, $isthis = false); // PDOStatement ya da false - hata yutulur
public static function exec($arg = '');                    // int etkilenen satır; hatada 0 - hata yutulur
public static function hasTable($table = '');              // bool, SHOW TABLES LIKE ile - ad yapıştırılır, önek eklenmez
public static function getPrefix(): string;                // veritabanı yapılandırmasındaki şema öneki
public static function getErrorMessage();                  // son hatanın metni; yutulanlar da dahil
```

## Örnek

```php
// Bir sayfa satır.
WDB::select('t.id, t.name, t.status, u.full_name')
    ->from('users_products AS t')
    ->join('LEFT', 'users AS u', 'u.id = t.owner_id')
    ->where('t.status', 'IN', ['active', 'inprocess'])
    ->where('t.type', '=', 'hosting')
    ->order_by('t.id DESC')
    ->limit(0, 25)
    ->build();

$rows = WDB::fetch_assoc();                 // eşleşme yoksa []

// Tek satır. Eşleşme yoksa build() false döner; yazılacak guard budur.
$stmt = WDB::select('id, name, status')->from('users_products')->where('id', '=', $id)->limit(1);
$row  = $stmt->build() ? $stmt->getAssoc() : [];

// Çevresindeki koşullardan yalıtılmış, bağlanmış bir OR grubu.
$search = WDB::select('id')->from('users_products');
$search->where('owner_id', '=', $userId);
$search->whereGroup(function ($q) use ($word) {
    $q->where('name', 'LIKE', '%' . $word . '%', '||');
    $q->where('status', 'LIKE', '%' . $word . '%');
}, '&&');
$search->where('type', '=', 'hosting');
$found = $search->build() ? $search->fetch_assoc() : [];
```

```php
// insert etkilenen satır sayısını döner; kimlik ardından okunur.
$affected = WDB::insert('users_products', [
    'owner_id'   => $userId,
    'product_id' => $productId,
    'name'       => $name,
    'status'     => 'waiting',
    'notes'      => null,                   // SQL NULL olarak bağlanır
    'cdate'      => DateManager::Now(),
]);
$newId = $affected ? (int) WDB::lastID() : 0;

// Güncelleme: zincir save() çağrılana kadar hiçbir şey yapmaz.
WDB::update('users_products', ['status' => 'active'])->where('id', '=', $newId)->save();

// Bilerek bağlanmayan tek değer: sunucunun hesapladığı bir ifade.
WDB::update('coupons')->set(['uses' => 'uses+1'], true)->where('id', '=', $couponId)->save();

// Yazılanı diğer giriş noktasından geri okuyun - aynı bağlantıdır.
$check = WDB::select('status')->from('users_products')->where('id', '=', $newId);
$saved = $check->build() ? ($check->getAssoc()['status'] ?? '') : '';

// Silme: save() değil, run().
WDB::delete('users_products')->where('id', '=', $newId)->run();
```

## Tuzaklar

> **Güvenliği sağlayan şey değer argümanıdır**
> 
> Değeri argüman olarak geçmek onu bağlanmış kılar. Bunun yerine kolon ifadesinin içine kurmak onu ifadenin kendisine taşır ve kullanıcı girdisindeki ilk tırnak bir enjeksiyona dönüşür. Üç yer bilerek bağlanmaz ve asla kullanıcı girdisi almamalıdır: `order_by` ile `group_by`, `set($data, true)` ve `hasTable`'a verilen tablo adı.

> **Konumuna göre okunan iki argüman**
> 
> `limit(25)` ilk 25 satırdır, `limit(50, 25)` ise 50. satırdan itibaren 25 satır: bir başlangıç verildiği anda adet ikinci sıraya kayar. `where()`'in dördüncü argümanı da o koşulu önceki değil **sonraki** koşula bağlar; yani seçeneğin öncesindeki koşula yazılır, gruptaki son koşula asla.

> **Bir yazma işlenmeden bitmez, işlenmesi de eşleşme demek değildir**
> 
> Güncelleme `save()`, silme `run()` ister; koşullarda duran bir zincir hiçbir şeyi değiştirmez ve hiçbir şey bildirmez. Dönüş değerleri de bilerek ayrışır: `save()` "hata yok" cevabını verir, yani koşul hiçbir satırla eşleşmese bile true'dur; `run()` ve `build()` ise "satır > 0" cevabını verir. Bir kaydın gerçekten değiştiğini doğrulamak, boolean'a güvenmek değil kaydı geri okumaktır.

> **Kurucu exception fırlatır, ham ifadeler fırlatmaz**
> 
> `build()`, `insert()`, `save()` ve `run()` düşen bir ifadeyi exception'a çevirir; operation katmanı da onu sizin için hata yanıtına dönüştürür. `query()` ve `exec()` ise hatayı yutar ve `false` ya da `0` döner; yani bir şema ifadesi tamamen sessizce başarısız olabilir. Onlara başvurduğunuzda `getErrorMessage()`'ı okuyun.

## İlgili Makaleler

- [Model Katmanı](https://dev.wisecp.com/tr/model-katmani)
- [Veritabanı Şemasını Değiştirme](https://dev.wisecp.com/tr/veritabani-semasini-degistirme)
- [Alan Yardımcıları](https://dev.wisecp.com/tr/alan-yardimcilari)
- [Önbellek](https://dev.wisecp.com/tr/onbellek)
