# Modül Varlıkları ve Logo

https://dev.wisecp.com/tr/modul-varliklari-ve-logo

Stil dosyalarını, betikleri ve görselleri modülünüzün içinde taşıyın, yol yazmadan bağlayın ve modüle kendi panel simgesini verin.

## Genel Bakış

Bir modülün durağan dosyaları modül dizininde yaşar ve modülle taşınır. Hiçbir şey kopyalanmaz, kaydedilmez: dizin zaten web üzerinden erişilebilirdir ve taban sınıf size adresini verir.

Bütün işi kolayca karışan iki özellik yapar: bir dosya sistemi yolu ve bir açık URL. Logo ayrıdır; kendi çözümleme sırası vardır ve platformun kendiliğinden aradığı tek varlıktır.

## Ön Koşullar

- Taban sınıflardan birini genişleten bir modül; dizin ve URL özellikleri böylece doludur. Düz sınıflı tip bunları kendisi kurar.
- Varlığın modüle ait olmayan bir sayfaya ulaşması gerekiyorsa bir kanca dosyası. Bkz. [Modülden Kanca Kaydetme](https://dev.wisecp.com/tr/modulden-kanca-kaydetme).
- Başka bir şey yok: derleme adımı, künye ve varlık hattı yoktur.

## Yapı

### Varlık Dizini

```bash
coremio/modules/{Type}/{Name}/
├── logo.svg            # panel simgesi. Modül KÖKÜ, assets/ değil
└── assets/
    ├── style/          # css
    ├── js/             # javascript
    └── images/         # arayüzünüzün İÇİNDE kullanılan görseller, asla logo değil
```

Dosya adlarında modül adını tekrarlamayın: dizin dosyanın hangi modüle ait olduğunu zaten söyler, konvansiyon `assets/js/app.js`'tir. Stil dosyasında `url(../images/icon.svg)` gibi göreli bir adres çözülür, çünkü dosya gerçek konumundan servis edilir.

### İki Yol

- **$this->dir**: Modül dizininin mutlak dosya sistemi yolu, ayraçla biter. Dosya okumak, varlık denetlemek ya da önbellek kırma için değişiklik zamanı almak üzere kullanın.
- **$this->url**: Aynı dizinin mutlak açık URL'i, eğik çizgiyle biter. İşaretlemedeki her şey bundan kurulur: `$this->url . 'assets/style/app.css'`.
- **Asla düz yol yazmayın**: İki özellik de ilk metodunuz çalışmadan önce taban yapıcı tarafından ayarlanır. Düz yazılmış bir yol sizin makinenizde çalışır, başka hiçbir yerde çalışmaz.

## Adım Adım

### Bir Stil Dosyası Ekleyin

1. Modül dizininin içinde `assets/style/app.css` oluşturun.
2. Sınıf adlarınızın başına modüle özgü bir önek koyun: panelin stil dosyası aynı sayfadadır ve genel bir ad sessizce çakışır.
3. Görsellere göreli adresle başvurun, onları `assets/images` içine koyun.

### Doğru Sayfada Yükleyin

1. Varlığın nereye ait olduğuna karar verin: modülünüzün sayfası stillerini kendisi döndürür, gerisi bir head kancasından geçer.
2. Kanca gövdesinde, bu sayfanın varlığa ihtiyacı yoksa boş dize döndürün.
3. Adresi URL özelliğinden kurun ve dosyanın değişiklik zamanından bir önbellek kırma değeri ekleyin.
4. Sayfayı açıp dosyanın ağ panelinde göründüğünü, ilgisiz sayfada görünmediğini doğrulayın.

### Logo Ekleyin

1. Modül köküne `logo` adında bir görsel koyun; uzantısı `svg`, `webp`, `png`, `jpg`, `jpeg` ya da `gif` olsun. Adıyla bulunur.
2. Farklı bir dosya adı ya da alt dizindeki bir dosya için onu yapılandırmada `meta.logo` altında adlandırın.
3. Modül listesini yenileyin. Simge adın yanında görünür.

## Referans

### Logo Çözümlemesi

```php
// Örnek üzerinde: bu modülün kendi adı ve tipi için çözer.
public function logo(): string;

// Elinizde örnek yokken statik olarak. Tip VARSAYILANINA dikkat: onu atlayan bir çağrı
// modülü bir sunucu modülü olarak arar.
public static function logo(string $name = '', $type = 'Servers'): string;
```

| Sıra | Kaynak | Adrese nasıl çevrilir |
| --- | --- | --- |
| 1 | Yapılandırmadaki `meta.logo` ya da üst düzey `logo` girdisi | Protokolle başlıyorsa olduğu gibi kullanılır; aksi halde modül dizinine göre çözülür, `images/logo.png` gibi bir alt yol da işler |
| 2 | Modül kökünde, desteklenen bir uzantıyla duran `logo` adlı dosya | Kalıpla bulunur ve modül dizinine göre çözülür. Böyle tek bir dosya bulundurun |
| 3 | Paylaşılan admin logo dizininde, modülün küçük harfli adını taşıyan dosya | Son çare; kendi görseli olmayan bir modül yine de marka simgesi gösterir |
| 4 | Hiçbiri eşleşmedi | Boş dize; çağıran taraf kendi yer tutucusunu gösterir |

### Varlık Enjeksiyon Noktaları

- **ui:admin.head.css**: Tam bir stil etiketi ya da boş dize döndürün. İşaretleme panelin head'inde, dinleyici başına bir kez yer alır.
- **ui:admin.head.js**: Betikler için aynısı. Tek dizede birkaç etiket olağandır: bir yapılandırma nesnesi ve onu okuyan betik.
- **ui:client.head.css**: Müşteriye dönük karşılığı. İkisini ayrı tutun: açık sayfada yüklenen panel stili arayüzünüzü temaya sızdırır.
- **ui:client.head.js**: Müşteri tarafı betikleri. Açık sayfaya ulaşan her şey oturum açmamış ziyaretçide de ayakta kalmalıdır.
- **page_styles · page_scripts**: Bir modül admin sayfasının döndürdüğü dizinin anahtarları. Varlık modülünüze ait bir sayfadaysa kancaya tercih edilir: kapılama örtüktür.
- **Önbellek kırma**: Dosyanın değişiklik zamanını sorgu değeri olarak ekleyin, olmazsa yapılandırmadaki `meta.version` değerine düşün; örnekte sürüm özelliği yoktur, onu `$this->config` üzerinden okuyun. Kırma değeri olmadan operatör güncellemeden sonra eski dosyayı alır ve yeniden üretemeyeceğiniz bir hata bildirir.

## Örnek

Kalıbın tamamı tek kanca dosyasında: bir sayfa kapısı, ait olduğu iş için kullanılan her özellik ve işaretlemeden kazınmak yerine betiğe verilen yapılandırma.

```php
// Bu dosya, modül etkin olsun olmasın, HER istekte koşar. Burada yalnız kayıt yapın.
$acme_on_page = fn () => in_array(Controllers::$cname ?? '', ['tickets', 'services'], true);

Hook::add('ui:admin.head.css', 1, function () use ($acme_on_page) {
    if (!$acme_on_page()) return '';

    $m = Modules::getInstance('Addons', 'Acme');

    // Diskteki dosya için dir, işaretlemedeki adres için url.
    $v = @filemtime($m->dir . 'assets' . DS . 'style' . DS . 'app.css') ?: ($m->config['meta']['version'] ?? '1.0');

    return '<link rel="stylesheet" href="' . $m->url . 'assets/style/app.css?v=' . $v . '">';
});

Hook::add('ui:admin.head.js', 1, function () use ($acme_on_page) {
    if (!$acme_on_page()) return '';

    $m    = Modules::getInstance('Addons', 'Acme');
    $lang = $m->lang;

    // Betiğin ihtiyaç duyduğu her şey, tek seferde kodlanır. Kaçış bayrakları önemlidir:
    // bu dize bir HTML belgesinde script etiketinin içine basılır.
    $config = Utility::jencode([
        'endpoint' => Controllers::$init->ControllerURI(),
        'i18n'     => [
            'run'    => $lang['btn-run'] ?? 'Run',
            'failed' => $lang['err-failed'] ?? 'Request failed',
        ],
    ], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);

    $v = @filemtime($m->dir . 'assets' . DS . 'js' . DS . 'app.js') ?: ($m->config['meta']['version'] ?? '1.0');

    return '<script>window.Acme = ' . $config . ';</script>'
         . '<script src="' . $m->url . 'assets/js/app.js?v=' . $v . '"></script>';
});
```

Okuma tarafı; adres tahmin etmez ve etiketi yeniden türetmez:

```javascript
(function () {
    var cfg = window.Acme;
    if (!cfg) return;                     // varlık, ait olmadığı bir sayfada yüklendi

    document.querySelectorAll('[data-acme-run]').forEach(function (btn) {
        btn.textContent = cfg.i18n.run;
        btn.addEventListener('click', () => WcpRequest(cfg.endpoint, {
            data: { operation: 'use_addon_method', method: 'run', id: btn.dataset.acmeRun },
        }));
    });
})();
```

Logo; dosya modül kökünde `logo` adını taşımadığında bildirilir:

```php
return [
    'meta' => [
        'name'    => 'Acme',
        'version' => '1.0',

        // Modül dizinine göre çözülür. Alt yol serbesttir; protokolle başlayan
        // bir adres ise yazıldığı gibi kullanılır.
        'logo'    => 'assets/images/brand.svg',
    ],
];
```

## Tuzaklar

> **Logo önbelleği yalnız modül adına göre anahtarlanır, tipe göre değil**
> 
> Aynı adı taşıyan farklı tipteki iki modül, istek boyunca tek bir çözülmüş logoyu paylaşır ve kazanan ilk sorulandır. Modülünüze başka hiçbir tipin kullanmadığı bir ad verin.

> **Logo yardımcısı modülü yüklemez**
> 
> Yapılandırmayı önbellekten okur; tanımlı bir logo adı ancak o modülü bir yer zaten yüklediyse dikkate alınır. Soğuk çağrıldığında `logo` adlı dosyaya düşer — o adın güvenli seçim olmasının sebebi budur. Örnek üzerinden çağırmak güvenlidir.

> **Elle yazılmış modül yolu yalnız sizin makinenizde çalışır**
> 
> Aynı dosyanın adresi her sistemde farklıdır: uygulama bir alt dizinde, başka sunucuda ya da farklı protokolün ardında olabilir. İki özellik bunu hesaba katar, düz dize katmaz; arıza başkasının sisteminde eksik stil dosyası olarak görünür.

> **Kapılanmamış varlık her ekranda yüklenir**
> 
> Kanca dosyaları her istekte, her modül dizini için, modül etkin olmasa da çalışır. Sayfa koşulu olmayan bir head dinleyicisi stilinizi ve betiğinizi her panel sayfasına ekler. Controller üzerinden kapılayın; betik de yapılandırma nesnesi yokken erken dönsün.

> **Logo bir arayüz görseli değildir**
> 
> Panel simgesi, çözücünün baktığı modül kökünde kalır; kendi ekranlarınızdaki görseller varlık dizinine aittir. Ayrı tutmak, yeniden markalamayı arayüzü didiklemek yerine tek dosya yapar.

## İlgili Makaleler

- [Modül Anatomisi](https://dev.wisecp.com/tr/modul-anatomisi)
- [Modülden Kanca Kaydetme](https://dev.wisecp.com/tr/modulden-kanca-kaydetme)
- [Admin Sayfası Ekleme](https://dev.wisecp.com/tr/admin-sayfasi-ekleme)
- [Modül Yapılandırması](https://dev.wisecp.com/tr/modul-yapilandirmasi)
- [Admin JavaScript Kütüphanesi](https://dev.wisecp.com/tr/admin-javascript-kutuphanesi)
- [Tema Varlıkları](https://dev.wisecp.com/tr/tema-varliklari)
