Model Katmanı
Modeller, veritabanına dokunmaya izin verilen yerdir; bir satırın satır olmaktan çıkıp uygulamanın geri kalanının kullanabileceği bir şeye dönüştüğü yer de burasıdır.
Genel Bakış
Bir model bir controller'a aittir, aynı adla bulunur ve onun için kurulur. Küçük ve tahmin edilebilir bir metot kümesi sunar; ona sahip olan controller ise bir sorgunun neye benzediğini bilmez.
Bu sınırın sebebi saflık değildir. Aynı veriye panel, müşteri paneli, API ve zamanlanmış komut satırı ihtiyaç duyar; bir sayfanın içine yazılmış sorgu ise yalnızca o sayfaya hizmet edebilir.
Yapı
coremio/models/{yüzey}/{ad}.php, controller adıyla birebir eşleşir. Kuruluş sırasında yola göre yüklenir, otomatik yükleyiciyle değil.
\WISECP\Models\{Yüzey}\{Ad}, sonra {Ad}Model, sonra çıplak Model. Hiçbiri tutmazsa elinizde düz taban sınıf kalır ve kendi metotlarınız yoktur.
$this->db; ilk okumada __get() üzerinden çözülür. Hiç sorgu yapmayan bir sayfa hiç bağlantı açmaz.
Referans
Taban Sınıf
public string $pfx; // tablo öneki, ham SQL parçaları için
public ?Database $connection = null;
public static ?self $init = null; // kurulan son model - WDB onun bağlantısını okur
public function __get($name); // 'db' Database döner; diğer her ad null
protected function lang_routes(string $langTable, int $ownerId): array; // ['en' => 'slug', 'tr' => 'slug']
public function menu_list($type, $lang, $list = [], $parent = 0);
public function link_detector($link): string;
$this->db'nin arkasındaki bağlantı fonksiyon-statik bir değişkende tutulur; yani süreçteki her model tek bir Database nesnesini paylaşır ve WDB aynı nesnenin statik cephesidir. İki giriş noktası, tek kurucu ve tek yarım kalmış sorgu durumu.
Alışıldık Metotlar
Bunlar bir arayüz değil, konvansiyondur; uymak, bir modeli görmüş okuyucunun hepsini görmüş olması demektir. Aşağıdaki imzalar daha yeni modellerin kullandığı biçimdir.
public function list(bool $rCount = false, array $filters = [], array $orders = [], int $start = 0, int $end = -1): array|int;
public function get(int $id): array|false;
public function add(array $data = []): int;
public function update(int $id = 0, array $data = []): bool;
public function delete(int $id): bool;
true satır sayısını int olarak döner; kolonları, sıralamayı ve sayfalamayı atlar. Tablo bileşeni aynı metodu iki kez, her biçimde bir kez çağırır.
?? ile okunduğu için her anahtar isteğe bağlıdır. Paylaşılan tek anahtar word, yani serbest metin aramasıdır. Kalanı modele özgüdür: hizmetler status, user_id, product_id, server_id, cycle, duedate artı duedate_op gibi anahtarlar kabul eder.
['id' => 'DESC']: çıplak kolon adından yöne. Tablo takma adını model kendisi ekler, siz eklemeyin. Boş dizi modelin varsayılan sıralamasına düşer.
limit()'e geçer. $end = -1 hiç sınır yok demektir ve varsayılandır, bu yüzden sayfayı açıkça isteyin.
get() boş dizi değil false döner; böylece çağıran "böyle bir kayıt yok" ile "içi boş bir kayıt" arasını ayırt edebilir.
Sorgu Kurucusu
Her kurucu metot bağlantıyı döndürür, yani çağrılar zincirlenir ve zinciri build() ya da save() kapatır. Statik cephe aynı nesneye yönlendirir, tek fark şudur: onun where()'ı dört argümanda durur, örnek beşinciyi de alır.
public static function select($arg = '*');
public static function from($arg = '');
public static function join($type, $table, $where); // $type: "LEFT", "INNER", ...
public static function where($column, $mark = '', $value = '', $logical = '');
public static function group_by($arg = '');
public static function order_by($arg);
public static function limit($arg1, $arg2 = null);
public static function build($isthis = false); // okumayı koşar, başarısızsa falsy
public static function fetch_assoc($statement = false); // tüm satırlar
public static function getAssoc($statement = false); // tek satır
public static function getObject($statement = false);
public static function rowCounter($statement = false); // etkilenen/dönen satır sayısı
public static function insert($table, $data); // satır sayısı; kimlik lastID()'den gelir
public static function update($table = '', $data = []); // where() zincirle, sonra save()
public static function delete($arg = '', $arg2 = '');
public static function save($isthis = false);
public static function lastID();
// Örnek metodunda where() bir argüman daha taşır:
public function where($column = '', $mark = '', $value = '', $logical = '', $filter = '?'): self;
"knowledgebase AS t". Kurulumun tablo öneki sizin için eklenir.
AND kalır, o da sizin için eklenir.
build() ? fetch : yedek olmasının sebebi budur.
limit(1) koyun ki ifade tam da okumak istediğinizi çeksin.
save() işler. Koşulsuz bir güncelleme tabloyu baştan yazar.
Çevrilmiş Satırlar
İnsanlara gösterilen kayıtlar çevirilerini, kaydın kendi tablosunun adını taşıyan yandaki bir tabloda, dil başına bir satır olarak, owner_id ve lang anahtarlarıyla tutar. Bir okuma o tabloyu aktif dil için join eder ve kaydın kendi değerine düşer. Kısmen çevrilmiş bir kurulum yine de bir değer gösterir. Aynı tablo dil başına slug'ı da taşır; lang_routes()'un dil değiştirici ve alternatif bağlantılar için döndürdüğü şey odur.
Örnek
namespace WISECP\Models\Admin;
use Language;
use Models;
class Widgets extends Models
{
public function list(bool $rCount = false, array $filters = [], array $orders = [], int $start = 0, int $end = -1): array|int
{
$lang = Language::selected();
$search = $filters["word"] ?? '';
if (!$orders || empty(array_key_first($orders))) $orders = ['id' => 'DESC'];
$stmt = $this->db->select($rCount ? "t.id" : "t.id, COALESCE(tl.name, t.name) AS name, t.status")
->from("widgets AS t")
->join("LEFT", "widgets_lang AS tl", "tl.owner_id = t.id AND tl.lang = '" . $lang . "'");
// Dördüncü argüman: BU koşulu bir sonrakine bağlayan operatör.
if ($search) $stmt->where("COALESCE(tl.name, t.name)", "LIKE", "%" . $search . "%", "&&");
$stmt->where("t.status", "!=", "deleted");
if ($rCount) return $stmt->build() ? $stmt->rowCounter() : 0;
$order = array_key_first($orders);
$stmt->order_by("t." . $order . " " . strtoupper($orders[$order]));
if ($end != -1) $stmt->limit($start, $end);
return $stmt->build() ? $stmt->fetch_assoc() : [];
}
public function get(int $id): array|false
{
if (!$id) return false;
return $this->db->select("t.*, COALESCE(tl.name, t.name) AS name")
->from("widgets AS t")
->join("LEFT", "widgets_lang AS tl", "tl.owner_id = t.id AND tl.lang = '" . Language::selected() . "'")
->where("t.id", "=", $id)
->limit(1)
->build() ? $this->db->getAssoc() : false;
}
public function add(array $data = []): int
{
return $this->db->insert("widgets", $data) ? $this->db->lastID() : 0;
}
public function update(int $id = 0, array $data = []): bool
{
return (bool) $this->db->update("widgets", $data)->where("id", "=", $id)->save();
}
}
Çağıran hiçbir zaman bir sorgu görmez; dallandığı şey tam olarak yukarıdaki iki biçimdir.
$total = $this->model->list(true, ['word' => $search]); // int
$rows = $this->model->list(false, ['word' => $search], ['id' => 'DESC'], 0, 25);
$widget = $this->model->get($id);
if ($widget === false) return $this->page_404(); // false = "böyle bir kayıt yok"
Tuzaklar
Koşullar değerlerini argüman olarak alır, böylece sürücü onları bağlar. Koşul dizesine ya da join ifadesine yapıştırılan bir değer, ilk sıra dışı girdiyi bekleyen bir enjeksiyondur.
Bu koşulu bir öncekine bağlayan operatör değildir; bir sonrakine bağlayandır. Operatörü bir alternatifin yanlış koşuluna yazmak hangi satırların döneceğini sessizce değiştirir ve hiçbir şey hata vermez.
Her şeyi seçen bir getter, çağıranlarına tabloda ne varsa onu verir; sonradan eklenen ve veritabanından çıkması hiç düşünülmemiş kolonlar dahil. Böyle bir değer bir yanıta ulaşabiliyorsa, dışarı yazıldığı sınırda filtreleyin.
Model neyin saklandığını cevaplar. Bunun sonucunda ne olması gerektiği, panelin, müşteri panelinin, API'nin ve zamanlayıcının hepsinin erişebildiği bir yardımcıya aittir.
İ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.