Çekirdek dosyayı yamalamak neden bir yerde biter
Her mağaza er geç çekirdekte olmayan bir davranışa ihtiyaç duyar: sepete ekle düğmesinin altına bir teslimat notu, ERP’ye gönderilen bir alan. On yıl boyunca standart cevap OCMOD’du: çekirdek kaynakta bir kod satırını arayıp sizin kodunuzu etrafına ekleyen bir XML dosyası. O satır değişene kadar da kusursuz çalışır.
Sonra bir güncelleme dosyayı yeniden yazar, arama metni artık eşleşmez ve değişiklik sessizce uygulanmayı bırakır. İyi senaryo bu. Kötüsü, yaklaşık eşleşmedir: yama biraz farklı bir bağlama düşer ve bozuk değil yanlış bir sayfa üretir — bunu da bir müşteri fark edene kadar kimse görmez.
Event’ler ilişkiyi tersine çevirir. Kodunuzun başkasının dosyasının neresine sokuşturulacağını tarif etmek yerine, isteğin hangi noktasında çağrılmak istediğinizi söylersiniz ve sizi OpenCart çağırır. Güncellemeden sonra dosya bambaşka görünebilir, ama tetikleme noktası hâlâ oradadır. Bütün gerekçe bu; OpenCart 4’ün kendi hazır işlevlerinin önemli bir kısmını event’lerle kurmasının nedeni de bu.
- Event’ler, tanımlı bir noktada davranış eklemek, sarmalamak veya değiştirmek istediğiniz her yerde kazanır: bir kontrolcü çağrısı, bir model metodu, işlenmiş bir şablon, yüklenen bir dil dosyası.
- Event’ler, kendi tetikleyicisi olmayan bir Twig şablonunun derinindeki işaretlemeyi yeniden kurmanız gerektiğinde kaybeder — orada ya alt temada şablonu ezersiniz ya da işlenmiş çıktı üzerinde metin değiştirmeye düşersiniz.
- Event’lerin bedeli bir pakettir. Tek dosyalık event diye bir şey yok: eklenti klasörü, bir manifest ve bir kurulum yordamı gerekir. İki satırlık bir değişiklik için ağır gelir — ilk güncellemeye kadar.
Event aslında nedir
Event, oc_event tablosundaki bir satırdır: bir tetikleyici, bir eylem, bir durum ve bir sıra değeri. OpenCart açılışta etkin satırları okur ve her birini bir dinleyici olarak kaydeder. Dört tetikleyici ailesi var ve erişmek isteyeceğiniz hemen her yeri kapsıyorlar.
- Saklandığı yer
- oc_event
- Tetikleyici ailesi
- controller · model · view · language
- Çalışma sırası
- sort_order, artan
- Controller tetikleyicileri $this->load->controller() üzerinden yapılan çağrıların çevresinde işler; OpenCart sayfaları ve parçalarını böyle üretir.
- Model tetikleyicileri $this->load->model() ile ulaşılan her metodun çevresinde işler; böylece sorgunun sahibi olmadan veriyi izleyebilir veya şekillendirebilirsiniz.
- View tetikleyicileri $this->load->view() çevresinde işler — bir kez işleme öncesinde, veri dizisi hâlâ düzenlenebilirken; bir kez de sonrasında, elinizde işlenmiş HTML ile.
- Language tetikleyicileri $this->load->language() çevresinde işler; arayüz metinlerini tam bir dil paketi göndermeden eklemenin veya ezmenin temiz yolu budur.
Her ailenin bir before bir de after biçimi var. Handler argümanları referansla gelir; bütün mesele de budur: before içinde $args’ı değiştirmek asıl çağrının ne alacağını değiştirir, after içinde $output’u değiştirmek ziyaretçinin ne göreceğini değiştirir. Bir kural kendi cümlesini hak ediyor: değer döndüren bir before handler’ı asıl çağrının tamamının yerine geçer. Bu gerçekten kullanışlı bir araçtır ve bir sayfayı kazara boşaltmanın en kolay yoludur.
Kendi tetikleyici metninizi yazmadan önce kurulumunuzun hazır getirdiklerini okuyun:
SELECT code, `trigger`, action, sort_order
FROM oc_event
WHERE status = 1
ORDER BY `trigger`;Paket: tek klasör, tek manifest
OpenCart 4 eklentilere bir ev verdi. Gönderdiğiniz her şey extension/<kod>/ altında yaşar; kendi admin, catalog ve system ağaçları ve kökte bir install.json bildirimi ile. Rota, uygulama parçası çıkarılmış hâliyle klasör yolunu yansıtır; namespace de rotanın StudlyCase karşılığıdır.
extension/stock_note/
├── install.json
├── admin/
│ ├── controller/module/stock_note.php -> extension/stock_note/module/stock_note
│ ├── language/tr-tr/module/stock_note.php
│ └── view/template/module/stock_note.twig
├── catalog/
│ ├── controller/event/product.php -> extension/stock_note/event/product
│ └── language/tr-tr/module/stock_note.php
└── system/
└── library/stock_note/client.php
// install.json
{
"name": "Stock Note",
"version": "1.0.0",
"author": "Sirketiniz",
"link": "https://example.com"
}Namespace kuralı herkesi bir kez yakalar. extension/stock_note/catalog/controller/event/product.php dosyası Opencart\Catalog\Controller\Extension\StockNote\Event namespace’ini ve \Opencart\System\Engine\Controller’dan türeyen Product sınıfını tanımlar. Tek parçayı yanlış yazın, boş sayfa ve logda bir “class not found” satırı alırsınız — bu yüzden önce daima logu okuyun.
install() içinde kaydedin, uninstall() içinde temizleyin
Birisi eklentiyi Eklentiler ekranından kurduğunda veya kaldırdığında OpenCart yönetim kontrolcünüzdeki install() ve uninstall() metotlarını çağırır. Event satırları burada oluşturulur ve burada silinir. Başka hiçbir yerde değil: SQL’den elle eklenmiş bir event kaldırma işleminden sağ çıkar ve bir sonraki geliştiricinin başına iş açar.
<?php
namespace Opencart\Admin\Controller\Extension\StockNote\Module;
class StockNote extends \Opencart\System\Engine\Controller {
public function install(): void {
$this->load->model('setting/event');
$this->model_setting_event->addEvent([
'code' => 'stock_note',
'description' => 'Urun sayfasinda teslimat notu',
'trigger' => 'catalog/view/product/product/before',
'action' => 'extension/stock_note/event/product.note',
'status' => 1,
'sort_order' => 1
]);
}
public function uninstall(): void {
$this->load->model('setting/event');
$this->model_setting_event->deleteEventByCode('stock_note');
}
}Paket başına tek bir code kullanın ve kaldırırken o code ile silin. Aynı code altında birden çok tetikleyici kaydetmek sorun değil, tercih edilen yol da bu: tek silme hepsini kaldırır ve yeniden kurulum asla çift dinleyici bırakmaz. Notun iki kez basılmasının klasik nedeni bu mükerrer satırlardır.
Handler’ı yazmak
Handler, catalog ağacındaki sıradan bir kontrolcüdür. İmzası tetikleyici ailesine göre değişir: before handler’ları rotayı ve argümanları, after handler’ları rotayı, argümanları ve çıktıyı alır. Parametre adları sizin, sırası değil.
Teslimat notunun temiz sürümü şöyle görünüyor — şablon işlenmeden önce, veri dizisi hâlâ düzenlenebilirken çalışıyor, yani değerin nerede görüneceğine tema karar veriyor:
<?php
namespace Opencart\Catalog\Controller\Extension\StockNote\Event;
class Product extends \Opencart\System\Engine\Controller {
// catalog/view/product/product/before
public function note(string &$route, array &$data): void {
$product_id = (int)($this->request->get['product_id'] ?? 0);
if (!$product_id) {
return;
}
$this->load->language('extension/stock_note/module/stock_note');
$this->load->model('catalog/product');
$product = $this->model_catalog_product->getProduct($product_id);
if ($product && (int)$product['quantity'] > 0) {
$data['ships_in'] = $this->language->get('text_ships_today');
} else {
$data['ships_in'] = $this->language->get('text_backorder');
}
}
}Alt tema da {{ ships_in }} değerini ait olduğu yere basar. Bu tür bir handler’ı güvenli kılan iki alışkanlık var: id’yi $data içinde bir anahtarın var olduğuna güvenmek yerine istekten okumak ve varsaymak yerine erkenden çıkmak.
Şablona dokunmadan işaretlemeyi değiştirmek
Bazen şablonu düzenleyemezsiniz: sahibi olmadığınız, üreticisinin birkaç ayda bir güncellediği ticari bir tema. O zaman aynı tetikleyicinin after biçimini alır ve işlenmiş metin üzerinde çalışırsınız. Hızlıdır, meşrudur ve bu yazıdaki en kırılgan tekniktir; çünkü aradığınız çıpa, tam olarak bir tema güncellemesinin değiştirdiği şeydir.
// catalog/view/product/product/after
public function noteAfter(string &$route, array &$data, string &$output): void {
$anchor = '<div id="product">';
if (!str_contains($output, $anchor)) {
return; // tema degismis - sessizce cik, asla olumcul olma
}
$html = '<p class="ships-in">' . $this->language->get('text_ships_today') . '</p>';
$output = str_replace($anchor, $anchor . $html, $output);
}Çıpayı uzun ve kozmetik değil, kısa ve yapısal tutun; değiştirmeyi bir kez yapın; çıpa yoksa handler sessizce çıksın. View event’i içinde hata fırlatan bir handler, sayfanın tamamını da beraberinde götürür.
Event çalışmadığında
Event’ler tasarım gereği sessizce başarısız olur; o yüzden tahmin etmek yerine sabit bir sırayla ayıklayın:
- 1Satırın var ve etkin olduğunu doğrulayın: SELECT * FROM oc_event WHERE code = 'stock_note';
- 2Tetikleyici metnini, çalışan bir çekirdek satırıyla karakter karakter karşılaştırın.
- 3Eylemin çözümlendiğini kontrol edin: rota extension/<kod>/ altında gerçek bir dosyayı göstermeli, noktadan sonraki kısım da o sınıfta public bir metot olmalı.
- 4system/storage/cache ve tema önbelleğini temizleyin. OpenCart istekler arasında çoğu kişinin sandığından fazlasını önbelleğe alır.
- 5Eklentinin yalnızca yüklenmiş değil, kurulmuş olduğundan emin olun — yönetim listesine değil, oc_extension ve oc_extension_install tablolarına bakın.
- 6Handler’ın ilk satırına error_log(__METHOD__) koyun. Hiç basmıyorsa sorun sizin mantığınızda değil, kayıttadır.
- 7Aynı çıktıya iki eklenti dokunuyorsa sort_order’a bakın. Metin değiştirmeyi sonraki dinleyici kazanır ve hatanın tamamı bu sıradadır.
Event’lerin yanlış araç olduğu yerler
Event’ler evrensel bir cevap değil; öyleymiş gibi davranmak yavaş mağazalar üretir. Saygı duyulması gereken dört sınır:
- Mağaza tarafındaki handler’lar eşleşen her sayfa görüntülemesinde çalışır. Sizinki dış bir API çağırıyorsa, başkasının çalışma süresini kendi ödeme akışınızın içine koymuş olursunuz — kuyruğa yazın ve akış dışında işleyin.
- Event’ler veritabanı sütunu, rota veya yönetim menüsü girdisi oluşturamaz. Onlar install() işidir ve aynı pakete aittir.
- Değer döndüren bir before handler’ı asıl çağrının yerine geçer. Bunu bilinçli bir ezme olarak kullanın, bir koşulu atlamanın kısayolu olarak değil.
- Aynı HTML’i yeniden yazan iki eklenti, çalışma anında bir birleştirme çakışmasıdır. Şablon izin verdiği her durumda çıktı düzeyindeki tetikleyici yerine veri düzeyindekini tercih edin.
İyi yapıldığında kazanç sessizdir: OpenCart’ı güncellersiniz, mağaza teslimat notunu göstermeye devam eder ve kimse cumartesisini yamaları yeniden uygulayarak geçirmez.
Ne zaman bize yazın
Her güncellemede bozulan bir yığın OCMOD yamasıyla yaşıyorsanız, bunları event’lere çevirmek sınırları belli, tahmin edilebilir bir iştir. Lansman ücretiyle saatlik 10 $ + KDV üzerinden çalışırız, iş başlamadan saat sayısını veririz ve ilk mesajları Pazartesi–Cumartesi 09:00–22:00 arasında iki saat içinde yanıtlarız. Değişiklik listenizi ve OpenCart sürümünüzü gönderin.
Node.js ve Python ile API servisleri; test odaklı geliştirme.