# Kanca Dinleyicisi Yazma

https://dev.wisecp.com/tr/kanca-dinleyicisi-yazma

Bir kancaya bağlanan işlevi yazmak: parametreleri doğru sırayla almak, dönüşü sözleşmesine göre vermek.

## Genel Bakış

Dinleyici üç şeydir: bağlandığınız **ad**, sıradaki yeriniz olan **sayı**, çalışacak **işlev**. Zor kısım bunlar değil. Zor olan işlevin **imzasını ve dönüşünü** doğru yazmaktır.

Her kanca kendi sözleşmesini taşır. Biri değeri referansla verir ve değiştirmenizi bekler. Biri döndürdüğünüz metni ekranda gösterir. Biri o metni hata olarak fırlatıp işlemi durdurur. Biri dönüşünüze hiç bakmaz.

Sözleşmeyi yanlış okumak **hata vermez**: dinleyici çalışır, hiçbir şey olmaz.

## Ön Koşullar

- [Kancalar Nasıl Çalışır](https://dev.wisecp.com/tr/kancalar-nasil-calisir) okunmuş olmalı.
- Bağlanacağınız kancanın adı ve **kaydı**. Parametrelerin anlamı orada yazar.
- Dinleyicinin yaşayacağı dosya: `coremio/hooks` altında bir dosya ya da modülünüzün `hooks.php` dosyası.

## Adım Adım

### 1. Sözleşmeyi okuyun

1. Kancanın kaydında **üç satır** vardır: *Mekanizma*, *Parametreler*, *Dönüş sözleşmesi*. Üçünü de okuyun.
2. Adın önündeki sözcüğe göre karar **vermeyin**. Ölçüldüğünde `filter` ailesinin bir bölümü kopyayla çağrılıyordu.
3. Parametre listesindeki **Ref** sütunu belirleyicidir. İşaretli parametreyi `&` ile alırsanız değiştirebilirsiniz.

### 2. İmzayı yazın

1. Parametreleri **kancanın verdiği sırayla** alın. Adları serbesttir, sıra değildir.
2. Sondaki gereksiz parametreleri **yazmayın**. Eksik yazmak güvenli, fazla yazmak dinleyiciyi düşürür.
3. Değiştireceğiniz parametreyi `&` ile alın.

```php
// filter:invoice.late_fee_amount — kayittaki sira: &$fee, $invoice, $cycle
Hook::add('filter:invoice.late_fee_amount', 10, function (&$fee, $invoice) {
    if ((int) ($invoice['user_id'] ?? 0) === 1) $fee = 0.0;   // ucuncu parametre yazilmadi
});
```

### 3. Dönüşü verin

1. Kaydın *Dönüş sözleşmesi* satırı ne diyorsa onu yapın. Aşağıdaki dağılım yardımcıdır, karar o satırındır.
2. Dokunmak istemiyorsanız `null` dönün.
3. Bir işlemi durduruyorsanız **kullanıcının okuyacağı cümleyi** dönün.

### 4. Çalıştığını kanıtlayın

1. Dosyayı yerine koyun, kancayı tetikleyen işi yapın. Yeniden başlatma gerekmez.
2. Hiçbir şey olmadıysa hata günlüğüne bakın. `Hook execution error` kaydı dinleyicinin koşup patladığını söyler.
3. `Hook listener unresolved` kaydı ise sınıf ya da metot adının yanlış olduğunu söyler.
4. Günlük boşsa dinleyici hiç çağrılmamıştır: ad yanlıştır ya da dosya taranan iki yerde değildir.
5. Kesin cevap için kancayı teşhis kipinde çalıştırın.

```php
foreach (Hook::runDetailed('action:service.created', $id, $data) as $row) {
    echo $row['source']['file'] . ':' . $row['source']['line'] . "\n";
    if ($row['error'] !== null) echo '  HATA: ' . $row['error'] . "\n";
}
```

## Referans

Aşağıdaki dağılım **1007 kancanın kaydından** sayıldı. Bir ailede neyi beklemeniz gerektiğini gösterir. Tek bir kanca için doğruluk kaynağı değildir: her satırda başka türlü davranan bir azınlık var.

- **action**: **301** kancada dönüş yoksayılır. **4** kanca telemetri toplar ve dönüşünüzü kaydeder.
- **filter**: **196** kancada değeri **referansla değiştirirsiniz**, dönüşe bakılmaz. **6** kancada değiştirilmiş değeri **döndürürsünüz**; son dolu dönüş öncekini ezer.
- **gate**: **129** kancada **boş olmayan bir string** işlemi durdurur ve hata olarak fırlatılır. `null` ya da boş string akışı sürdürür.
- **ui**: **333** kancada **basılacak HTML** dönersiniz; boş dönüşler atlanır. **12** kancada size verilen nesneyi değiştirirsiniz.
- **register**: **5** kancada kayıt dizisi dönersiniz. **4** kancada verilen diziyi genişletirsiniz, **2** kancada tek değer dönersiniz.

### Sıra numarası

Küçük sayı önce çalışır. **Aynı sayı iki kez alınamaz**: ikinci dinleyici bir sonraki boş sayıya kaydırılır.

Sayıyı diğer dinleyicilere göre seçin. Bir değeri **son sözü siz söyleyerek** değiştirmek istiyorsanız büyük sayı verin. Bir işlemi **herkesten önce** durdurmak istiyorsanız küçük sayı verin.

## Örnek

Bir kurulumun kurumsal müşteri kuralları: gecikme ücreti alınmaz, hizmet açılışı dış bir sisteme bildirilir, borçlu hesabın hizmeti silinemez.

```php
<?php

// DEGER: gecikme ucretini referansla sifirla.
Hook::add('filter:invoice.late_fee_amount', 10, function (&$fee, $invoice) {
    if (Corporate::has((int) ($invoice['user_id'] ?? 0))) $fee = 0.0;
});

// OLAY: hizmet acildi. Donusumuze bakilmaz.
Hook::add('action:service.created', 10, function ($id, $data) {
    if (Corporate::has((int) ($data['owner_id'] ?? 0))) Crm::openedService($id, $data);
});

// IZIN: bos olmayan string silmeyi durdurur; bu cumle operatore gosterilir.
Hook::add('gate:service.delete', 10, function ($service) {
    $uid = (int) ($service['owner_id'] ?? 0);
    if (Corporate::has($uid) && Corporate::owes($uid))
        return 'Odenmemis faturasi olan kurumsal hesabin hizmeti silinemez.';
    return null;
});
```

Üçü aynı dosyada durur ve üçü farklı sözleşmeye uyar: biri parametresini değiştirir, biri hiçbir şey döndürmez, biri metin döndürüp işlemi keser.

## Tuzaklar

> **Referans işaretini kanca vermiyorsa boşunadır**
> 
> İmzada `&$deger` yazmak tek başına yetmez; değerin referansla **gönderilmiş** olması gerekir. Kayıt o parametreyi referanslı göstermiyorsa değişikliğiniz yerel kopyada kalır. Belirti yoktur: hata çıkmaz, yalnız etki olmaz.

> **Referanslı kancaya sabit değer geçilemez**
> 
> Bir kancayı referanslı biçimde **siz açıyorsanız**, geçtiğiniz her argüman değişken olmalıdır. Dizi sabiti, metin sabiti, fonksiyon dönüşü ya da `??` ifadesi geçmek **ölümcül hatadır** ve sayfayı düşürür. Bağlam değerlerini önce değişkene alın.

> **Sınıf biçiminde nesne paylaşılır**
> 
> Dinleyiciyi sınıf metodu olarak kaydettiğinizde o sınıf **bir kez** kurulur. Aynı sınıfı kullanan bütün kancalar aynı nesneyi paylaşır. Kurucudaki iş kanca başına değil **istek başına bir kez** olur; nesnede tuttuğunuz durum diğer kancalara taşınır. İstemiyorsanız statik biçimi kullanın.

> **Sıra numarası eşitse kayıt sırası karar verir**
> 
> Aynı sayıyı iki dinleyiciye vermek onları eşit yapmaz; ikincisi bir sonraki boş sayıya **kaydırılır**. Hangisinin kaydığı dosyaların yüklenme sırasına bağlıdır ve modül eklendikçe değişebilir. Sırası önemli olan dinleyicilere **ayrı sayılar** verin.

> **Kapıya iş yaptırmayın**
> 
> Engelleme kancaları **her denemede** çalışır ve tek işleri olur ya da olmaz demektir. İçinde uzak servise istek atmak veya veri yazmak akışı yavaşlatır. Dahası, başka bir dinleyici işlemi zaten durdurmuş olabilir; yazdığınız kayıt **karşılığı olmayan** bir kayıt olarak kalır.

## İlgili Makaleler

- [Kancalar Nasıl Çalışır](https://dev.wisecp.com/tr/kancalar-nasil-calisir)
- [Kanca Alanları](https://dev.wisecp.com/tr/kanca-alanlari)
- [Sık Kullanılan Kanca Senaryoları](https://dev.wisecp.com/tr/sik-kullanilan-kanca-senaryolari)
