Core/Render/Providers — fiziksel HTML/XML/JSON üretimi (12 dosya)
Doğrulanan kod tabanı:
c23b431f· 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/Render/Providers/— 12*.php= 5 kök +UI/altında 7.
Envanter: 12 dosyanın 12'si anlatıldı.
Doğrulama platformu: Windows + PHP 8.3, tümüprovider()/resolver()üzerinden gerçekten çözüldü.
1. Ne işe yarar, kim kullanır
RenderService::render() son adımda provider($type)->render($view, $data, $type)
çağırır (Services/RenderService.php:62). Provider'lar gerçek HTML'i üreten
tek sınıflardır: FrontendProvider header+view+footer'ı birleştirir,
SeoProvider <meta> bloklarını basar, CrawlerProvider robots.txt/sitemap
üretir, AssetProvider <link>/<script> etiketlerini basar.
Kayıt: SystemRenderMapTrait.php:47 — providers altında 10 kayıt.
Kayıt dışı 2 sınıf: UI/ViewProvider ve UI/AjaxProvider aşağıda §4'te.
2. Klasör/dosya envanteri (12/12)
| Dosya | Görev | Önemli public yöntemler |
|---|---|---|
SeoProvider.php (236) |
<head> meta üreticisi. Teknik/proje/sosyal/marka/link segmentlerini ayrı ayrı basar, hepsini yorum işaretleriyle çerçeveler. |
render(?string $view=null,array $data=[]): string · korumalı: renderTechnical(), renderProjectMeta(), renderSocial(), renderBranding(), renderLinks(array $meta,string $context='frontend'): array |
AssetProvider.php (135) |
CSS/JS etiketlerini basar; CDN önceliği uygular. | render(?string $view,array $data=[]): string, decorate(string $content,string $physicalPath,?string $label='RBN Framework'): string · korumalı: cdnFirst(array $assets): array, renderStyle(array $style): string, renderScript(array $script): string |
CrawlerProvider.php (306) |
robots.txt, sitemap, feed, llms.txt, ads.txt (renderAds()) üretir; aktif sayfa envanteri sunar. noindex kararını kendisi yorumlamaz, SeoResolver'a devreder. |
render(?string $view,array $data=[]): string, renderRobots(array $data=[]): string, renderSitemap(array $data=[]): string, renderFeed(array $data=[]): string, renderLlms(array $data=[]): string, renderAds(array $data=[]): string, getActivePages(): array, hasActiveFaqs(): bool, getActivePagesCount(): int, isSiteNoindex(): bool, isPageNoindex(array\|object $entry): bool, hasFeed(): bool, getProject(string $type) |
BreadcrumbProvider.php (104) |
Kırıntı HTML'ini basar ve veri dizisine enjekte eder. | resolveAndRender(array &$data,?string $view): string, render(?string $view,array $data=[]): string |
SchemaProvider.php |
Biriken düğümleri SchemaPolicy'den geçirip TEK @graph olarak basar; noindex sayfada hiçbir şey basmaz. |
build(string $name,array $data=[]): self, render(): string · açık alan: $pageType |
ConsentProvider.php |
Ziyaretçi izni: sertifikalı CMP betiği (tanımlıysa, en önce), Consent Mode default/update betiği (ölçüm kodundan önce), CMP yokken kişiselleştirilmemiş reklam bayrağı ve reklam/serbest script bloklarını rızaya kadar bekleten gate(). CMP zorlaması projeden kapatılamaz. |
cmp(array): ?array, decision(array): array{open,analytics,ads} (rıza kapısı: tek karar, bkz. kavramlar/06-riza-kapisi.md), headHtml(bool,array=[]): string, gate(string $html,string $purpose): string, BANNER_VERSION |
UI/FrontendProvider.php (137) |
En sık çalışan provider. Trafik kaydı + ayarlar + SEO + asset + şablon zinciri. | render(?string $view,array $data=[]): string · korumalı: safeSnippet(mixed $value): string |
UI/PanelProvider.php (112) |
Yönetim paneli layout'u. | render(?string $view,array $data=[]): string |
UI/AuthProvider.php (70) |
Giriş/kayıt ekranı layout'u. | render(?string $view,array $data=[]): string |
UI/PartialProvider.php (55) |
Parça/fragment basımı; @import dizisini toplu basar. |
render(?string $view,array $data=[]): string, renderImports(array $imports,array $data=[]): string |
UI/StaticProvider.php (32) |
Sabit (statik) sayfa basımı — dosyanın en küçük provider'ı. | render(?string $view,array $data=[]): string |
UI/AjaxProvider.php (54) |
Layout'suz parça basıcı (modal, tooltip, AJAX güncellemesi). $data['__imports'] varsa PartialProvider::renderImports() ile içe aktarımları da basar. |
render(?string $view,array $data=[]): string |
UI/ViewProvider.php (81) |
Kayıtsız çekirdek view koşucusu: resolve()/include() mantığı. |
render(?string $view,array $data=[],string $appContext='frontend'): mixed, include(string $path,array $data=[],string $source='auto',string $appContext='frontend'): void, resolve(string $path,array $data=[],string $source='auto',bool $strictRbn=false,string $appContext='frontend'): ?string |
3. Akış — FrontendProvider::render() (Providers/UI/FrontendProvider.php:19-108)
Tam zincir ve satır kanıtları README §3.1'de. Burada yalnız provider'a
özgü üç karar:
- Trafik kaydı her frontend render'da bir kez (
:23
$this->storage->traffic()->record()). Aynı istekte iki kez render edilirse
(ör. partial + tam sayfa) iki kayıt yazılır — engel yok, ölçülmedi. - Fragment varsa tüm zincir atlanır (
:92-94):resolveFragment()view'i
basar,ob_get_clean()ile buffer'ı alır,getSection()ile tek bölümü
döndürür. Yani header/footer basılmaz. - Ayar okuma önceliği (
:59-77):array_merge([...varsayılanlar], $data)—
yani controller'ın geçtiği veri her zaman kazanır; ayarlardan gelen veri
yalnız controller verisi yoksa kullanılır. Yorum satırı:27-28bunu
"0 Duplicate Reads" diye açıklar.
3.1 safeSnippet() — ikinci katman (FrontendProvider.php:124-136)
4 snippet RawHtmlGate::sanitize()'den geçer: google_analytics_code,
google_adsense_code, head_scripts, body_scripts (:73-76). Bu değerler
view'da {!! !!} ile basıldığı için kaçış gerekmez; yazma yetkisi
SettingsConfig::REQUIRED_ROLE (admin/developer) ile sınırlıdır. Ayrıntı:
Handlers §4.
3.2 SeoProvider::render() — 5 segment (Providers/SeoProvider.php:20-64)
render($view, $data)
├─ $data['meta'] yoksa resolver('seo')->resolve('project') ile üret :23-26
├─ $view === 'branding' ise SADECE renderBranding() :32-34
└─ segmentler sırayla: technical → project → social → branding → links :36-40
Her segment "<!-- [ ETİKET ] -->" yorumuyla çerçevelenir;
baştaki/ sondaki RBN FRAMEWORK SEO ENGINE v<FRAMEWORK_VERSION> işaretleri :44, :61
renderProjectMeta() <title>'ı htmlspecialchars_decode() ile basar
(:91) — çünkü SeoResolver metni önceden temizlemişti (seoCleanText);
çift kaçışı önlemek için decode edilir. robots/description/keywords
ENT_NOQUOTES ile kaçırılır (:103-110).
4. Kayıt dışı iki provider — ViewProvider ve AjaxProvider
UI/ViewProvider.php ve UI/AjaxProvider.php SystemRenderMapTrait.php
providers listesinde yok (ölçüldü: 10 kayıt, 12 provider sınıfı).
Ama çalışıyorlar — çözümleme zincirinin 3. adımında bulunuyorlar:
$probe->provider('view') → Rbn\Framework\Core\Render\Providers\UI\ViewProvider (ölçüldü)
Nasıl? ComponentContext::resolve()
(Core/System/Discovery/Clusters/Logic/Component/ComponentContext.php:84):
DiscoveryEngine::instance()->namespace()->find("provider.view", 'provider')
→SystemRegistry::locate('view','provider')→'Rbn\Framework\Core\Render\Providers\UI\ViewProvider'
(ölçülen çıktı; tam yollu, RenderMap'teki kısa yollardan farklı olarak).NamespaceResolver::resolveCoreLayer()(Namespace/NamespaceResolver.php:109)
NamespaceMaptaban adları +Providers\ViewProviderkombinasyonunu dener;
Render => Rbn\Framework\Core\Render\girdisi listede olduğu için
Rbn\Framework\Core\Render\Providers\ViewProvideryok, ama
Framework => Rbn\Framework\+Rendermodül öneki varyantı var.
Ölçülen sonuç: NamespaceResolver::find('view','provider') →
'Rbn\Framework\Core\Render\Providers\UI\ViewProvider' döndü. Yani ViewProvider
fiziksel yolundan (UI/ altı) çözülüyor, kayıt haritasından değil.
Sonuç ve risk:
ViewProviderçalışıyor, ama kayıt tek doğruluk kaynağı değil —
SystemRenderMapTrait'e eklenirse aynı sınıf iki yerden gelir.UI/AjaxProvider.phphiçbir yerden çözülmüyor.aliasesharitasında
'ajax' => 'partials'var (SystemRenderMapTrait.php:100) yaniajax
tipiPartialProvider'a gider;AjaxProvidersınıfı ölü koddur.
View.php:53yorumu "Shift to AjaxProvider" der amatype = 'ajax'ataması
yapar veRenderService::render('ajax', …)→provider('ajax')→ alias →
PartialProvider. Ölçüldü:provider('ajax')çözümlemesi
SystemRenderMapTrait.php:100alias'ı üzerinden PartialProvider'dır.
(Kod değiştirilmedi — salt okunur belge.)
5. Yapılandırma ve varsayılanlar
| Değer | Kaynak |
|---|---|
SeoProvider çerçeve sürümü |
FrameworkIdentity::FRAMEWORK_VERSION (Providers/SeoProvider.php:44) |
| Varsayılan viewport | width=device-width, initial-scale=1.0 (SeoProvider.php:73) |
<title> kaçırma |
htmlspecialchars_decode() (SeoProvider.php:91) |
| meta kaçırma | htmlspecialchars(..., ENT_NOQUOTES, 'UTF-8') (SeoProvider.php:103) |
| Frontend varsayılan site adı | 'RBN Core' (UI/FrontendProvider.php:30) |
| Frontend snippet sayısı | 4 (UI/FrontendProvider.php:73) |
AssetProvider::decorate() etiketi |
?string $label = 'RBN Framework' (AssetProvider.php:108) |
6. Tuzaklar ve kurallar (kodda görülen + ölçülen)
- `Fragment istenince header/footer basılmaz (
:92-94). Bir partial
isteğinde sayfa başlığı/asset bloğu gelmez — view bu bloklara bağlıysa
boş kalır. Layouts/headerveLayouts/footerçözülemezse render yine devam eder
(:97-105if ($headerPath && file_exists(...))). Yalnız asıl view
zorunludur (:85-87handleMissing()). Yani eksik header sessiz eksik kalır.SchemaProvider::render()çıktısıappSchemaHtmlolarak frontend'e
enjekte edilir (:70), yani<head>içine view'dan basılır —render()
çağrısındacontextbilgisi taşınmaz.CrawlerProvider::render()tek giriş noktasıdır verenderRobots()/
renderSitemap()/renderFeed()/renderLlms()ayrı ayrı da çağrılabilir
(:39, :93, :187, :206).CrawlerController::feed()öncehasFeed()
kontrolü yapar ve değilseshield()->abort(404)(Controllers/CrawlerController.php:51)
— ölçülenhasFeed()mantığıgetProject('feed')'e dayanır.BreadcrumbProvider::resolveAndRender(array &$data, …)diziyi by-reference
değiştirir (:19) — view verisinebreadcrumbsekler.render()saf basım.
Bu yüzdenresolveAndRender()mutlaka view render'dan önce çağrılmalıdır.StaticProvider32 satırdır verender()imzası diğerlerinden farklı
değildir; pratikte yalnıztype='static'ile çağrılır.PartialProvider::renderImports()@importdizisini toplu basar
(:46); her içe aktarmaViewEngine::import()→path()+compile()
gider, yani her biri kök sınırından geçer (README §3.6).CrawlerProvideryasal sayfalarıservice('legal')ile okur (getActivePages,getActivePagesCount). Sayfa tablosu yoktur
(z_app_pageskaldırıldı); satışlı sitede zorunlu kimlik alanı boşsaLegalServiceaçık hata verir, sessizce boş basmaz (bkz. Yasal-Sayfa-Motoru §2).hasActiveFaqs()içerik varlığınız_app_faqs'ten sorar (is_active = 1). Sitemap üretimi bunu kullanır:
SSS rotası (FaqPage::PATH) yalnız aktif soru varken listelenir, yoksafaqPage()404 verir. Sorgu hata verirse
falsedöner (güvenli taraf: adres listelenmez).
7. Örnek (gerçek koddan)
// Core/Render/Providers/SeoProvider.php:44-61 (çerçeve + segment birleştirme)
$output = "\n <!-- 🔱 RBN FRAMEWORK SEO ENGINE [v" . FrameworkIdentity::FRAMEWORK_VERSION . " ] -->\n";
$output .= $techHtml . "\n";
$output .= "\n <!-- [ {$contextLabel} SEO ] -->\n" . $projectHtml . "\n";
$output .= $socialHtml . "\n";
$output .= "\n <!-- [ RESOURCE LINKS ] -->\n" . implode("\n", $linkHtml) . "\n";
$output .= "\n <!-- ⚓ RBN Framework SEO ENGINE - END -->\n";
// Ölçülen çözümleme — kayıt haritasında olmayan provider
// provider('view') → Rbn\Framework\Core\Render\Providers\UI\ViewProvider
// provider('ajax') → aliases['ajax'] = 'partials' → PartialProvider (AjaxProvider ölü kod)
8. İlgili belgeler
- Core/Render genel · Resolvers · Builders ·
Handlers · Controllers - Core/Base/Web.md · Core/System/Registries.md ·
Core/System/Discovery.md (çözümleme zinciri) - Kavram: asset · Açık sorular §1.11