# Hizmet Durum Kancaları

https://dev.wisecp.com/tr/hizmet-durum-kancalari

Satılan bir hizmetin açılışından silinmesine kadar dokuz kanca: kurulum, durum geçişleri, askı, sonlandırma ve silme.

## Genel Bakış

Hizmet **iki yerde birden** yaşar: bizim veritabanımızda bir satır olarak ve sağlayıcı modülünün ucunda gerçek bir hesap olarak. Buradaki kancaların çoğu birinci tarafı anlatır.

Bu ayrımı bilmek gerekir: durum değiştiğinde **bizim kaydımız** değişmiştir. Sunucudaki hesabın gerçekten kapanıp kapanmadığı ayrı bir sorudur ve çoğu zaman **kuyruğa alınmış** bir işin sonucudur.

## Referans

### Kurulacak hizmeti değiştirme

filterservice.save_data

`Hook::runRefs` referansla

Hizmet satırı veritabanına yazılmadan önce çalışır.

Parametreler 1

$dataarrayrefYazılacak satır: `user_id`, `product_id`, `options`, `status`, `duedate`. Burada yaptığınız değişiklik doğrudan veritabanına gider.

Dönüş 1

voidDeğer **referansla** değişir; dönüş kullanılmaz.

Dinleyici PHP

```php
Hook::add('filter:service.save_data', 10, function (&$data) {
    // Kendi izleme anahtarinizi options icine koyun; kolon eklemeyin.
    $data['options']['acme_batch'] = Acme::currentBatch();
});
```

### Hizmetin açıldığını öğrenme

actionservice.created

`Services::create()` satır yazıldı

Hizmet satırı yazıldıktan sonra çalışır. Sağlayıcıdaki hesap bu noktada **henüz açılmamış** olabilir.

Parametreler 2

$idintYeni hizmetin kimliği.

$dataarrayYazılan veri. Filtreden geçmiş hâlidir, yani değişiklikleriniz burada görünür.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.created', 10, function ($id, $data) {
    // Satir var, sunucudaki hesap henuz olmayabilir: kurulumu beklemeyin.
    Crm::opened((int) $id, (int) ($data['user_id'] ?? 0));
});
```

### Durum geçişini durdurma

gateservice.status_change

`Services::change_status()` eski ve yeni durum

Hizmetin durumu değişmeden önce çalışır; eski ve hedef durumun ikisini de verir.

Parametreler 3

$servicearrayHizmet kaydı, **mevcut** durumuyla.

$statusstringHedef durum: `active`, `suspended`, `cancelled`, `inprocess`.

$oldStatusstringMevcut durum. Belirli bir geçişi hedeflemek için ikisini birlikte okuyun.

Dönüş 1

stringBoş olmayan bir string geçişi **durdurur**; metin hata olarak fırlatılır.

Dinleyici PHP

```php
Hook::add('gate:service.status_change', 10,
    function ($service, $status, $oldStatus) {
        // Yalniz iptal edilmis hizmetin yeniden acilmasini denetle.
        if ($oldStatus === 'cancelled' && $status === 'active'
            && !Acme::reactivationAllowed($service))
            return 'Iptal edilmis hizmet yonetici onayiyla acilir.';

        return null;
    });
```

### Durum geçişini izleme

actionservice.status_changed

`Services::change_status()` modül ezmiş olabilir

Durum değiştikten sonra çalışır. Verilen durum, modülün ezmesinden sonraki **nihai** değerdir.

Parametreler 4

$serviceIdintHizmet kimliği.

$statusstringYeni durum. Modül müdahale ettiyse istenen durumdan **farklı** olabilir.

$oldStatusstringÖnceki durum.

$servicearrayGeçiş **öncesi** hizmet anlık görüntüsü.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.status_changed', 10,
    function ($serviceId, $status, $oldStatus, $service) {
        // Ayni duruma geri donuste tekrar is yapmayin.
        if ($status === $oldStatus) return;

        Crm::statusMoved($serviceId, $oldStatus, $status);
    });
```

### Askıya almayı durdurma

gateservice.suspend

`cronjobs/ServiceSuspend` veto iptale çevrilir

Hizmet ya da ek hizmet askıya alınmadan önce çalışır. **Durdurmanın bir bedeli vardır**: iş iptal sinyaline çevrilir.

Parametreler 4

$target_typestring`service` ya da `addon`. Aynı kanca ikisini de taşır.

$target_idintAskıya alınacak kaydın kimliği.

$servicearrayCanlı satır: `status`, `duedate`, `module`, `owner_id`.

$user_idintHizmet sahibi.

Dönüş 1

stringBoş olmayan bir string askıya almayı **veto eder** — ama iş burada bitmez: sinyal **iptale** çevrilir ve gerekçeniz kayda geçer. Yani "askıya alma" demek "hiçbir şey olmasın" demek değildir.

Dinleyici PHP

```php
Hook::add('gate:service.suspend', 10,
    function ($target_type, $target_id, $service, $user_id) {
        if ($target_type !== 'service') return null;      // eklentiye karisma

        // DIKKAT: veto askiyi engeller ama isi IPTAL sinyaline cevirir.
        if (Acme::vipAccount($user_id)) return 'VIP hesap: elle inceleyin.';

        return null;
    });
```

### Askıya almayı izleme

actionservice.suspended

`cronjobs/ServiceSuspend` modül işi kuyrukta

Hizmet askıya alındıktan sonra çalışır. Sunucudaki asıl kapatma **kuyruğa** alınmıştır.

Parametreler 5

$target_typestring`service` ya da `addon`.

$target_idintAskıya alınan kaydın kimliği.

$user_idintHizmet sahibi.

$reasonstringAskı nedeni, **müşterinin diline çevrilmiş**.

$module_queue_idintModül işinin kuyruk kimliği. `0` demek **kuyruğa hiç atılmadı** demektir: modülsüz hizmette sunucu tarafında bir şey olmaz.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.suspended', 10,
    function ($target_type, $target_id, $user_id, $reason, $module_queue_id) {
        // Kuyruk id'si 0 ise sunucuda hicbir sey yapilmadi.
        if ($module_queue_id === 0) Ops::note('suspend-no-module', $target_id);
    });
```

### Sonlandırmayı izleme

actionservice.terminated

`cronjobs/ServiceTerminate` sunucu tarafı

Hizmet sonlandırıldıktan sonra çalışır. Bu kanca **sunucu tarafı** bilgisi verir: hangi modül, hangi sunucu.

Parametreler 5

$target_idintSonlandırılan hizmetin kimliği.

$service_typestring`hosting` ya da `server`.

$modulestringSunucu modülünün adı.

$server_idintHizmetin bağlı olduğu sunucu.

$module_queue_idintKuyruğa atılan sonlandırma işinin kimliği.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.terminated', 10,
    function ($target_id, $service_type, $module, $server_id, $module_queue_id) {
        // Sunucu kapasitesi serbest kaldi: kendi sayacinizi guncelleyin.
        Capacity::released((int) $server_id, $service_type);
    });
```

### Hizmet silmeyi durdurma

gateservice.delete

`Services::delete()` kayıt gider

Hizmet kaydı silinmeden önce çalışır. Silme, sunucudaki hesabı kapatmakla **aynı şey değildir**: yalnız bizim kaydımızı kaldırır.

Parametreler 1

$servicearraySilinecek hizmet kaydı.

Dönüş 1

stringBoş olmayan bir string silmeyi **durdurur**; metin hata olarak fırlatılır.

Dinleyici PHP

```php
Hook::add('gate:service.delete', 10, function ($service) {
    // Etkin hizmeti silmek sunucuda oksuz hesap birakir.
    if (($service['status'] ?? '') === 'active')
        return 'Etkin hizmet silinemez; once sonlandirin.';

    return null;
});
```

### Silmeyi izleme

actionservice.deleted

`Services::delete()` son anlık görüntü

Hizmet kaydı silindikten sonra çalışır.

Parametreler 2

$idintSilinen hizmetin kimliği.

$servicearraySilme **öncesi** anlık görüntü. Veriye ihtiyacınız varsa buradan alın; kayıt artık yok.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.deleted', 10, function ($id, $service) {
    Acme::forgetService((int) $id, $service['name'] ?? '');
});
```

## Tuzaklar

> **Askı vetosu iptale dönüşür**
> 
> Askıya alma kapısında boş olmayan bir metin döndürmek işi durdurmaz, **iptale çevirir**. "Bu hizmeti askıya almayın" diye yazılan bir kural, hizmetin **büsbütün iptal edilmesine** yol açabilir. Bu kapıya dokunmadan önce sonucun ne olacağını bilerek yazın.

> **Kuyruk kimliği sıfırsa sunucuda bir şey olmadı**
> 
> Askı ve sonlandırma kancaları size **kuyruk kimliği** verir. Sıfır demek modül işinin **hiç oluşturulmadığı** demektir: hizmetin modülü yoktur ya da sunucu bilinmiyordur. Bizim kaydımız değişmiştir ama sunucuda hiçbir şey olmamıştır.

> **Nihai durum istenen durum olmayabilir**
> 
> Durum olayı size **modülün ezmesinden sonraki** değeri verir. Kapıda gördüğünüz hedefle olayda gelen değer **farklı** olabilir. Bir geçişe tepki veriyorsanız değeri olaydan okuyun, kapıdaki niyetten değil.

> **Silmek kapatmak değildir**
> 
> Hizmet silme yalnız **bizim kaydımızı** kaldırır. Sunucudaki hesap yerinde durur ve artık hiçbir yerden görünmez. Sunucu tarafının da kapanması gerekiyorsa önce sonlandırma yapılır, silme ondan sonra gelir.

## İlgili Makaleler

- [Hizmet Yaşam Döngüsü Kancaları](https://dev.wisecp.com/tr/hizmet-yasam-dongusu-kancalari)
- Sipariş Akışı Kancaları
- Zamanlanmış Görev Kancaları
