Modülden Kanca Kaydetme

1.9k görüntülenme Markdown

Modül dizininize bir hooks.php koyarsınız; bir modülün çekirdeğe dokunmadan uzanma biçimi budur.

Genel Bakış

Genişletmenin tamamı kancalar üzerinden yapılır. Bir modül, sahip olduğu tek dosyadan olayı yakalar, bir değeri değiştirir, işaretleme enjekte eder, yetenek kaydeder ya da bir işlemi reddeder. coremio/ içindeki hiçbir şey modülünüzün varlığını bilmez.

Katalog beş kategoride 979 kanca noktası taşıyor: ui 343, action 298, filter 196, gate 131, register 11. Ad tahmin etmek yerine kataloğa bakın.

Ön Koşullar

  • coremio/modules/{Tip}/{Ad}/ altında bir modül dizini; on altı tipin hepsi olur.
  • Kanca adı, hooks/INDEX.md dosyasından kopyalanmış olarak. Var olmayan bir ad sessizce başarısız olur.
  • O kancanın hooks/{domain}/ altındaki sayfası: parametreler, hangisinin referans olduğu ve dönüş sözleşmesi.

Yapı

classes/Hook.php Motor: kayıt, öncelik sıralaması, argüman eşleme ve dosyanızı bulan yükleyici.
{modül}/hooks.php Dinleyicileriniz. coremio/modules/*/*/hooks.php deseniyle bulunur: ad ve konum sabittir.
coremio/hooks/ Çekirdeğin kendi dinleyici dosyaları; aynı geçişte, modül dosyalarından önce yüklenir.
hooks/INDEX.md Üretilmiş katalog: her kanca noktası, domain'i ve onu tetikleyen dosya ile satır.
{modül}/router.php İkinci ve daha erken giriş noktası: router kurulurken, kanca dosyalarından önce yüklenir.

Adım Adım

Dosyayı Oluşturun

  1. Modül dizininizin köküne, {Ad}.php ve config.php dosyalarının yanına hooks.php ekleyin.
  2. Dosya include edilir; en üst seviyede düz ifadeler yazın.
  3. Kendi src/ dizininizdeki sınıflar otomatik yüklenmez; başvurmadan önce include_once ile yükleyin.

Kendi Durumunuzla Kapılayın

  1. Modülü kurmadan yapılandırmanızı yükleyin: yükleyiciye üçüncü argüman olarak true geçin.
  2. Her dinleyiciyi kendi etkinlik işaretinizin, lisanslı bir modülse lisansınızın kontrolüne sarın.
  3. Dosyayı ucuz tutun; bir kancaya dokunan her istekte çalışır.

Dinleyici Kaydedin

  1. Ekleme metodunu kanca adı, bir öncelik ve ya bir closure ya da bir tanım dizisiyle çağırın.
  2. Yalnız ihtiyacınız olan parametreleri bildirin; motor bunları konum sırasına göre eşler.
  3. Bir değeri değiştirmek için o parametreyi referansla bildirin; yalnız referanslı varyant onu geri taşır.

Öncelik Seçin

  1. Küçük olan önce çalışır. Varsayılan yoktur, bu yüzden sayıyı bilinçli geçin.
  2. Sonraki bir kaydı gölgelemek için küçük (rota ezmeleri böyle çalışır), en sona eklenmek için büyük bir sayı kullanın.

Referans

Kayıt

tam imzalar
class Hook
{
    // $properties YA bir callable YA da bir tanım dizisidir (aşağıdaki üç biçime bakın).
    public static function add($name, $priority, $properties = []): void;

    public static function run($name, ...$args): array;        // değerle
    public static function runRefs($name, &...$args): array;   // HER argüman referansla
    public static function runDetailed($name, ...$args): array; // dinleyici başına telemetri
}
Çalıştırma metoduDöndürdüğüDinleyici exception fırlatırsa
runnull olmayan her dönüş, öncelik sırasındaloglanır, sonraki dinleyici çalışır
runRefsaynısı, ayrıca referans düzenlemeleriniz çağırana ulaşırloglanır, sonraki dinleyici çalışır
runDetailed[['source' => ['type','class','method','file','line'], 'value' => …, 'error' => ?string], …], null'lar korunurerror alanına yazılır
hepsi, bilinmeyen adboş dizihiçbir şey olmaz; yazım hatası sessizdir

Üç Kayıt Biçimi

üç biçim
// 1. Closure. Çağrılabilir olan her şey doğrudan girer.
Hook::add('action:service.created', 10, function ($id, $data) {
    // ...
});

// 2. Örnek metodu. Sınıf argümansız olarak BİR KEZ kurulur ve istek boyunca
//    önbellekte tutulur, bu yüzden yapıcısı parametresiz çalışmalıdır.
Hook::add('filter:invoice.totals', 10, [
    'class'  => 'MyAddonHooks',
    'method' => 'adjustTotals',
]);

// 3. Statik metot. Hiçbir şey kurulmaz.
Hook::add('ui:admin.service_detail.bottom', 10, [
    'class'          => 'MyAddonHooks',
    'method::static' => 'renderPanel',
]);

Sınıf bulunamazsa ya da metot yoksa dinleyici null döner ve istek devam eder. Bu tam olarak hiç tetiklenmemiş bir kanca gibi görünür. Closure tercih edin.

Argümanlar Dinleyicinize Nasıl Ulaşır

eşleme kuralı
// Dinleyicinizin $i konumunda bildirdiği her parametre için:
//   referansla bildirilmiş VE $i konumunda argüman var  -> referansla geçirilir
//   $i konumunda argüman var                            -> değerle geçirilir
//   $i konumunda argüman yok                            -> parametre düşürülür,
//                                                          yani varsayılanınız geçerli olur
$callArgs = [];
foreach ($reflection->getParameters() as $i => $param) {
    if ($param->isPassedByReference() && isset($args[$i])) $callArgs[] = &$args[$i];
    else if (isset($args[$i])) $callArgs[] = $args[$i];
}

Kancanın verdiğinden az parametre bildirmek güvenlidir. Bir referans, değişikliğinizi ancak kanca referanslı varyantla tetiklendiyse geri taşır. Değer geçen bir kancada &$deger sessizce hiçbir şeyi değiştirmez.

Beş Kategori ve Her Birinin Beklediği Dönüş

ÖnekDinleyiciniz ne yaparDönüş değeriniz
action:bir olaya tepki veriryoksayılır
filter:bir değeri kullanılmadan önce değiştirirdüzenleme referans parametresi üzerinden gider
ui:işaretleme, stil ya da script enjekte ederbasılacak dize
register:bir yetenek kaydeder: cron görevi, rota, menü öğesi, widgetkayıt verisi, ya da hiçbir şey kaydetmemek için false
gate:bir işlemi veto ederboş olmayan değer engeller, null devam ettirir

Ad kategori:domain.subject.action biçimindedir; küçük harf, parçalar snake_case. Bir ui: adı yerleştirme kelimesiyle biter: dinleyicisine bağlam verilmez, hedefi addan çıkarır.

Kanca Dosyasında Kendi Yapılandırmanızı Okuma

tam imzalar
// $nominc = true, sınıfı dahil ETMEDEN yapılandırmayı ve dil dosyasını yükler.
public static function Load($type = '', $name = '', $nominc = false, $status = '');
public static function Config($type, $module);
public static function getInstance(string $type, string $name, array $params = []): ?object;
kapı
Modules::Load('Addons', 'MyAddon', true);              // yalnız yapılandırma, sınıf yok
$my_config = Modules::Config('Addons', 'MyAddon') ?: [];

if (($my_config['status'] ?? false) && License::valid_addon('my-addon')) {
    // ... dinleyicileri burada kaydedin
}

Örneği bir dinleyicinin içinde kurun. Kayıt yapıp yapmayacağınıza karar vermek için modülü her istekte kurmak, bir modülün paneli yavaşlatmasının en yaygın sebebidir.

Örnek

Dört noktaya dokunan bir kanca dosyası: bir olay, bir değer, bir sayfa ve zamanlanmış bir görev.

MyAddon/hooks.php
<?php

// src/ sınıfları otomatik yüklenmez: bu dosyanın andığı şeyi, anmadan önce include edin.
include_once __DIR__ . DS . 'src' . DS . 'Notifier.php';

use WISECP\Modules\Addons\MyAddon\Src\Notifier;

// Sınıfsız yapılandırma. Tek ucuz çağrı, aşağıda bir şey kaydedilip kaydedilmeyeceğine karar verir.
Modules::Load('Addons', 'MyAddon', true);
$my_config = Modules::Config('Addons', 'MyAddon') ?: [];

if (!($my_config['status'] ?? false)) return;

/* Bir olay. Bu kanca ($id, $data) ile tetiklenir: yeni users_products kimliği ve eklenen
   satır. Dönüş değeri yoksayılır, yani işi yapın ve hiçbir şey söylemeyin. */
Hook::add('action:service.created', 10, function ($id, $data) {
    Notifier::service_created((int) $id, is_array($data) ? $data : []);
});

/* Bir değer. $totals REFERANSLA bildirilir, çünkü bu kanca runRefs ile tetiklenir;
   $invoice ve $items salt okunur bağlamdır. */
Hook::add('filter:invoice.totals', 10, function (&$totals, $invoice, $items) {
    if ((int) ($invoice['legal'] ?? 0) !== 1) return;

    $fee = (float) ($GLOBALS['my_addon_fee'] ?? 0);
    if ($fee <= 0) return;

    $totals['total'] = round((float) $totals['total'] + $fee, 4);
});

/* İşaretleme. Dizeyi döndürün; yüzey onu basar. Örneği YUKARIDA değil BURADA kurun. */
Hook::add('ui:admin.service_detail.bottom', 20, fn ($service) =>
    Modules::getInstance('Addons', 'MyAddon')->render_service_panel(is_array($service) ? $service : []));

/* Bir yetenek. Kayıt kancaları besledikleri şeyin bootstrap'ı sırasında koşar. */
Hook::add('register:cronjobs', 1, function () {
    include_once __DIR__ . DS . 'cronjobs' . DS . 'SyncTask.php';

    CronJobQueue::register(
        \WISECP\Modules\Addons\MyAddon\CronJobs\SyncTask::TYPE,
        \WISECP\Modules\Addons\MyAddon\CronJobs\SyncTask::class
    );
});

Okuma tarafı: yukarıdaki değer kancasını tetikleyen çekirdek çağrısı.

çekirdek onu nasıl tetikler
// coremio/helpers/Invoices.php, recalculate_totals() içinde: rakamlar kurulduktan sonra
// ve satıra yazılmadan önce.
Hook::runRefs('filter:invoice.totals', $totals, $invoice, $items);

// $totals artık dinleyicilerin içinde bıraktığı şeydir ve $persist onu yazar.

Kendi modülünüz bir genişletme noktası yayınladığında aynı özen geçerlidir:

kendi kancanızı tetiklemek
// Değerle: diğer modüllerin izleyebileceği bir olay.
Hook::run('action:myaddon.sync_finished', $summary, $startedAt);

// Referansla: burada bağlam olanlar dahil HER argüman referanstır, bu yüzden her biri
// önce düz bir değişken olmalıdır.
$context = ['id' => $recordId, 'lang' => Language::selected()];
Hook::runRefs('filter:myaddon.payload', $payload, $context);

// Bir kapı: herhangi bir dinleyiciden gelen boş olmayan dönüş işlemi durdurur.
$veto = Hook::run('gate:myaddon.export', $recordId);
if (array_filter($veto)) throw new Exception((string) current(array_filter($veto)));

Tuzaklar

Referanslı varyantın her argümanı referanstır, bağlam olanlar dahil

İmza variadic ve referanslıdır. Herhangi bir konumdaki sabit, cast, fonksiyon dönüşü ya da null-birleştirme ifadesi ölümcül hatadır. Her birini önce düz bir değişkene alın; değer geçen varyantta bu sorun yoktur.

Dinleyici içindeki exception yutulur

Motor her throwable'ı yakalar, loga yazar ve devam eder. Entegrasyonunuz gerçekleşmez, sayfa normal görünür, hiçbir şey bunu söylemez; en sık sebep unutulmuş bir include_once'tur. Dinleyici hareketsiz görünüyorsa önce hata logunu okuyun.

İlk kancadan önce koşması gereken iş buraya ait değildir

Kanca dosyaları tembel okunur, ilk çalıştırma çağrısında; kuruluş tarihi sıfır tarihiyken hiç okunmaz. Daha erken gereken her şey (bir rota, bir izin kataloğu) router kurulurken yüklenen router.php dosyasına konur.

Dosya gövdesi bir kancaya dokunan her istekte çalışır

En üst seviyede modülünüzü kurmak, veritabanına sormak ya da bir servise çıkmak bunun bedelini her seferinde, müşteri sayfaları dahil ödetir. Yapılandırmayı sınıfsız yükleyiciyle okuyun ve örneği dinleyicinin içinde kurun.

Öncelik çakışması çözülür, bildirilmez

Aynı sayıyla iki dinleyici kaydetmek ikincisine bir sonraki boş yuvayı verir; sıra kayıt sırasını, o da modül dizinlerinin alfabetik sırasını izler. Kalabalıktan uzak bir sayı seçin.

Faydalı oldu mu?

Geri bildiriminiz için teşekkürler!

Hâlâ Yardıma mı İhtiyacınız Var?

Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.