# Modülle Şablon Gönderme

https://dev.wisecp.com/tr/modulle-sablon-gonderme

Bildirimi modülünüzle birlikte gönderin; operatörün yapması gereken tek şey modülü etkinleştirmek olsun.

## Genel Bakış

Kendi mailini gönderen bir modül iki şey kurar. **Kayıt**, şablonu Bildirim Şablonları ekranına koyar; operatör onu oradan açıp kapatır. **Dosyalar** ise konuyu, gövdeyi ve kısa mesajı okundukları yerlere koyar.

Birincisi eksikse `dispatch()` `disabled` döner. İkincisi eksikse mail gövdesiz ve konusuz gider. Tek çağrı ikisini de yapar.

- **Notification::seed_templates()**: Eksik kaydı kurar ve parçaları doğru köklere yazar. Idempotenttir: var olan dosya asla ezilmez, yani operatörün düzenlemesi her yeniden etkinleştirmeden sağ çıkar.
- **Notification::dispatch()**: Sonrasında göndermek için çağırdığınız şey. Burada modüle özgü hiçbir şey yoktur — tohumlanmış bir şablon, çekirdeğinkiyle aynı şekilde gönderilir.

## Ön Koşullar

- `enable()` yolu olan bir modül.
- Bir grup adı. Mail o alana aitse çekirdek grubunu kullanın, değilse kendi adınızı verin.
- Önce [Bildirim Şablonları Nasıl Çalışır](https://dev.wisecp.com/tr/bildirim-sablonlari-nasil-calisir) makalesini okuyun. Bu çağrının yazdığı kökler orada anlatılıyor.

## Yapı

Şablonları modülün içinde tutun; böylece modülle birlikte taşınır ve silinirler. İki kaynak biçimi okunur; size hangisi uyuyorsa onu kullanın.

```bash
coremio/modules/Servers/Acme/
├── Acme.php
└── notifications/                       # düz biçim: parça başına bir dosya
    ├── en/
    │   ├── acme-quota-reached.json        # {"subject": "..."}
    │   ├── acme-quota-reached.html        # e-posta gövdesi
    │   └── acme-quota-reached.txt         # kısa mesaj
    └── tr/ ...

coremio/modules/Servers/Acme/notifications/    # klasör biçimi: tasarım başına gövde ekler
└── en/acme-quota-reached/
    ├── content.json
    ├── content.txt
    ├── content.html                       # taban tasarımın gövdesi
    └── ledger.html                        # Ledger tasarımının kendi gövdesi
```

Klasör biçimi, sürüm paketinin de kullandığı biçimdir. Böylece bir modül ile bir sürüm, şablonu aynı dille tarif eder.

## Adım Adım

1. E-posta gövdesini bir belge değil **parça** olarak yazın. Etrafındaki kabuk aktif tasarımdan gelir.
2. Desteklediğiniz her dil için birer dosya yazın. Yazmadığınız dilin mesajı olmaz; operatör onu doldurabilir.
3. Smarty yer tutucuları kullanın (`{$service_name}`) ve `settings` içinde bildirin; panel onları önersin.
4. Tohumlayıcıyı `enable()` içinden çağırın. Güncellemede de çalışan bir muhafız ekleyin: eski bir kurulum, yeni şablonu almak için modülü kapatıp açmaz.
5. `dispatch()` ile gönderin ve dönen `status` değerini okuyun. `disabled`, kaydın eksik olduğunu ya da operatörün maili kapattığını söyler.

## Referans

```php
static function seed_templates(string $group, array $templates, array $options = []): array
{
    // ...
}
```

- **$templates[anahtar]['settings']**: Config kaydı; yalnızca anahtar yokken yazılır. Vermediğiniz her alan varsayılana düşer: `status` 1, `user-mail` 1, `admin-mail`/`user-sms`/`admin-sms` 0, boş `emails`/`phones`/`departments`. **Anahtarı hiç vermezseniz** config dosyasına dokunulmaz — kaydını kendisi yöneten modüller için.
- **$templates[anahtar]['source']**: Dosyaları tutan dizin. Yukarıdaki iki biçim de okunur; tasarım başına gövde taşıyabildiği için önce klasör biçimi denenir.
- **$templates[anahtar]['text']**: `source` yerine satır içi biçim: `[dil => ['subject' => …, 'html' => …, 'sms' => …, 'themes' => [tasarım => html]]]`. Vermediğiniz parça yazılmaz.
- **$options['themes']**: `'base'` (varsayılan) gövdeyi ürünle gelen tasarıma yazar, diğer tasarımlar ona geri düşer. `'all'` aynı gövdeyi kurulu her tasarıma kopyalar — seçmeden önce aşağıdaki tuzağı okuyun.
- **dönüş**: `['written' => string[], 'skipped' => int, 'registered' => string[]]` — bu koşuda yazılan yollar, zaten var olduğu için dokunulmayan dosya sayısı ve config'e eklenen `grup/anahtar` çiftleri.

## Örnek

```php
private function ensure_notification_template(): void
{
    static $checked = false;
    if ($checked) return;
    $checked = true;

    \Notification::seed_templates('service', [
        'acme-quota-reached' => [
            'settings' => [
                'variables' => '{service_id},{service_name},{quota_usage}',
                'status'    => 1,
                'user-mail' => 1,
            ],
            'source' => __DIR__ . DS . 'notifications',
        ],
    ]);
}
```

```php
$this->ensure_notification_template();

$result = \Notification::dispatch('service', 'acme-quota-reached', [
    'user_id'   => (int) $service['owner_id'],
    'variables' => [
        '{service_id}'   => $service['id'],
        '{service_name}' => $service['name'],
        '{quota_usage}'  => $usage . '%',
    ],
]);

// 'disabled' bir hata değil bir karardır: operatör bu maili kapatmış.
if (($result['status'] ?? '') === 'error') \Logger::error('Acme kota maili gönderilemedi');
```

## Tuzaklar

> **Göndermediğiniz tasarım eksik değildir**
> 
> O olay için dosyası olmayan bir tasarım, taban gövdeyi *kendi* kabuğunun içinde gösterir. Gövdeyi her tasarıma kopyalamak aynı şey değildir. Kopya geri düşmeyi ezer; tema yazarı o mail için bir daha tasarım yayınlayamaz.

> **Kayıt tek başına yetmez**
> 
> Dosyası olmayan bir config kaydı boş mail gönderir. Bunu ilk öğrenme yolu müşteri şikâyeti olur. Kaydı kendiniz yönetiyorsanız dosyalar için yine tohumlayıcıyı çağırın. `settings` anahtarını vermeyin; kaydınıza dokunulmaz.

> **Yolu asla elle kurmayın**
> 
> Parçalar farklı köklerde yaşar ve gövdenin kökü aktif tasarıma bağlıdır. `templates/notifications/` ile bir dil klasörünü birleştiren kod, hiçbir şeyin okumadığı yere yazar. Yazma başarılı olur, mail boş kalır.

## İlgili Makaleler

- [Bildirim Şablonları Nasıl Çalışır](https://dev.wisecp.com/tr/bildirim-sablonlari-nasil-calisir)
- [E-posta Şablonu Yazma](https://dev.wisecp.com/tr/e-posta-sablonu-yazma)
- [Bildirim Şablonu Değişkenleri](https://dev.wisecp.com/tr/bildirim-sablonu-degiskenleri)
