Core/Render/Builders — durum biriktiriciler (varlık, SEO, schema, breadcrumb, sitemap, feed, llms)
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/Builders/— 7*.php.
Envanter: 7 dosyanın 7'si anlatıldı.
Doğrulama platformu: Windows + PHP 8.3,AssetBuildergerçekten çalıştırılarak.
1. Ne işe yarar, kim kullanır
Yedi sınıfın ortak işi veri toplamak ve bir çıktı dizisine/stringsine dönüştürmek;
hiçbiri HTTP yanıtı yazmaz, hiçbiri ViewEngine'i çağırmaz. Hepsi
BaseComponent/BaseRender'dan türer ve kayıt altında handlers olarak durur
(SystemRenderMapTrait.php:37) — yani $this->handler('seoBuilder') ile
erişilir. Çıktıyı asıl basan sınıflar Providers'tadır.
Tuzak: handler('seoBuilder') bir Builder'ı döndürür, resolver('seo')
ise Resolver. İkisi karıştırılmamalı; SeoBuilder override'ları biriktirir,
SeoResolver bunları SettingsService verisiyle birleştirir.
2. Klasör/dosya envanteri (7/7)
| Dosya | Görev | Önemli public yöntemler |
|---|---|---|
AssetBuilder.php (378) |
Varlık kuyruğu + derleyici + sıralayıcı. prepare() çekirdek yığını ve özel kaynakları toplar, build() sıralayıp styles/scripts dizisi döndürür. |
reset(): self, addStyle(string $path,int $priority=10): self, addScript(string $path,array $attrs=[],bool $inHead=false,int $priority=10): self, addFont(string $name,int $priority=15): self, prepare(string $appContext,$source=null): self, build(): array, compile($item,string $appContext='frontend'): ?array · korumalı: collect(), injectCoreStack(), generateWebUrl(), resolveToken(), detectType() |
SeoBuilder.php (195) |
Sayfa bazlı SEO override biriktirici. prepare() resolver çıktısıyla birleştirip payload() üretir. |
reset(): self, setTitle(?string), setDescription(?string), setKeywords(?string), setCanonical(?string), noIndex(string $directives='noindex, nofollow'), setImage(string), getOverrides(): array, payload(): array, hasPayload(): bool, prepare(string $context='project',array $overrides=[]): self, build(array $resolved): array |
SchemaBuilder.php |
JSON-LD düğüm üreticisi, tür başına bir metot: organization(), webSite(), page(), itemList(), breadcrumbs(), blogPosting(), newsArticle(), tvSeries(), movie(), person(), product(), serviceNode() (+ schema(), addRaw()). Değer yoksa alan düşer; aggregateRating/review/FAQPage/SearchAction üretilmez. Ayrıntı: Yapisal-Veri-Head-Izin.md. |
schema(string\|array $type,array $data): self, organization(array), webSite(array), page(string,array), itemList(array), breadcrumbs(array), blogPosting(array), newsArticle(array), tvSeries(array), movie(array), person(array), product(array), serviceNode(array), geo(?string): ?array, phone(string,string): ?string |
BreadcrumbBuilder.php (130) |
Kırıntı (breadcrumb) adımlarını biriktirir; ana adımı korpustan, alt adımları BreadcrumbResolver'dan alır. |
reset(): self, build(…), add(string $title,string $url,string $icon='',bool $active=false): self |
SitemapBuilder.php |
Sitemap girdilerini biriktirir ve <urlset>/<sitemapindex> XML'i üretir (google-arama/sitemap.md): UTF-8, mutlak <loc> (2.048 karakterden kısa; geçersiz adres addUrl() ile reddedilir, çözücüler isValidLoc() ile eler), & ' " > < varlık kaçışı ('), dosya başına en çok 50.000 girdi ve 50 MB (aşılırsa LengthException; çözücü dosyaları böler ve indeks yazar). lastmod yalnız verilen GERÇEK değişiklik tarihidir (FormatHelper::toIso8601()); tarihsiz girdide etiket yoktur. <priority> ve <changefreq> YAZILMAZ (Google yok sayar). |
MAX_ENTRIES=50000, MAX_BYTES=52428800, MAX_LOC_LENGTH=2048, reset(): self, addUrl(string $loc,?string $lastmod=null): self, addUrls(array $urls): self, getEntries(): array, hasEntries(): bool, buildXml(bool $isIndex=false): string · statik: isValidLoc(string $loc): bool |
FeedBuilder.php |
RSS 2.0 feed XML'i üretir (google-arama/rss-besleme.md). Öğe: link ZORUNLU, title ya da description'dan en az biri (ikisi de boşsa öğe atlanır), aynı link tek öğe, guid = link, pubDate yalnız gerçek yayın tarihi varsa (RFC 822). lastBuildDate = en yeni pubDate. <enclosure> YAZILMAZ (RSS 2.0 length ister, bilinmez). Açıklama CDATA içindedir, ]]> iki bölüme ayrılır. |
setChannel(array $channel): self, addPosts(array $posts): self, buildXml(): string · korumalı: clean(string $string,bool $stripNewlines=false): string |
LlmsBuilder.php |
llms.txt (Markdown) üretir: tek H1 (site adı), gerçek site özeti varsa blockquote (dolgu metin yok), ## Başlık altında - [ad](url) maddeleri, ikincil bağlantı (sitemap) ## Optional altında. Biçim llmstxt.org önerisidir. |
reset(): self, setSiteInfo(string $siteName,string $siteUrl,string $summary=''): self, addSection(string $title,array $items): self, buildMarkdown(): string · statik: sanitizeText(string $text): string, link(string $title,string $url): string (içerik kaynaklı metni tek satıra / güvenli bağlantı biçimine indirir) |
3. Akış — AssetBuilder (en karmaşık zincir)
FrontendProvider::render() → AssetService::prepareContext($context)
(Services/AssetService.php:28) → AssetBuilder::prepare($appContext, $source).
AssetService::prepareContext('frontend') Services/AssetService.php:28
└─ AssetBuilder::prepare('frontend', 'frontend') Builders/AssetBuilder.php:79
1. injectCoreStack($payload, $appContext) :87 → :245-283
├─ route config 'css_engine' okunur (bootstrap | rbn) :250-252
├─ AssetBundles::STACK_MAP['universal'] paketleri :257-263
│ · auth/panel ya da rbn motoru ise bootstrap,
│ bootstrap_icons, font_awesome ATLANIR (0 KB bypass) :259-261
├─ auth/panel ya da (rbn motoru + frontend) → 'rbn_master' :266-268
├─ STACK_MAP[$appContext] paketleri :270-274
└─ auth/panel/rbn → common.css + rbnAlert.css filtrelenir :277-282
2. collect($payload, $source, $appContext) :90 → :207-240
· AssetBundles::BUNDLES ile ad→paket açılımı :215-219
· Özyineleme derinliği 8 ile sınırlı :209-213
· '.css' veya '@font/' ile başlayan → styles, diğer → scripts :232-237
3. frontend özel font varsa varsayılan Inter temizlenir :93-113
4. Her girdi compile() edilip kuyruğa eklenir :116-134
5. return $this
AssetService::render('header') → AssetBuilder::build() Services/AssetService.php:51
├─ frontend & hiç font yoksa '@font/Inter' + priority 5 :154-162
├─ uasort() × $sortFn (proje son, çekirdek motor ilk, sonra prio) :164-196
└─ ['styles'=>…, 'scripts'=>…]
3.1 Sıralama kuralı — ölçüldü
build() içindeki $sortFn üç kademeli (AssetBuilder.php:164):
/project-assets/ile başlayan daima en son;bootstrap/rbn-master.css/rbn-core.cssiçeren daima ilk;- sonra
priorityartan.
Ölçülen çıktı (DOC-AGAC-3-dogrula3.php V4):
/framework-assets/css/rbn-core.css prio=1
/framework-assets/css/bootstrap.min.css prio=5
http://localhost/framework-assets/fonts/inter prio=5 ← otomatik Inter
/project-assets/css/site.css prio=99
3.2 Token çözümleme ve web URL'i (AssetBuilder.php:289-377)
compile($item):
resolveToken($path)→@project/veya@fw/öneki soyulur; kalan
kaynaksızsanullhint döner;@font/→ hintfont(:350-369).DiscoveryEngine::instance()->assets()->resolve($cleanPath, $sourceHint)
fiziksel dosyayı bulur; bulunamazsa vehttpiçermiyorsanulldöner
(kuyruğa eklenmez —:297-299).- Sürüm:
AssetConfig::VERSION(1.0), fiziksel dosya varsafilemtime()
(:301-304). generateWebUrl():- hint
font→/framework-assets/fonts/<slug>(:320-322); httpiçeriyorsa olduğu gibi döner (:324-326);- framework kaynağı ve çok parçalı yol →
<küme>/<dosya>(küme = ilk parça,
imageshariç tam yol küçük harfle) (:335-342); - sonuç:
url('/<proxy>/<yol>=v<sürüm>')(:347).
- hint
detectType()→ uzantı →AssetConfig::EXTENSION_MAP, varsayılanjs(:373-377).
4. Yapılandırma ve varsayılanlar
| Sabit | Değer | Kaynak |
|---|---|---|
AssetConfig::VERSION |
1.0 |
Configs/AssetConfig.php:18 |
AssetConfig::PROXY_SETUP['project'] |
{"path":"project-assets","token":"@project/"} |
AssetConfig.php:26 (ölçüldü) |
AssetConfig::PROXY_SETUP['framework'] |
{"path":"framework-assets","token":"@fw/"} |
AssetConfig.php:30 (ölçüldü) |
AssetConfig::EXTENSION_MAP |
css→css, js→js, mjs→js, less→css, scss→css, png/jpg/svg→image, json→data |
AssetConfig.php:80 |
SeoConfig::VERSION |
1.3 |
Configs/SeoConfig.php:19 (ölçüldü) |
| Varsayılan font önceliği | 5 (en üstte yüklensin) |
AssetBuilder.php:159 |
| Varsayılan font | @font/Inter (yalnız frontend bağlamında) |
AssetBuilder.php:154 |
addFont önceliği |
15 |
AssetBuilder.php:70 |
| Özyineleme sınırı | 8 |
AssetBuilder.php:210 |
| CSS motoru tercihi | route config css_engine: bootstrap (varsayılan) | rbn |
AssetBuilder.php:250 |
BreadcrumbConfig::TERMINAL_ACTIONS |
["view","show","preview","download"] |
Configs/BreadcrumbConfig.php:77 (ölçüldü) |
5. Tuzaklar ve kurallar (ölçülmüş)
-
addStyle()veaddScript()ikisi de yinelenen yolu eler — koruma
çalışıyor.addStyle()!isset($this->styles[$path])kullanır
(AssetBuilder.php:41),addScript()dizi taraması yapar (:52-56).
Ölçüldü:addStyle('x.css',1),addStyle('y.css',2),addStyle('x.css',9)
→$stylesanahtarları["x.css","y.css"](2 eleman) vex.css
önceliği 1'de kalır (ikinci çağrının9değeri yok sayılır).
addScript('/a.js')iki kez →build()['scripts']1 eleman.
(Not:build()['styles']bu durumda 3 eleman döndürür — fark, otomatik
Inter fontundur (§5.2), çoğalma değildir. İlk ölçüm yanlış yorumlanmıştı;
acik-sorular.md§1.8 bu düzeltmeyle güncellendi.) -
⚠️
addFont()gerçek bir çift-font riski taşıyor (ölçüldü).
build()'in "hiç font yoksa Inter ekle" kontrolü derlenmiş yola bakar
(str_contains($path, '/fonts/'),AssetBuilder.php:148), amaaddFont()
kuyruğa derlenmemiş@font/<ad>yazar (:72). Ölçülen sonuç:Çağrı $stylesanahtarlarıbuild()['styles']addFont('Inter')["@font/Inter"]1 — …/fonts/inter(prio 5)addFont('Roboto')["@font/Roboto"]2 — …/fonts/inter(prio 5) +@font/Roboto(prio 15)Yani
addFont('Roboto')çağrısında varsayılan Inter de eklenir: kontrol
@font/Robotoyolunda/fonts/bulamaz (yol henüz derlenmemiş), font
yok sayar ve Inter'i ekler.prepare()akışında bu düzelir
(AssetBuilder.php:93temizliğipayloadüzerinde çalışır ve@font/
ile başlayan ham yolları görür); amaaddFont()doğrudan
AssetService/controller üzerinden çağrılırsa çift font basılır
(FrontendBaseController::addAsset()→AssetService::addStyle()yolu).
(Beklenen:build()içindeki font kontrolüstr_contains($path, '/fonts/')
veyastr_starts_with($path, '@font/')ile iki biçimi de kabul etsin.
Kod değiştirilmedi — belge salt okunurdur.) -
prepare()font temizliği yalnızfrontendbağlamında çalışır
(:93).panel/authbağlamında özel font eklenirse temizlenmez. -
compile()çözülemeyen yoluNULLdöndürür → kuyruğa eklenmez
(:297-299). Ölçüldü:Girdi Sonuç /framework-assets/css/yok.cssNULL@project/css/a.cssNULL(proje diskinde yok)@font/Inter{"path":"…/framework-assets/fonts/inter","type":"js", …}https://cdn.example.com/x.js{"path":"https://cdn.example.com/x.js","type":"js", …}(olduğu gibi)Yani bulunamayan varlık sessizce düşer (404 değil, hiç
<link>/<script>
bile basılmaz) ve dış CDN adresleri doğrulamasız geçer. -
injectCoreStack()panel/auth bağlamındarbn_masteryalnızauth
için yüklenir (:266:$isAuthContext || ($isRbnEngine && $appContext === 'frontend')).
Yani panel (authdeğil) +rbnmotoru kombinasyonundarbn_master
yüklenmez; yalnızbootstrap'lar atlanır (:259). Panelinrbnmotoruyla
stil eksikliği yaşaması bu satırdan gelir. -
SchemaBuilder::geo()dönüş tipiarray, diğerleriself—
schema(string $type,array $data)zincirinegeo()doğrudan eklenemez
(:376). -
SitemapBuilder::buildXml(bool $isIndex=false)—<sitemapindex>üretimi
içintruegerekir;SitemapResolverhangisini seçtiğine göre çağırır. -
SitemapBuilder::addUrl()yalnızlocvelastmodalır. Öncelik/changefreq parametresi YOKTUR (Google yok sayar); proje verisindeki eskipriority/changefreqanahtarları okunmaz. -
BreadcrumbBuilder::build()imzası çok parametreli (:31-…);
kaynakBreadcrumbResolver::resolve()'dır. Kırıntı akışı:
BreadcrumbProvider::resolveAndRender()→BreadcrumbResolver→BreadcrumbBuilder.
6. Örnek (gerçek koddan)
// Core/Render/Services/AssetService.php:98-100 (kuyruğa ekleme)
public function addScript(string $path, array $attrs = [], bool $inHead = false, int $priority = 10): void
{
$this->handler('assetBuilder')->addScript($path, $attrs, $inHead, $priority);
}
// Ölçülen çıktı — addFont + otomatik Inter davranışı
$ab->reset(); $ab->addFont('Inter');
// build()['styles'] => [ ['path' => 'http://localhost/framework-assets/fonts/inter', 'priority' => 5] ]
7. İlgili belgeler
- Core/Render genel · Providers ·
Configs · Resolvers - Kavram: asset sistemi ·
Support/Definitions (AssetBundles,AssetConvention) ·
Açık sorular §1.8 (addStyleçoğalması)