Çekirdeğe Dokunmadan Çalışma
Platformun yayımladığı genişleme noktalarının işlenmiş bir kataloğu: her birinin neye ulaşıp neye ulaşamadığı ve önünüzdeki değişiklik için doğrusunun nasıl seçileceği.
Genel Bakış
Aşağıdaki her noktanın adı belli bir giriş dosyası, bir sözleşmesi ve bir sınırı var.
Noktalar birbirinin dengi değil. Bir kanca yalnız yayımlanmış olduğu yere uzanır. Bir modül kendi dizinine, kendi tablolarına ve kendi ayarlarına sahiptir ama on altı tip sözleşmesinden birine sığmak zorundadır. Bir tema website'i kapsar, admin panelinde karşılığı yoktur.
Ön Koşullar
- Arkasında bir nokta olmayan dosyaya yükseltme koşusunun ne yaptığı için Güncellemeye Dayanıklı Çalışma İlkeleri.
- Sistem dizinine yazma erişimi ve görebildiğiniz bir sayfayı yenileyebilme imkânı.
- Adı konmuş bir hedef: değiştirmek istediğiniz ekran, akış ya da değer. "Ödeme akışını değiştirmek", "sepet toplamı filtresinin verdiği değeri değiştirmek" hâline gelir.
Yapı
Genişleme Noktası Haritası
Değiştirdiğiniz şeye uyan satırı bulun, sözleşmesini aşağıdan okuyun.
| Neyi değiştirmeniz gerekiyor | Nokta | Sınırı |
|---|---|---|
| Çekirdeğin hesapladığı bir değer (toplam, liste, veri yükü) | Bir filter: kancası | Yalnız yayımlanmış olan yerde. Jenerik bir "her metottan önce" araya girme yoktur |
| Olan bir şeye tepki verme (eşitleme, bildirim, denetim kaydı) | Bir action: kancası | Dönüş değeriniz atılır, istisnanız yutulur; loglamazsanız hatalarınız görünmez |
| Kendi kuralınıza göre bir işlemi reddetme | Bir gate: kancası | Reddet ya da izin ver, arası yok. İşlemi değiştiremezsiniz |
| Mevcut bir sayfaya işaretleme ekleme | Bir ui: kancası | Yalnız var olan konumlarda. Admin paneli için şablon geçersiz kılma katmanı yoktur |
| Bir şey sağlama, ödeme alma, ad tescili, mesaj gönderme | Uygun tipte bir modül | On altı tip, her biri sabit bir metot sözleşmesiyle. Hiçbirine sığmayan ihtiyacın modül tipi yoktur |
| Tümüyle size ait bir admin sayfası | Modül admin alanı | On altı tipin on birinde tanınır; kalanlar sessizce hiçbir şey olarak kaydedilir |
| Size ait bir HTTP ucu | API rota filtresi | İşleyiciniz modül örneğinde gerçek bir metot olmalıdır. Toplayıcı bir dağıtım yoktur |
| Mevcut bir sayfada yeni bir admin AJAX işlemi | Admin operation yedek kancası | Sarmalayıcı korumalarının hiçbiri geçerli değildir: yetki kontrolü, demo kapısı ve istek başlığı kontrolü yok |
| Zamanlanmış iş | Modülden kaydedilen bir cron işleyicisi | Yeniden deneme ve zamanlama kuyruğundadır. Diliminizin ne zaman koşacağını siz seçmezsiniz |
| Ziyaretçiye dönük görünüm | Bir tema dizini | Yalnız website. Admin paneli, tema katmanı olmayan düz PHP şablonlarıdır |
| Bir bileşen metninin ifadesi | Çeviri filtresi | Yalnız bileşen okumaları. Paket seviyesindeki metinlerin okuma anı filtresi yoktur |
| Şablona ulaşan değişkenler | Şablon değişkeni filtresi | Değerle çalışır ve dizi döndüren son dinleyici tüm kümenin yerine geçer |
| Müşteri, talep ya da ürün kaydındaki veri | Operatörün tanımladığı özel alanlar | Kod değil yapılandırma. Depolama ve gösterim alırsınız, davranış değil |
Dosyalar Nereye Gider
Hepsini tek bir dizin taşır; yukarıdakilerin hiçbiri bu ağacın dışına uzanmaz.
Acme.php # çekirdeğin örneklediği modül sınıfı
config.php # ayarlar; modül yazar, bir sürüm asla yazmaz
hooks.php # otomatik dahil edilir: her Hook::add burada yaşar
router.php # admin yönlendirmesi için otomatik dahil edilir: admin alanını kaydeder
AdminArea.php # size ait admin sayfaları
lang/en.php # metinleriniz, istediğiniz gibi anahtarlanmış
cronjobs/Sync.php # zamanlanmış işleyiciniz, hooks.php'den kaydedilir
src/AcmeClient.php # size ait düz sınıflar, `new` ile kurulur
Kanca yükleyicisi her modül dizinindeki hooks.php dosyasını tarar, admin yönlendirmesi de router.php dosyasını okur. Diğer her şeye bu ikisinden ulaşılır: açık bir include_once ile ya da çekirdeğin sizin için kurduğu modül sınıfı üzerinden.
Adım Adım
Gerçekte Neyi Değiştirdiğinizin Adını Koyun
- Ekranı açın ve değiştirmek istediğiniz tam değeri, kontrolü ya da anı bulun.
- Onu üreten kodu bulun. Ekrandaki metni, formdaki alan adını ya da adresteki rota anahtarını arayın, değerin sahibi helper'a ya da operation'a kadar geri izleyin.
- Beş fiilden hangisinin geçerli olduğuna karar verin. Bir değeri dönüştürmek, bir olaya tepki vermek, bir eylemi reddetmek, işaretleme basmak, listeye kayıt eklemek. Kanca kategorisi o fiildir.
Noktayı Seçin
- Değişikliğinizin yaşadığı alanı
hooks/INDEX.mdkataloğunda arayın. Dizin her kancayı alanıyla ve tetiklendiği tam dosya ve satırla verir. - Kanca varsa önce parametre tablosunu okuyun. Bir argümanın referansla gelip gelmediği o sayfadadır ve dinleyicinizin nasıl yazılacağına o karar verir.
- Kanca yoksa ama iş bütün bir yetenekse (bir panel, bir geçit, bir sağlayıcı) bu bir modüldür. Seçtiğiniz tip, çekirdeğin çağıracağı metotları sabitler.
- İkisi de uymuyorsa çekirdeği yamalamak yerine jenerik bir genişleme noktası isteyin. Modülünüzün, bayrağınızın ya da tablonuzun adını taşıyan kanca jenerik değildir; kararın adını taşıyan kanca jeneriktir.
Kaydedin
- Modül dizininizde
hooks.phpyoksa oluşturun. İstek başına bir kez, ilk kanca etkinliğinde otomatik olarak dahil edilir. - Dosyanın tamamını modülünüzün etkin olmasına bağlayın. Yapılandırmayı hafif kipte yükleyip durumu okuyun, kaydı ondan sonra yapın.
- Bir öncelikle kaydedin. Düşük olan önce çalışır, alınmış bir numara boş bulunana kadar artırılır; hiçbir dinleyici sessizce düşmez.
- Modül örneğini dosyanın başında değil dinleyici gövdesinin içinde, kanonik fabrikayla kurun.
Sağ Çıkacağını Kanıtlayın
- Sayfayı yenileyin ve davranışın değiştiğini doğrulayın. Kaydı düzgün ama gövdesi hata fırlatan bir dinleyici, hiç ateşlenmemiş bir kancayla birebir aynı görünür. Hata yakalanır ve loglanır.
- Kendi ağacınızda çekirdek yollarını arayın. Düzenlediğiniz,
coremio/classes,coremio/controllers,coremio/helpersya datemplates/adminaltındaki her şey bir gelecek arızadır. - Kendi dizininizin dışından çağırdığınız her kancayı, sınıfı ve metodu listeleyin. O liste, bir yükseltmeden sonra yeniden kontrol edeceğiniz uyumluluk sözleşmesidir.
- Modülü kapatın ve sayfayı yenileyin. Ekran hatasız biçimde kendi varsayılan davranışına dönmelidir. Dönmüyorsa size ait bir şey durum kapısının dışında çalışıyordur.
Referans
Kayıt İmzaları
// coremio/classes/Hook.php
public static function add($name, $priority, $properties = []): void;
// coremio/classes/Modules.php - sınıfı dahil etmeden yapılandırmayı yükler ($nominc = true),
// sonra okur. hooks.php içinde ucuz bir "modülüm açık mı?" kapısı için ikisi de gerekir.
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;
// coremio/classes/ModuleAdminArea.php - modülün router.php dosyasından çağrılır.
public static function register(string $areaClass): void;
public static function get(string $type, string $name): ?array;
// coremio/helpers/CronJobQueue.php - bir register:cronjobs dinleyicisinden çağrılır.
public static function register(string $type, string $handlerClass): void;
public static function dispatch(string $type, array $payload = [], array $opts = []): int;
// coremio/cronjobs/CronJobHandler.php - bir ARAYÜZDÜR, yani genişletmeyin, uygulayın.
// Başarı için true, başarısız olup yeniden denenmek için false, ya da admin Sonuçlar
// sekmesine bir yük de vermek için ['success' => bool, 'result' => array] döndürün.
public function handle(array $payload, array $job): bool|array;
$nominc = true, modül sınıfını dahil etmeden config.php ve dil dosyasını yükler. Kapı biçimi budur: hooks.php içinde her istekte koşacak kadar ucuzdur.
Load() çağrılmadan çağrılırsa hiçbir şey dönmez; bu "modül kapalı" diye okunur ve dosyanızın tamamını kapatır. Sıra isteğe bağlı değildir.
slug, slug/(?), slug/(?)/(?)) ve menü kaydını yapar. Sınıfı reddettiğinde de dahil olmak üzere hiçbir şey döndürmez.
TYPE sabiti, ikincisi sınıf adıdır. Keşif işleyicisi (.discover ile biten bir tip) ayrıca bir FREQUENCY sabiti ister; zamanlayıcının okuduğu değer odur.
Her Nokta Karşılığında Ne Bekler
| Kanca | Ateşlenmesi | Sözleşme |
|---|---|---|
register:admin.operations | run(), argümanlar: controller adı, operation adı | Reddetmek için null döndürün. Dizi döndürürseniz JSON'a çevrilip yanıtın tamamı olarak gönderilir |
filter:api.routes | runRefs(), argümanlar: referansla rota listesi, referansla hedef kitle | Listeye demet ekleyin. Dönüş değeri kullanılmaz. İlk eşleşme kazanır, gölgelemeye öncelik karar verir |
register:cronjobs | run(), argümansız | İşleyici dosyanızı dahil edin ve kuyruğun kayıt metodunu çağırın. Dönüş değeri kullanılmaz |
filter:i18n.translation | runRefs(), argümanlar: referansla metin, anahtar, dil kodu | Metni yerinde değiştirin. Yalnız bileşen okumalarında ve yalnız çözülen değer bir dize olduğunda ateşlenir |
filter:template.variables | run(), argümanlar: şablon yolu, veri dizisi | Değiştirilmiş veri dizisinin tamamını döndürün. Dizi döndüren son dinleyici tek başına kazanır |
register:admin.menu | run(), argümansız | Menü ağacına yazıp true döndürün ya da hiçbir katkı yapmamak için false döndürün |
// [0] METHOD [1] desen (/api/v1 sonrasındaki tam yol, {x} yakalar)
// [2] Group [3] Action [4] public? [5] authOnly? [6] audience
$routes[] = ['GET', 'acme/status', 'Module:Addons/Acme', 'status', false, true, 'admin'];
// "Module:{Type}/{Name}" grubu, modül örneğinin şu metoduna dağıtır
// api_{Action}(WISECP\Api\Core\Request $request, array $match)
// ve kararı method_exists verir: __call yedeği yoktur. [3] içindeki bir yazım hatası
// görebileceğiniz bir hata değil, 404'tür.
//
// [4] public = true → hiç kimlik bilgisi yok; modül kendi erişimini kendi denetler
// [5] authOnly = true → geçerli bir kimlik bilgisi yeter, kapsam kontrol edilmez (serbest
// yüzeydeki varsayılan, çünkü modül kapsamları katalogda değildir)
// [6] audience → 'admin' | 'client' | 'any', yalnız public false iken bakılır
Genişleme Noktasının Olmadığı Yerler
Dört boşluk. Hiçbirinin desteklenen bir kaçamağı yok.
ui: kancasıdır. Olmayan bir konum yeni bir kanca talebidir.
register() hiçbir şey yapmadan, hiçbir yerde hata bırakmadan döner. Yanına bir Addons modülü koyun ya da tipin eklenmesini isteyin.
Örnek
Dört noktayı kullanan, kendi dizininin dışına dokunmayan küçük bir eklenti.
<?php
// Ucuz kapı: yalnız yapılandırma, sınıf dahil edilmez. Aşağıdaki her şey if'in içinde,
// yani kapalı bir modül hiçbir şey kaydetmez ve yalnız bir dosya okuması kadar tutar.
Modules::Load('Addons', 'Acme', true);
$acme = Modules::Config('Addons', 'Acme') ?: [];
if ($acme['status'] ?? false) {
// 1. Bu modülün sahibi olmadığı bir sayfadaki AJAX eylemi. services controller'ında
// operation=acme_resync olarak ulaşılır. Bu çağrıyı hiçbir şey sarmalamaz,
// yani yetki kontrolünü yapmak bize düşer.
Hook::add('register:admin.operations', 1, function ($cname, $operation) {
if ($operation !== 'acme_resync') return null;
if ($cname !== 'services') return null;
if (!Admin::isPrivilege(['SERVICES_OPERATION']))
return ['status' => 'error', 'message' => Language::gc('acme/no-privilege')];
return Modules::getInstance('Addons', 'Acme')->resync_request();
});
// 2. Kimlik bilgisi isteyen admin yüzeyinde bize ait bir uç.
Hook::add('filter:api.routes', 1, function (&$routes, &$audience) {
if ($audience !== 'admin') return;
$routes[] = ['GET', 'acme/status', 'Module:Addons/Acme', 'status', false, true, 'admin'];
});
// 3. Zamanlanmış bir görev. Dosya açılışta değil burada dahil edilir: cron kaydı
// yalnız çekirdek dizinini tarar.
Hook::add('register:cronjobs', 1, function () {
include_once __DIR__ . DS . 'cronjobs' . DS . 'Sync.php';
CronJobQueue::register(\WISECP\Modules\Addons\Acme\CronJobs\Sync::TYPE,
\WISECP\Modules\Addons\Acme\CronJobs\Sync::class);
});
// 4. Bir dil dosyasını düzenlemeden tek bir bileşen metnini yeniden ifade edin.
// Referansla ve yalnızca ifadesinin sahibi olduğumuz tam anahtar için.
Hook::add('filter:i18n.translation', 1, function (&$text, $key, $lang) {
if ($key !== 'admin/services/status-active') return;
$text = Language::gc('acme/status-live');
});
}
İlk noktanın diğer tarafı. Metot, çekirdeğin kodladığı diziyi döndürür; yanıtın şeklinin sahibi odur.
public function resync_request(): array
{
$id = (int) Filter::init('POST/id', 'rnumbers');
if (!$id) return ['status' => 'error', 'message' => Language::gc('acme/id-required')];
// Fırlatmak, modülün başarısızlığı bildirme yoludur; burada bir AJAX çağrısını
// doğrudan yanıtlıyoruz, dolayısıyla hatayı bunun yerine elle şekillendiriyoruz.
try {
$rows = $this->client()->resync($id);
}
catch (\Throwable $e) {
return ['status' => 'error', 'message' => $e->getMessage()];
}
return ['status' => 'successful', 'message' => Language::gc('acme/resynced'), 'count' => $rows];
}
// Yukarıda kaydedilen API ucu buraya iner. Ad, api_ artı demetteki Action'dır
// ve kararı veren tek şey method_exists'tir.
public function api_status(\WISECP\Api\Core\Request $request, array $match): array
{
return ['data' => ['enabled' => true, 'last_sync' => Config::getd('acme_last_sync')]];
}
Admin sayfası: iki dosya ve tek satırlık bir kayıt.
// coremio/modules/Addons/Acme/router.php
namespace WISECP\Modules\Addons\Acme;
include_once __DIR__ . DS . 'AdminArea.php';
\ModuleAdminArea::register(AdminArea::class);
// coremio/modules/Addons/Acme/AdminArea.php
namespace WISECP\Modules\Addons\Acme;
class AdminArea extends \ModuleAdminArea
{
public static function manifest(): array
{
return [
'title' => 'Acme',
'slug' => 'acme',
'privileges' => ['TOOLS_ADDONS'],
'menu' => ['path' => ['TOOLS'], 'name' => 'Acme'],
];
}
// /{admin}/acme → page_home()
// /{admin}/acme/report → page_report()
public function page_home(array $params): string|array
{
return ['content' => '<p>Acme</p>', 'page_title' => 'Acme'];
}
// Aynı adrese operation=refresh ile POST
public function op_refresh(\Operation $operation): bool
{
$operation->demo();
return $operation->output(['status' => 'successful']);
}
}
Tuzaklar
Normal bir operation bir sarmalayıcıdan geçer. O sarmalayıcı yetki listesini kontrol eder, panelin AJAX katmanından gelmeyen isteği reddeder ve demo kipinde yazmaları engelleyen nesneyi kurar. Yedek kancasına ancak sarmalayıcı reddettikten sonra ulaşılır, yani bunların hiçbiri geçerli değildir. Yetkiyi kendiniz, dinleyicinin içinde, ilk iş olarak kontrol edin.
Değerle ateşlenir ve çağıran, dönen her diziyi bir öncekinin üzerine atar. Dizi döndüren son dinleyici kümenin tamamının yerine geçer; aynı şablondaki iki dinleyici birleşmez. Size verilen diziyi okuyun, değiştirin ve tamamını döndürün.
Kayıt üç durumda hiçbir şey yapmadan döner. Sınıf bir alt sınıf değilse, ad alanı beklenen biçimde değilse ya da modül tipi tanınan on bir tipten biri değilse. İstisna yok, log satırı yok, menü kaydı yok. Sayfanız bulunamadı verdiğinde önce tipe bakın.
Kanca yükleyicisi, kancalarınızdan biri ateşlenecek olsun ya da olmasın dosyayı dahil eder. Bir dinleyici gövdesinin dışına yazılmış veritabanı sorgusu, uzak çağrı ya da modül örneği oluşturma her sayfa yüklemesinde ödenir. Yapılandırmayı yükleyin, durumu kontrol edin, geri kalanı bir closure'ın içine koyun.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.