Özel Operation Ekleme
Rota ve hata biçimi icat etmeden, veri değiştirip JSON yanıt veren bir POST ucu ekleyin.
Genel Bakış
Operation, veri değiştiren ve JSON ile yanıt veren bir metottur. Var olan bir controller'a operation parametresi gönderirsiniz: rota kaydı yoktur. Controller adı çözer, yetkileri kontrol eder, fırlattığınızı hataya çevirir.
Operation'lar trait'lerde yaşar ve controller'a use ile eklenir. Metot, controller'ın modeline ve yardımcılarına erişir.
Ön Koşullar
- Genişlettiğiniz sayfaya zaten yanıt veren bir controller, yönetici ya da müşteri tarafında.
- Operatör panelinde bir yetki anahtarı; boş tanımı oturum açan herkes çağırabilir.
- Bir çağıran:
status,messageveredirectanahtarlarınızı panelin istek yardımcısı işler.
Yapı
| Parça | Nerede | Ne taşır |
|---|---|---|
| Trait | coremio/operations, ad alanı WISECP\operations | Operation başına bir public metot |
| Controller | coremio/controllers, yönetici ya da website | Trait için use ve tanım dizisi |
| Çağıran | Bir şablon ya da kendi JavaScript'iniz | operation ve alanlarınızı gönderir, JSON'u okur |
Adım Adım
Metodu Yazın
- Bir trait'e public metot ekleyin: tek parametresi operation nesnesi, dönüşü
bool. - Metot yazıyorsa ilk satırda demo korumasını çağırın.
- Girdileri filtre yardımcısıyla okuyun, ham istek dizilerine dokunmayın; parola kendi temizleyicisini ister.
- Doğrulamayı fırlatarak yapın; kurulacak bir hata dönüş değeri yoktur.
- Yanıtı, after kancasının değiştirebileceği bir değişkenden çıktı yardımcısıyla döndürün.
Tanımlayın
- Trait'i içe aktarın ve controller sınıfında
useile ekleyin. - Gönderilen adla anahtarlayıp yapıcıdaki tanım dizisine ekleyin.
- Sayfanın kullandığı yetkileri verin; kontrol metottan önce çalışır.
- Giriş metodunun dağıtıcıya devrettiğini doğrulayın; müşteri controller'ı bunu açıkça yapar.
Çağırın
- Controller'ın kendi adresine,
operationadınıza ayarlı olarak gönderin. - İsteği asenkron çağrı olarak gönderin; yönetici operation'ı öyle görünmeyeni reddeder.
- Standart anahtarlar: mesaj bildirim olur, yönlendirme gider,
reloadyeniler. - Geri çağırmaları yalnız bu anahtarların yapamadığı iş için kullanın.
Referans
Operation Nesnesi
class Operation
{
public ?string $name = ''; // gönderilen operation adı
public static ?string $last = ''; // istek başına kurulan son ad
// Dağıtıcı kurar: $properties, tanım dizisindeki kayıttır.
public function __construct($name = '', $properties = []);
// Tanıtım sisteminde fırlatır. Yazan her operation'ın ilk satırı.
public function demo(): void;
// Kancayı ateşler ve cevapları normalize eder. 'before' ve 'after', iki genel
// admin-operation filtresinin kısaltmasıdır; başka bir dize olduğu gibi kullanılır.
// Dönüş: [] ya da ['overwrite' => array] ya da ['output' => mixed].
public function hook(string $name = '', array $vars = []): array;
// Yanıtı gönderir. Dizi, JSON başlığı kurularak JSON'a çevrilir; başka her şey
// olduğu gibi basılır. Her zaman true döner, yani `return $op->output(...)`
// bool dönüş tipini karşılar.
public static function output($response): bool;
public static function name(): ?string;
public function assertContext(): void;
public static function resolveContext(): bool;
}
Tanım Dizisi
$this->operations = array_merge($this->operations, [
// Yaygın biçim: gönderilen ad => çalıştırmak için gereken yetkiler.
'save_acme_settings' => ['privileges' => ['SETTINGS_OPERATION']],
// 'method', gönderilen adı başka adlı bir metoda yöneltir; iki gönderilen adın
// tek bir uygulamayı paylaşma yolu budur.
'acme_retry' => ['privileges' => ['SETTINGS_OPERATION'], 'method' => 'acme_run'],
// 'allow_navigation' asenkron istek şartını kaldırır. Yalnız adres olarak
// açılması gereken operation'lar için (dosya indirme) ve yalnız operation'ın
// kendi tek kullanımlık jetonuyla birlikte.
'download_acme_log' => ['privileges' => ['SETTINGS_OPERATION'], 'allow_navigation' => true],
// Müşteri tarafı operation'ı genelde yetki tanımlamaz: kendini metodun içinde
// üye oturumuna göre kapılar.
'acme_client_action' => [],
]);
Dağıtıcı Ne Yapar
| Adım | Davranış | Başarısız olursa |
|---|---|---|
| Ad temizliği | Ad rota-güvenli bir dizeye filtrelenir; main bulunamadı işleyicisine gider | Bilinmeyen ad reddedilir |
| Lisans kontrolü | Aktif lisans ister; yardım ve yoklama operation'ı muaf | Yetki kontrolünden önce hata |
| Taşıma kontrolü | X-Requested-With: XMLHttpRequest taşıyan asenkron istek | Tanım izin vermiyorsa HTTP 403 |
| Yetki kontrolü | Tanım yetki listeliyorsa çalışır | Eksik yetkiyi adlandıran hata |
| Metodunuz | Yeni kurulmuş operation nesnesiyle çağrılır | Her istisna {"status":"error","message":"..."} olur |
| Yedek yol | Tanım ve metot yoksa ad bir kayıt kancasına sunulur | Dizi cevabı gönderilir |
before kısaltmasının kancası. Dinleyici dizi döndürür: error engeller, overwrite_vars değişkenlerinizi değiştirir, output yerine cevap verir. Boş dizi sürdürür.
after kısaltması; yanıt değişkeni oluştuktan sonra çalışır. Aynı dönüş biçimi, ama error istisna fırlatır.
Çağıranın Okuduğu Yanıt
| Anahtar | Değer | Panel ne yapar |
|---|---|---|
status | successful ya da error | Mesajı olan ve başarı olmayan her şey hata sayılır |
message | Çevrilmiş metin | Bildirim, çağıran istediyse toast |
redirect | Bir adres ya da reload ya da script | Gider, yeniler ya da script çalıştırır; mesajla bildirimi bekler |
redirect_delay | Milisaniye | Beklemeyi ezer: mesajla beş saniye, mesajsız anında |
successToast | Mantıksal değer | Toast biçimini çağıranın tercihine rağmen zorlar |
data | Herhangi bir şey | Otomatik hiçbir şey; kendi geri çağırmanız okur |
Örnek
Bir entegrasyon anahtarını döndüren operation ve onu çağıran kod.
namespace WISECP\operations;
use Operation;
use Filter;
use Exception;
trait AcmeSettings
{
public function rotate_acme_key(Operation $operation): bool
{
/** @var \WISECP\controllers\admin\settings $this */
// 1. Tanıtım sisteminde reddedin; herhangi bir şey okunmadan önce.
$operation->demo();
// 2. Girdiyi okuyun. Asla $_POST: filtre tipi alan başına seçilir ve bir sır,
// noktalaması bozulmadan kalsın diye 'password' filtresinden geçmelidir.
$id = (int) Filter::init('POST/id', 'numbers');
$label = (string) Filter::init('POST/label', 'hclear');
$confirm = (string) Filter::init('POST/confirm_password', 'password');
// 3. BEFORE HOOKS: okumadan sonra, doğrulamadan önce; böylece bir dinleyici
// girdileri değiştirebilir ya da bizim yerimize cevap verebilir.
# BEFORE HOOKS
$hook = $operation->hook('before', get_defined_vars());
if ($hook && $hook['overwrite'] ?? []) extract($hook['overwrite']);
if ($hook && $hook['output'] ?? false) return $operation->output($hook['output']);
// 4. Fırlatarak doğrulayın. Dağıtıcı bunların her birini, sizin tarafınızda hiçbir
// iş olmadan {"status":"error","message":"..."} biçimine çevirir.
if (!$id) throw new Exception(\Language::gc('admin/settings/error-missing-id'));
if ($label === '') throw new Exception(\Language::gc('admin/settings/error-label-empty'));
$adata = \UserManager::LoginData('admin');
if (!\User::_password_verify('admin', $confirm, $adata['password']))
throw new Exception(\Language::g('needs/permission-delete-item-invalid-password'));
// 5. İşin kendisi; trait'in controller'dan devraldığı model üzerinden.
$key = \Utility::generate_hash(48);
$this->model->set_acme_credentials($id, ['label' => $label, 'api_key' => $key]);
// 6. Denetim izi. Üçüncü argüman, actions dil dosyasındaki bir anahtardır.
\User::addAction((int) $adata['id'], 'alteration', 'changed-acme-key', ['id' => $id]);
// 7. Yanıt bir değişkene konur ki after kancası onun yerine bir şey koyabilsin.
$response = [
'status' => 'successful',
'message' => \Language::gc('admin/settings/success-acme-key-rotated'),
'data' => ['masked' => substr($key, 0, 6) . str_repeat('*', 10)],
];
# AFTER HOOKS
$hook = $operation->hook('after', get_defined_vars());
if ($hook && $hook['overwrite'] ?? []) extract($hook['overwrite']);
if ($hook && $hook['output'] ?? false) return $operation->output($hook['output']);
// 8. Tek çıkış. output() kodlar, başlığı kurar ve true döner.
return $operation->output($response);
}
}
namespace WISECP\controllers\admin;
use WISECP\operations\AcmeSettings;
use Controllers;
use Filter;
class settings extends Controllers
{
use AcmeSettings;
public function __construct()
{
parent::__construct();
$this->checkLogin();
// Kayıt ve erişim denetimi tek yerde. Bu kayıt olmadan da metoda ulaşılabilirdi
// ve yetki kontrolünden geçmeden çalışırdı.
$this->operations = array_merge($this->operations, [
'rotate_acme_key' => ['privileges' => ['SETTINGS_OPERATION']],
]);
}
public function main()
{
// Ayrım noktası: gönderilen bir operation aşağıdaki sayfa metotlarına hiç ulaşmaz.
if ($operation = Filter::init('REQUEST/operation')) return $this->operation($operation);
// ... page_* dağıtımı buradan devam eder
return '';
}
}
Çağıran taraf.
function rotateAcmeKey(btn) {
WcpRequest(CONTROLLER_LINK, {
method: 'POST',
button: btn, // gidiş dönüş boyunca pasifleşir ve dönen simge alır
buttonLoader: saving_loader,
options: { headers: { 'X-Requested-With': 'XMLHttpRequest' } },
data: {
operation: 'rotate_acme_key', // beyan edilen ad, birebir
id: ACME_ID,
label: document.getElementById('acmeLabel').value,
confirm_password: document.getElementById('acmeConfirm').value,
},
// status/message/redirect bizim için ele alınır; bu yalnız ek kısım içindir.
afterDone: (res) => {
if (res.status !== 'successful') return;
document.getElementById('acmeKeyMasked').textContent = res.data.masked;
},
});
}
Müşteri paneli operation'ında genel before ve after kancası yoktur.
namespace WISECP\operations;
use Operation;
use Filter;
use Exception;
trait ClientAcme
{
public function acme_disconnect(Operation $operation): bool
{
$operation->demo();
// Bağlam operation'ın İÇİNDE çözülür: tanım dizisi bir kapı değil kayıttır ve
// bir metot, kaydı olmadan da dağıtılabilir durumdadır.
$member = \UserManager::LoginData('member');
if (!$member) throw new Exception(\Language::gc('website/account/err-auth'));
$uid = (int) ($member['id'] ?? 0);
$sid = (int) Filter::init('POST/service_id', 'numbers');
$service = \Services::get($sid);
if (!$service || (int) ($service['owner_id'] ?? 0) !== $uid)
throw new Exception(\Language::gc('website/account/err-not-found'));
// Kendi alan kancalarınız, ait oldukları noktada. Bir kapı, boş olmayan bir
// gerekçe döndürerek reddeder ve operation bunu bir hataya çevirir.
// İki ad da modülünüzün ad alanında yaşar: asla bir çekirdek kancasını
// ateşlemeyin ve kataloğun taşımadığı bir kanca uydurmayın.
foreach (\Hook::run('gate:service.acme_disconnect', $sid, $uid) as $veto)
if ($veto) throw new Exception((string) $veto);
// set_options() diye bir helper yoktur. Seçenekler Services::set() üzerinden gidip
// gelir, o da diziyi sizin için JSON'a çevirir: okuyun, birleştirin, haritanın
// tamamını yazın.
$options = $service['options'] ?? [];
$options['acme_linked'] = 0;
\Services::set($sid, ['options' => $options]);
\Hook::run('action:service.acme_disconnected', $sid, $uid);
return $operation->output([
'status' => 'successful',
'message' => \Language::gc('website/account/acme-disconnected'),
]);
}
}
Tuzaklar
Dağıtım, tanım kaydıyla ya da var olan bir metotla eşleşen her adı kabul eder; yardımcıları private tutun.
API kaynakları doğrudan yardımcıya ya da modele gider; sadece operation'a eklenen kural jetonla aşılabilir kalır. Kuralı iki tarafın da çağırdığı bir metoda taşıyın.
Kendi kodlamanızı yazmak yanıt filtresini ve kodlama işaretlerini atlar. Kanca dalları dahil, çıktı yardımcısıyla dönün.
Yönetici operation'ı, istek kendini asenkron bir çağrı olarak tanıtmıyorsa reddedilir. İndirme için muafiyeti tanımlayın ve tek kullanımlık jeton ekleyin.
Liste ya da önizlemede hiçbir şeyi korumadan tanıtım sistemini bozar. Metot yazıyorsa koruma onun ilk satırı.
İ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.