RBN Core - Framework v0.9.7 76 belge

Core/Database/Models — tablo sınıfları (Master / Common / Project)

Doğrulanan kod tabanı: 1d89c431 (dal feat/fw-license-master) · Tarih: 2026-10-05 · Yayın: 0.9.7 = bu commit + sonrası; belge yalnız doğrulama anındaki kodu anlatır
Kaynak klasör: Core/Database/Models/ — 34 *.php.
Envanter: 35 dosyanın 35'i aşağıda anlatıldı.

1. Ne işe yarar, kim kullanır

Her model bir tabloyu temsil eder; BaseModel'dan gelen kapsam, beyaz liste,
zaman damgası ve ilişki davranışlarını konkrete bağlar ($table,
$connection, $scoped, $timestamps, $fillable, $guarded). Model
SQL yazmaz; yalnız BaseModel/trait API'sini kullanır (Anayasa §8).

Kimler çağırır: Core/Database/Repositories/*, doğrudan
$this->model('project.user') çağıran controller'lar.

2. Dosya envanteri

2.1 Kök

Dosya Tablo Bağlantı $scoped Görev / özel yöntemler
SchemaDoctorModel.php tablosuz ($table = null) database_project — Sistem geneli şema bakımı. getTableStatus(): array, getCurrentDbName(): string, getTablePrimaryKey(string): string, getTableSchema(string): string, optimize(string): bool, convertCollation(string,string): bool, dropTable(string): bool, truncateTable(string): bool, executeRaw(string): array, getRows(string,int $limit=100): array, deleteRows(string,array $ids,?string $pk=null): bool, getTableData(string,?array $ids=null): array, getPdo(). getTable(): string yerine getTableOrNull() kullanılmalıdır.

2.2 Common/ (6) — database_common

Dosya Tablo $scoped $timestamps Görev / özel yöntemler
CmLogAiUsagesModel.php cm_log_ai_usages true true AI kullanım sayaçları
CmLogContactsModel.php cm_log_contacts true false İletişim formu mesajları
CmLogNotificationsModel.php cm_log_notifications true false Sistem bildirimleri
CmSysIpBlocksModel.php cm_sys_ip_blocks true false IP blok kayıtları; projectScopeIncludes = ['GLOBAL']
CmSysRateLimitsModel.php cm_sys_rate_limits true false Hız sınırı sayaçları: recordAttempt(string $identifier,string $action,string $ip,string $userAgent,array $metadata=[],string $countryCode='XX'): bool, getAttemptsCount(string,string,int $windowStart): int, getLastAttempt(string,string,int): ?array, cleanExpired(string,string,int $window): int
CmSysSettingsShieldModel.php cm_sys_settings_shield true true RbnShield ayarları

2.3 Master/ (9) — database_master

Dosya Tablo $scoped $guarded Görev / özel yöntemler
MasterApplicationModel.php applications false — Uygulama kaydı + sürüm
MasterCronJobsModel.php cron_jobs false — Zamanlayıcı iş tanımları
MasterDevelopersModel.php developers false role, password Master geliştirici hesapları
MasterIpBlocksModel.php ip_blocks false — IP blok kayıtları
MasterIpWhitelistModel.php ip_whitelist false — IP beyaz liste
MasterLicenceModel.php licences false status Merkezi lisans kaydı
MasterProjectsModel.php projects false license_key, status Proje kimliği ve alan adı
MasterRbnHeartbeatsModel.php rbn_heartbeats false — Sistem telemetri nabzı. $primaryKey = 'heartbeat_key', incrementing = false, keyType = 'string', timestamps = false
MasterSettingsModel.php settings false — Master ayarları

2.4 Project/ (18) — database_project

Dosya Tablo $scoped $timestamps $guarded / $fillable Görev / özel yöntemler
ContentCategoryModel.php app_content_categories true true $fillable: project_key, type, name, slug, icon, order_num, description, is_active, … İçerik kategorileri
ContentDraftModel.php app_content_drafts true true — İçerik taslakları
CronLogsModel.php z_log_crons true true — Proje zamanlayıcı günlükleri
ConsentLogModel.php z_log_consents true true — Sunucu tarafı rıza kaydı (ekleyici; IP/kullanıcı aracısı yok); kurulum rbn consent:install
SalesConsentLogModel.php z_log_sales_consents true true — Ödeme adımı ön bilgilendirme onayı kanıtı (ekleyici; ürün/tutar, metin sayfaları + SHA-256 özeti, saat; IP/kullanıcı aracısı/hesap yok); kurulum rbn sales-consent:install
FaqsModel.php z_app_faqs true true — SSS kayıtları; getFaqs(array $filters=[]): array
FrontendMenusModel.php z_app_menus_frontend true true — Frontend menü tanımları
RbnHeartbeatsModel.php dinamik (z_sys_heartbeats varsayılan) false false — Telemetri nabzı; DEFAULT_TABLE, KEY_COLUMN='heartbeat_key', TABLE_CANDIDATES. resolveTableName(): string, isAvailable(): bool, probeTable(string): bool, beat(string $anahtar,array $payload=[]): bool, static onbellegiTemizle(): void, guard(): bool; create/update/destroy/save yolları guard() ile korunur (delete() yoktur: koşulsuz silme hatadır)
RssBlacklistModel.php app_rss_blacklist true false — RSS kara liste
RssSourceModel.php app_rss_sources true true — RSS kaynakları
SettingsApiModel.php z_settings_api true true projectScopeIncludes = [] API anahtarı ayarları
SettingsGroupModel.php z_setting_groups false true — Ayar grupları
SettingsModel.php z_settings true true — Proje ayarları
SidebarCategoriesModel.php z_bs_sidebar_categories true true — Panel kenar çubuğu kategorileri
SidebarMenusModel.php z_bs_sidebar_menus true true — Panel kenar çubuğu menüleri
UserActivitiesModel.php z_users_activities false true — Kullanıcı etkinlik günlüğü
UserSecurityModel.php z_users_security false — guarded: user_id Kullanıcı güvenlik verileri
UsersModel.php z_users false true guarded: role, email, username Kullanıcı hesapları
UserTokenModel.php z_user_tokens false false — Tek kullanımlık jeton kasası (e-posta doğrulama, parola sıfırlama)

Kapsama: 35/35.

3. Akış — modelin kuruluşu ve kapsam

$this->model('project.user')  → keşif → RegistryMap: 'project.user' => Models\Project\UsersModel  SystemPhysicalMapTrait.php:58
 └─ new UsersModel()
     └─ BaseModel::__construct()                       BaseModel.php:210
         ├─ $connection = 'database_project'
         └─ parent::__construct() → BaseComponent → bootConcernsContext()/bootBaseContext()
 └─ ->where(...)
     └─ QueryModelTrait::query()                       QueryModelTrait.php:44
         ├─ logModelScopeVisibility() (kapsam dışıysa saatlik ölçüm satırı)  :49
         ├─ new QueryBuilder($this->db, $this->table)  :67
         ├─ $builder->connection($this->connection)    :71-73
         └─ $scoped ise: where(project_key, aktif) ya da whereIn(project_key, [aktif, …projectScopeIncludes])  :88-108

Kapsam anahtarı çözümü BaseModel::resolveScopeProjectKey() →
getActiveProjectKey(); withProjectScope()/withoutProjectScope() klon
üretir (BaseModel.php:155).

4. Yapılandırma

Öğe Yer Not
security.mass_assignment Base/Data/Traits/Model/Engine/MassAssignmentTrait.php:42 on ise $fillable beyaz liste, $guarded kara liste
security.model_not_scoped_log .../QueryModelTrait.php:39 on → kapsam dışı model logu
$projectScopeIncludes model dosyası Örn. CmSysIpBlocksModel: ['GLOBAL']
@tenant-scope etiketi model docblock'ı Her modelin kararını yazdığı beyan zorunluluğu

5. Tuzaklar ve kurallar

  1. Varsayılan kapsam KAPALI. BaseModel::$scoped = false
    (Base/Data/BaseModel.php:57); her model kararını kendi dosyasında yazar.
  2. Tipli alan yeniden bildirilemez. BaseModel::$primaryKey tipsiz
    bildirilmiştir; alt sınıf string tipiyle yeniden bildirirse PHP fatal
    verir ve sınıf hiç yüklenmez (MasterRbnHeartbeatsModel.php:37).
  3. $guarded alanları doğrudan yazılamaz. Yetki gerekiyorsa
    authorizeFields([...]) klonu kullanılır ve her çağrı
    MASS_ASSIGNMENT_AUTHORIZED_WRITE olarak loglanır
    (MassAssignmentTrait.php:105).
  4. $fillable tanımlı değilse süzme uygulanmaz (geriye uyum kilidi).
  5. Boş proje bağlamında kapsam uygulanmaz (bkz. Engine.md).
  6. Heartbeat modeli şema oluşturmaz. Tablo yoksa tüm veri yolları güvenli
    varsayılana döner (RbnHeartbeatsModel.php:15, 227-236).
  7. SchemaDoctorModel tablosuzdur; getTable(): string yerine
    getTableOrNull().

5.1 İçerik değişiklik tarihi: $contentFields ve modified_at

Sitemap lastmod ve JSON-LD dateModified yalnız satırın modified_at sütunundan gelir (FormatHelper::modifiedAt()). Sitemap'e giren her
içerik modeli (çekirdekte ContentCategoryModel; projede ürün gibi modeller) içerik sayılan alanları $contentFields ile bildirir:

protected array $contentFields = ['title', 'slug', 'content'];
  • ContentDateModelTrait (Core/Base/Data/Traits/Model/Engine/) create() ve update() yolunda modified_at değerini MERKEZİ yazar: yeni kayıt = şimdi;
    güncellemede listedeki alanlardan biri eski satırdan GERÇEKTEN farklıysa şimdi. Aynı içerikle kayıt (boşluk, 199 = 199.00, JSON biçimi) tarihi oynatmaz
    (FormatHelper::contentChanged(); yazı tablosu ContentServiceTrait::savePost() aynı karşılaştırmayı kullanır).
  • Sayaç, sıralama, görünürlük ve entegrasyon alanlarını listeye KOYMAYIN; bunları query()->update() ile yazın (model update() yolundan geçmez, modified_at oynamaz).
  • $contentFields bildiren modelin tablosunda modified_at ZORUNLUDUR (çalışma zamanında hasColumn dalı yoktur). Sütunu php rbn content:modified-at --project=<anahtar> --apply
    ekler: updated_at'ten ÖNCE, son iki sütun updated_at, created_at; mevcut satırlar modified_at = updated_at (boşsa created_at) ile dolar, updated_at değişmez.
    --apply olmadan komut yalnız plan gösterir. Tablo listesi, sitemap kaynağı olan modellerin $contentFields bildirenleridir (CrawlerResolver::resolveSitemapModels()).
  • Panel/servis kayıtları modelin save()/update()/create() yolundan geçmelidir; $model->where(...)->update($data) (builder) yolu modified_at yazmaz.

6. Örnek (gerçek koddan)

// Kapsamlı (scoped = true) model: proje süzgeci builder'a otomatik eklenir
$faqs = $this->model('project.faq')->where('is_active', 1)->get();

// Kapsam dışı (scoped = false) modelde süzgeç KENDİN yazılır
$all = $this->model('master.projects')->where('is_active', 1)->get();

// Korumalı alana yetkili yazma (klon döner, loglar)
$this->model('project.user')->authorizeFields(['role'])->update($id, ['role' => 'admin']);

7. İlgili belgeler