Müşteri Paneli Köprüsü
Müşterinin tarayıcısından eklenti modülünüzün bir metodunu çağırırsınız. Operation zaten var: kendinize ait controller, rota ya da uç kaydetmezsiniz.
Genel Bakış
Müşteri panelindeki bir eklenti sayfası, modülünüzün ürettiği HTML'dir. Sonra bir şey yapması gerekir: tercih kaydetme, durum çekme, iş başlatma. Website tarafında hazır bağlanmış tek bir operation var ve adı use_ ile başlayan her metodu çağırır.
Admin panelde de aynı köprü var, tools controller'ının arkasında. Fark, kimin geçmesine izin verildiğidir; bu makalenin güvenlik kısmı da o farktır.
Ön Koşullar
- Yapılandırmasında
statusaçık olan bir Addon modülü; kapalı bir eklenti köprü için görünmezdir. - Bir web yüzü: müşteri paneli tercihi (
show_on_clientAreaartıclientArea()) ya da public birmain()sayfası. Biri yoksa köprü her çağrıyı reddeder. coremio/modules/Addons/SampleAddon, iki yüzün de çalışan bir gösterimi.
Yapı
/addon/{Ad} adresini çözer, sayfayı üretir ve köprü operation'ını dağıtır.
use_addon_method operation'ını ve eklentinizin web yüzü olup olmadığına karar veren kapıyı taşıyan trait.
$area_link, $error, $config, $lang, $dir, $url ve view() verir.
tarayıcı POST /addon/MyAddon operation=use_addon_method & method=save-preference
|
+-- addon controller -> addon_ctx() etkin yapılandırma + modül örneği + web yüzü?
+-- ClientAddon -> yüz müşteri paneliyse üye oturumu gerekir
+-- ad normalize -> 'save-preference' use_save_preference'a dönüşür
+-- method_exists -> yoksa reddedilir
+-- $module->use_save_preference() HİÇBİR argüman verilmeden çağrılır
+-- falsy dönüş -> Exception($module->error)
'-- dizi ya da dize -> JSON gövdesi
Adım Adım
Eklentiye Bir Web Yüzü Verin
config.phpiçindeshow_on_clientAreadeğerini açın ve['page_title' => …, 'breadcrumbs' => …, 'content' => …]döndüren birclientArea()metodu ekleyin. Bu,/addon/{Ad}adresini müşteri sayfası yapar ve giriş yapmış bir üye ister.- Ya da public bir sayfa için
main()metodu ekleyin; o sayfaya hiçbir oturum garantisi verilmez. - Güzel bir adres için
meta.slugayarlayın; controller$area_linkdeğerini ona göre yazar.
use_ Metodunu Yazın
- Modül sınıfında
use_{bir_şey}olarak adlandırın; başka hiçbir şey çağrılabilir değildir ve dağıtım katmanındaki sınırın tamamı bu önektir. - Parametre almayın. Girdiyi tıpkı bir operation gibi kendiniz
Filter::init("POST/…")ile okuyun. - Boş olmayan bir dizi ya da dize döndürün; falsy dönüş başarısızlık sayılır ve
$this->errortaşıyan bir exception fırlatır. - Gerçek bir hata için fırlatın: çağıran taraf bunu standart hata zarfına çevirir.
Sayfadan Çağırın
- Controller'ın doğru adrese yönelttiği
$this->area_linkadresine POST edin. Yolu elle yazmayın. operation=use_addon_methodvemethod={öneksiz ad}gönderin, metodunuzun okuduğu diğer alanlarla birlikte.- Website'te
X-Requested-Withbaşlığıyla düzfetch, admin paneldeWcpRequestkullanın.
Referans
İki Uç
| Yüz | Adres | Kim geçer |
|---|---|---|
| müşteri paneli | /addon/{Ad} ya da yapılandırılmış slug | giriş yapmış bir üye, eklenti tercih ettiyse |
| public sayfa | /addon/{Ad} | herkes, oturumsuz |
| eski takma ad | /addon/{Ad}/client | müşteri paneliyle aynı; tercih yoksa 404 |
| admin panel | tools eklenti adresi | tools yetkisi olan bir yönetici |
| website'ten çağrılan salt-admin eklenti | yukarıdakilerden herhangi biri | kimse: operation Addon not found. fırlatır |
O kontrol yokken salt-admin bir eklentinin use_* metotlarına website'ten oturumsuz ulaşılabiliyordu. Ayarlar eziliyor, talep verisi okunuyor, ücretli API kredisi yakılıyordu. Kapıyı dış duvar sayın, tek duvar değil.
Operation ve Ad Kuralı
public function use_addon_method(Operation $operation): bool;
$method = (string) Filter::init("REQUEST/method", "route"); // a-zA-Z0-9 - _ . korunur
$method = "use_" . str_replace([' ', '-', '.'], '_', $method); // boşluk, tire, nokta -> alt çizgi
if ($method === "use_" || !method_exists($module, $method))
throw new \Exception("Undefined addon method.");
$result = $module->{$method}(); // argüman YOK
if (!$result) throw new \Exception((string) (($module->error ?? '') ?: 'An error occurred'));
return $operation->output($result);
Yani save-preference, save.preference ve save_preference üçü de use_save_preference() metoduna ulaşır. route filtresi en başta çalışır ve yalnız a-zA-Z0-9, tire, alt çizgi ile noktayı korur; bu yüzden bir ad başka bir sınıfa kaçamaz.
Metodunuz Ne Döndürmeli
public function use_sample_method(): array|string;
| Döndürdüğünüz | Müşterinin aldığı | Ne için |
|---|---|---|
| boş olmayan dizi | o dizi, JSON olarak | olağan durum; standart anahtarları koruyun |
| boş olmayan dize | dize, olduğu gibi yazılır | DOM'a yerleştirilecek hazır HTML parçası |
[], '', false ya da null | $this->error değerinden kurulan {"status":"error","message":"…"} | hiçbir şey: eski bir yol, buna göre tasarlamayın |
| fırlatılan exception | {"status":"error","message":"mesajınız"} | her gerçek hata |
Hedeflenecek zarf panelin geri kalanıyla aynıdır:
return [
'status' => 'successful',
'message' => $this->lang['saved'] ?? 'Saved.',
'data' => ['preference' => $value, 'updated_at' => time()],
];
Taban Sınıfın Size Verdikleri
class AddonModule
{
public string|bool $error = ''; // metodunuz yanlış değer döndürünce köprü bunu okur
public array $config = []; // kaydedilmiş ayarlarla birleştirilmiş config.php
public array $lang = []; // lang/{selected}.php
public string $area_link = ''; // POST edilecek adres; her yüze göre YENİDEN YAZILIR
public string $_name = ''; // dizin adı
public array $user = []; // oturum açmış üye, varsa
public array $admin = []; // oturum açmış yönetici, varsa
public string $url = CORE_FOLDER . DS . MODULES_FOLDER . DS . 'Addons' . DS;
public string $dir; // modül dizininin dosya sistemi yolu
// Kurucu $url sonuna {Name} ekleyip onu public bir URL'e çözer; $dir, $config, $lang,
// $user ve $admin alanlarını doldurur ve $area_link değerini o anki yüze yöneltir.
public function __construct();
protected function view($file = '', $variables = []): string;
public function privileges();
public function save_settings($pFields, $accessPs): bool;
public function change_addon_status($arg = '');
public function save_config($data = []): bool;
public function use_default_settings($formElements = null);
public function isEnabled();
}
Panelde tools eklenti adresini gösterir. Website'te eklenti controller'ı onu public adresle değiştirir. Yol kurmak yerine onu gösterin.
Çekirdek Verisi Okuma
// $groupAction, rota kayıt defterindeki "Group/Action" değeridir; müşteri kayıt defteri için
// başına "client:" ekleyin, o durumda $input ayrıca owner_id taşımalıdır.
public static function internal(string $groupAction, array $input = [], array $query = []): array;
use WISECP\Api\Kernel;
// Süreç içinde: HTTP yok, kimlik doğrulama yok, hız sınırı yok; ama dış API'nin döndürdüğü
// zarfın AYNISI. $input önce yol parametrelerini, sonra gövdeyi doldurur.
$resp = Kernel::internal('Tickets/GetTicketMessages', ['id' => $ticketId], ['limit' => 50]);
$replies = $resp['data'] ?? [];
Bunu doğrudan yardımcı sınıf çağırmaya tercih edin: kaynak katmanı satırları çözülmüş, izin listesinden geçmiş ve normalize edilmiş verir.
Örnek
Tek bir müşteri tercihini saklayan bir müşteri sayfası.
<?php
namespace WISECP\Modules\Addons\MyAddon;
use Exception;
use Filter;
use Language;
use User;
use UserManager;
class MyAddon extends \AddonModule
{
/** config.php içinde show_on_clientArea true olduğunda /addon/MyAddon adresinde basılır. */
public function clientArea(): array
{
$member = UserManager::LoginData('member');
return [
'page_title' => $this->lang['meta']['name'] ?? 'My Addon',
'breadcrumbs' => [['link' => '', 'title' => $this->lang['meta']['name'] ?? 'My Addon']],
'content' => $this->view('client.php', [
'link' => $this->area_link, // buraya POST edin
'preference' => (string) (User::getInfo((int) $member['id'], ['my_addon_pref'])['my_addon_pref'] ?? ''),
]),
];
}
/**
* method=save-preference ile erişilir. Parametresizdir: girdisini tıpkı bir operation
* gibi kendisi okur ve hesabı, isteğin gönderdiği hiçbir şeye güvenmek yerine
* oturumdan yeniden okur.
*
* @throws Exception
*/
public function use_save_preference(): array
{
$member = UserManager::LoginData('member');
if (!$member) throw new Exception(Language::gc('website/index/addon-login-required') ?: 'Login required.');
$value = Filter::init('POST/preference', 'route');
if ($value === '' || !in_array($value, ['daily', 'weekly', 'never'], true))
throw new Exception($this->lang['err-bad-preference'] ?? 'Choose one of the offered options.');
User::AddInfo((int) $member['id'], ['my_addon_pref' => $value]);
return [
'status' => 'successful',
'message' => $this->lang['saved'] ?? 'Saved.',
'data' => ['preference' => $value],
];
}
}
<select id="ma-pref" class="form-select">
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="never">Never</option>
</select>
<button type="button" id="ma-save" class="btn btn-primary mt-2">Save</button>
<script>
(function () {
var link = ;
var btn = document.getElementById('ma-save');
var sel = document.getElementById('ma-pref');
if (!btn || !sel) return;
btn.addEventListener('click', function () {
btn.disabled = true;
var body = new URLSearchParams({
operation: 'use_addon_method',
method: 'save-preference', // tire sorun değil, use_save_preference olur
preference: sel.value
});
fetch(link, {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded' },
body: body
})
.then(function (r) { return r.json(); })
.then(function (r) {
if (r.status === 'successful') window.WCPTheme && window.WCPTheme.toast(r.message, 'success');
else window.WCPTheme && window.WCPTheme.toast(r.message, 'error');
})
.finally(function () { btn.disabled = false; });
});
})();
</script>
Aynı çağrının admin sayfasından yapılışı:
WcpRequest(AREA_LINK, {
method: 'POST',
data: { operation: 'use_addon_method', method: 'save-preference', preference: 'weekly' },
button: runBtn,
buttonLoader: window.saving_loader,
done: function (response) { // `done` yazmazsanız standart işleme uygulanır
output.textContent = JSON.stringify(response, null, 2);
}
});
Tuzaklar
Web yüzü main() olan bir eklentiye, eski modüllerle uyum gereği tasarım olarak oturumsuz erişilir. Her metot için "bunu kim çağırabilmeli" diye sorun ve o kontrolü metoda yazın.
Köprü ziyaretçiyi doğrular, kaydı değil. Müşteri kimliğini gövdeden okuyan bir metot, isteyene başka bir müşterinin verisini verir. Hesabı üye oturumundan okuyun.
Haklı olarak boş dönen bir sorgudan sonra [] döndürmek, hata özelliğinde ne varsa onu taşıyan bir hata zarfı üretir; çoğu zaman boş bir mesaj. Veri alanı boş liste olan bir dizi döndürün.
Standart ayar kaydı, alanlarınızla birlikte durum işaretini ve erişim yetkisi listesini de yazar; onu yeniden kullanan özel bir kaydetme eklentinizi kapatabilir. Özel kaydetmeye ayrı bir use_ metodu verin.
Bağlam çözücü örneği kurmadan önce etkinlik işaretine bakar, bu yüzden kapalı bir eklentiye yapılan çağrı metot hatası değil Addon not found. ile düşer. Önce durum işaretini kontrol edin.
İ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.