Alan Yardımcıları
İş kuralları yardımcılarda yaşar. Panel, müşteri paneli, API ve zamanlayıcı hepsi aynı kuralı çağırır. Bir hizmetin, bir siparişin ya da bir tutarın ne demek olduğu konusunda anlaşmalarının sebebi budur.
Genel Bakış
Model neyin saklandığını cevaplar. Yardımcı ne olması gerektiğini cevaplar. Bir hizmeti askıya almanın ne yaptığını, ödenen bir siparişin neye dönüştüğünü, bir tutarın para birimleri arasında nasıl çevrildiğini. Dört ekran da bu cevaplara ihtiyaç duyduğu için kural tek bir yerde yaşar ve her biri onu çağırır.
Hepsi WDB üzerine kurulu statik sınıflardır. Bir modül, bir kanca dinleyicisi ya da bir cron işleyicisi onlara bir controller ile aynı şekilde ulaşır. İşi sorgularla kendiniz yapmak, bugün doğru olan ama ürünün kendi kuralı ilk değiştiğinde ayrışan bir şey üretir.
Referans
Services
public static function get(int $id = 0, string $select = '', $noCache = false): array;
// -> users_products satırı: id, owner_id, order_id, invoice_id, subscription_id, type,
// type_id, product_id, name, period, period_time, total_amount, amount, amount_cid, qty,
// status, status_msg, suspended_reason, pmethod, auto_pay, cdate, duedate, suspend_date,
// cancel_date, terminated_date, server_terminated, renewaldate, process_exemption_date,
// module, options, metrics, notes, unread
// 'options' ve 'metrics' ÇÖZÜLMÜŞ dizi olarak gelir; NULL olan bir kolon null kalır.
// 'module' her zaman vardır ve "none"a düşer - var olmayan bir hizmetin yine de boş
// olmayan bir dizi dönmesinin sebebi budur. $select kolonları daraltır, $noCache memoyu atlar.
public static function add(array $data = []): int; // yeni id, başarısızlıkta 0
public static function set(int $id = 0, array $data = []): bool;
public static function delete(int $id = 0, bool $cancelModule = false): bool;
public static function preload(array $ids = []): void; // tek sorgu, get()'in memosunu doldurur
public static function statuses(): array;
// -> durum anahtarı => ['title' => etiket, <grup> => true]. Anahtarlar waiting, inprocess,
// active, completed, suspended, expired, cancelled; kodun dallanması gereken şey grup
// bayrağıdır, çünkü 'completed' active, 'expired' ise cancelled grubuna girer.
public static function addons(string|int|null $service_id = 0): array; // users_products_addons satırları,
// artı hesaplanmış bir 'rak' sıralama kolonu
public static function get_addon(int $id = 0, string $select = ''): array;
public static function requirements(int $service_id = 0): array;
public static function change_status(int $serviceId, string $status, array $options = []): bool;
// $options, hepsi isteğe bağlı:
// apply_on_module false | true | 'sync' | 'queue' modül aksiyonunu yerinde koştur ya da kuyruğa al
// module_completed bool modül işini zaten yaptı; hizmeti inprocess'te tutma
// force_status bool durumu olduğu gibi yaz, aynı korumayı atla
// reason string suspended ve cancelled için suspended_reason olarak saklanır
// user_id int bunu kim yapıyor, geçmiş kaydı için
// notify bool müşteriye durum bildirimini gönder
public static function run_module(array|int $service, string $action, array $params = []): mixed;
// -> modülde böyle bir metot yoksa null, modül reddettiyse false, aksi halde modülün kendi
// dönüşü. Instance kurulamazsa ya da modül exception fırlattıysa fırlatır.
public static function add_history(int $user_id = 0, int $service_id = 0, string $name = '', array $data = []): int;
Money
public static function getUCID(): int; // bu ziyaretçiye sunulan para birimi id'si
public static function selected(): int; // getUCID()'nin okunur takma adı
public static function exChange($amount, $cid1 = 0, $cid2 = 0);
// -> çevrilmiş tutar. İki cevap çevrim değildir:
// $cid1 === $cid2 -> $amount olduğu gibi döner, hiçbir kur okunmaz
// çeviremiyorsa -> 0; bilinmeyen para birimi, 0 olan bir kur ve sıfırdan büyük
// olmayan bir $amount hepsi buraya düşer
public static function formatter($amount = 0, $cid = 0, $symbol = false, $exchange = false, $info = false): array|string;
// -> "99.90" · $symbol ile: "$99.90" · $info ile dize yerine bir dizi:
// ['currency_id' => 4, 'currency_code' => 'USD', 'prefix' => '$', 'suffix' => '',
// 'symbol' => '$', 'amount' => '99.90']
// $exchange önce çevirir: true sunulan para birimini, bir id ya da kod onu kullanır.
public static function formatter_symbol($amount = 0, $currency = 0, $exchange = false, $info = false): string;
// Burada üçüncü argüman $exchange'dir, $symbol DEĞİL - sembol zaten hep açıktır.
public static function deformatter($amount = '', $currency = 0): float; // "1.234,56" -> 1234.56
public static function Currency($identified = 0, $isActive = false): array;
// -> currencies satırı: id, status, local, hidden, country, countries, code, name, prefix,
// suffix, rate, format, modules. Böyle bir para birimi yoksa []. $identified bir id ya da
// bir kod ("USD") alır; $isActive pasif bir para birimine de [] dedirtir.
public static function getCurrencies(int $default = 0): array;
public static function currency_code(int $id = 0): string;
public static function getSymbol($currency = 0);
// -> ['position' => 'LEFT'|'RIGHT', 'prefix' => ..., 'suffix' => ..., 'symbol' => ...]
public static function get_tax_amount($amount = 0, $rate = 0); // $amount'un ÜSTÜNE eklenen vergi
public static function get_inclusive_tax_amount($amount = 0, $rate = 0); // $amount'un İÇİNDEKİ vergi
public static function get_discount_amount($amount = 0, $rate = 0); // $amount * $rate / 100
Orders
public static function get(int $id, $select = ''): array;
// -> orders satırı: id, user_id, invoice_id, affiliate_id, ordernum, cdate, tax_type,
// taxes, amount, currency, pmethod, status, ip, notes, discounts, items, details
// taxes, discounts, items ve details ÇÖZÜLMÜŞ dizi olarak gelir. Sipariş yoksa [].
public static function get_order_by_number(int $num, string $select = ''): array;
public static function create(array $data = []): int;
// Yalnız bu anahtarlar okunur; $data içindeki başka her şey saklanmaz, düşürülür.
// user_id int ZORUNLU
// amount float ZORUNLU - 0.0 olabilir, eksik olamaz
// currency int ZORUNLU - bir para birimi id'si
// status string 'waiting'
// pmethod string 'none'
// tax_type string 'exclusive'
// taxes array JSON'a çevrilir
// discounts array JSON'a çevrilir
// items array JSON'a çevrilir
// details array JSON'a çevrilir
// invoice_id int 0
// affiliate_id int 0
// notes string null
// ip string isteği yapanın adresi
// Zorunlu bir anahtar eksikse exception fırlatır. Sipariş numarası sizin için üretilir ve
// bir dinleyici çağrının tamamını veto edebilir.
public static function set(int $id, array $data): bool;
public static function delete(int $id, bool $deleteServices = true): bool;
public static function services(int $order_id = 0): array;
// -> siparişin hizmetleri; id, name, type, status, amount, module, period, period_time ile daraltılmış
public static function statuses(): array; // waiting, inprocess, active, cancelled
public static function payment_statuses(): array; // incomplete, complete, unknown
public static function change_status(int $order_id, string $status, bool $updateServices = false, string|bool $applyOnModule = false): bool;
public static function recalculateStatus(int $order_id, bool $force = false): ?string;
public static function generateOrderNumber(): int;
public static function add_history($user_id = 0, $order_id = 0, $name = '', $data = []): int;
Products
public static function get(string|int|null $id = 0, string $lang = '', string $select = ''): array;
// -> products satırı, artı çevrilmiş 'title' ve onun takma adı 'name'. Boş bir $lang etkin
// dil demektir. 'options' ve 'module_data' ÇÖZÜLMÜŞ dizi olarak gelir. Böyle bir ürün
// yoksa []. Süreç boyunca (id, lang) başına memolanır; yani arada düzenlenen bir satır
// yeniden okunmaz.
public static function set($id = 0, $set = []): bool;
public static function types(): array;
// -> tip anahtarı => ['title' => ..., 'description' => ..., 'icon' => ...]. Liste sabit
// değildir: bir modül onu register:product_types kancasıyla genişletir.
public static function groups(): array;
public static function cycles(): array;
public static function cycle($duration = '', $period = ''): string; // (1, 'month') -> "monthly"
public static function get_price($type, $owner, $owner_id, $lang = 'none'): array;
public static function get_price_by_criteria(string $owner, int $owner_id, string $cycle = '', string|int $currency = '', int $status = 1, string $type = ''): array;
// $owner tabloya göre değişen ve TAHMİN EDİLEMEYEN bir sabittir: ürün fiyatı 'products'
// (çoğul), alan adı uzantısı 'tld', eklenti 'addon' altında saklanır. Yanlış biçim hiçbir
// şeyle eşleşmez ve hiçbir hata bildirmez.
public static function addon($id = 0, $lang = '', $select = ''): array;
public static function requirement($id = 0, $lang = '', $select = '');
public static function get_category($id, $lang = '', $select = ''): array;
public static function get_server($id = 0): array; // servers satırı, 'password' çözülmüş olarak
public static function get_tld($definition = 'com', $select = '');
User
public static function getData($id = 0, $fields = '*', $fetch = 'object', $noCache = false): object|array;
// $fields kabul edilir ama KULLANILMAZ: users satırının tamamı her zaman okunur ve memo
// yalnız id ile anahtarlanır. Biçimi $fetch seçer - 'object' (varsayılan) bir stdClass,
// başka her değer bir dizi verir. Dolayısıyla tek kolon okumak bunu açıkça söylemelidir:
// $groupId = (int) (User::getData($id, '', 'array')['group_id'] ?? 0);
public static function setData($id = 0, $data = []): int|bool;
public static function create($data = []);
public static function delete(int $id, array $options = []): bool;
public static function getInfo($owner_id = 0, $names = [], $noCache = false): array;
// -> istediğiniz adlar ad => değer olarak; hiç saklanmamış olan için null.
public static function AddInfo($owner_id = 0, $values = []); // upsert, ad => değer
public static function deleteInfo($owner_id = 0, $name = ''): int|bool;
public static function addAction($id = 0, $reason = '', $detail = '', $data = [], $target_id = 0);
// $id kaydın ait olduğu müşteri
// $reason serbest biçimli gruplama etiketi: 'alteration', 'addition', 'delete', 'module-log'
// $detail locale actions.php içindeki ÇEVİRİ ANAHTARI - cümle bundan üretilir
// $data o cümlenin kullandığı yer tutucular ({service_name} vb.); ayrıca JSON olarak saklanır
// $target_id kaydın konusu olan kayıt, müşterinin kendisi değilse
public static function addNote(int $owner_id, string $content, bool $pinned, int $adminId, string $adminName): array|false;
public static function getPrivileges($id = 0, $resultType = 'array'): array|string;
public static function parseDealership(string $data): array;
"Bulunamadı" Neye Benzer
| Çağrı | Var olmayan kayıt için cevap | Yazılacak guard |
|---|---|---|
Services::get($id) |
['module' => 'none'] - boş değil, yani doğruluk testinden geçer |
if (!($service['id'] ?? 0)) |
Services::get_addon($id) |
[] |
if (!$addon) |
Orders::get($id) |
[] |
if (!$order) |
Products::get($id) |
[] |
if (!$product) |
Money::Currency($id) |
[] |
if (!$currency) |
User::getData($id) |
boş bir stdClass, 'array' ile [] |
if (!($user->id ?? 0)) |
Örnek
// Hizmet. "Bulunamadı" cevabı yine de doğru sayılan tek getter budur; bu yüzden guard
// diziye değil kimliğe bakar.
$service = Services::get($id);
if (!($service['id'] ?? 0)) throw new Exception('Hizmet bulunamadı');
// Tutar, yanında saklanan para birimine aittir ve ziyaretçiye başka biri sunuluyor olabilir.
// Önce çevirin, sonra biçimlendirin.
$served = Money::getUCID();
$amount = Money::exChange((float) $service['amount'], (int) $service['amount_cid'], $served);
$displayed = Money::formatter_symbol($amount, $served);
// İşlemi yardımcı üzerinden yapın; böylece geçmiş kaydı, modül ve bildirim panelin
// yapacağı gibi gerçekleşir.
Services::change_status((int) $service['id'], 'suspended', [
'apply_on_module' => 'queue',
'reason' => 'Ödeme gecikti',
'user_id' => $adminId,
'notify' => true,
]);
// Müşterinin aktivitesine yazın. Üçüncü argüman locale actions.php içindeki anahtardır;
// dördüncüsü o cümlenin yer tutucularını doldurur.
User::addAction((int) $service['owner_id'], 'alteration', 'acme-service-suspended', [
'service_id' => (int) $service['id'],
'service_name' => $service['name'] ?? '',
'amount' => $displayed,
], (int) $service['id']);
// Kayıt hem anahtarı, hem kurulumun kendi dilinde üretilmiş cümleyi, hem de yer tutucuları
// JSON olarak tutar. Çevirisi olmayan bir anahtar burada anahtarın kendisi olarak görünür.
$stmt = WDB::select('reason, detail, locale_detail, data, ctime')
->from('users_actions')
->where('owner_id', '=', (int) $service['owner_id'])
->where('detail', '=', 'acme-service-suspended')
->order_by('id DESC')
->limit(1);
$entry = $stmt->build() ? $stmt->getAssoc() : [];
$vars = $entry ? Utility::jdecode($entry['data'] ?? '', true) : [];
// Ve yardımcının gerçekten yazdığı durum; ilk çağrının doldurduğu memoyu atlayarak.
$after = Services::get((int) $service['id'], '', true)['status'] ?? '';
Tuzaklar
Bir hizmeti yardımcı üzerinden oluşturmak ya da askıya almak, çevresindeki şeyleri de yapar. Geçmiş kaydını, ilişkili kayıtları, modül aksiyonunu, başka kodun dinlediği olayları. Kendi yazdığınız bir insert ya da update bunların hiçbirini yapmaz ve doğru görünen ama sonradan tuhaf davranan bir kurulum bırakır.
Saklanan her tutar bir para birimine aittir ve ziyaretçiye başkası sunuluyor olabilir. Karşılaştırmadan, toplamadan ya da göstermeden önce çevirin. Cache'lediğiniz her şeyin anahtarına sunulan para birimini koyun. Ancak çevrim yapılamadığında exChange() 0 döner. Bilinmeyen bir para birimi, sıfır olan bir kur ve sıfırdan büyük olmayan bir tutar hepsi oraya düşer. Negatif sayı olarak geçirilen bir alacak ya da iade, tek kelime etmeden sıfıra iner.
Services::get() her zaman bir module anahtarı taşır; yani var olmayan bir hizmet doğru sayılan bir dizidir ve if (!$service) hiçbir zaman tetiklenmez. User::getData() kolon listesini tümüyle yok sayar ve dizi istemediğiniz sürece bir stdClass verir. Tek kolon beklerken sonucu cast etmek sessizce yanlış sayıyı üretir. Money::formatter_symbol()'da ise üçüncü argüman $symbol değil $exchange'dir ve dördüncüsü, alttaki çağrıyı beyan edilen string dönüş tipine karşı bir dizi döndürmeye zorlar.
Cümle, metin olarak geçtiğiniz bir şeyden değil üçüncü argümandan üretilir; ikincisi yalnızca bir gruplama etiketidir. Bir dil dosyasında olup diğerlerinde olmayan bir anahtar, geri kalan herkes için müşterinin geçmişinde çıplak anahtar olarak görünür. Çağrıyı eklerken anahtarı tüm dil dosyalarına ekleyin.
İ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.