DbM Template Engine
Dokumentacja jest stale rozwijana i aktualizowana wraz z postępem projektu. Ponieważ powstaje ona równolegle z kodem, niektóre sekcje mogą tymczasowo odnosić się do wcześniejszych wersji systemu - są one sukcesywnie dostosowywane do bieżącego stanu aplikacji. Jeśli zauważysz nieaktualne informacje, zgłoś to lub załóż Issue / Pull Request.
Dokumentacja
# DbM Template Engine
Lekki, szybki i bezpieczny silnik szablonów dla PHP — DbM Template Engine (namespace Dbm\Views).
Zaprojektowany z myślą o czytelności, testowalności i prostocie integracji z aplikacjami MVC.
# Wprowadzenie
DbM Template Engine to prosty system szablonów, który konwertuje składnię podobną do Twig/Blade do czystego PHP, zapisuje skompilowany kod w cache i uruchamia go w bezpiecznym kontekście runtime. Celem było uzyskanie dobrego kompromisu pomiędzy wydajnością (cache), bezpieczeństwem (domyślne escapowanie wyjścia) oraz elastycznością (filtry, partiale, dziedziczenie layoutów).
# Cechy
- Kompilacja składni
{% ... %}i{{ ... }}do PHP. - Cache plikowy dla skompilowanych klas (
TemplateCache). - Runtime z obsługą bloków (
TemplateRuntime) i delegacją do kontrolera. - System filtrów (
FilterExtension) z możliwością rejestracji własnych filtrów i obsługą parametrów. - Opcjonalne lintowanie wygenerowanego kodu PHP przed zapisaniem (tryb
enableLint). - Tryb debugujący zapisujący wersje pośrednie (opcja
enableDebugger).
# Instalacja
- Umieść kod pod namespace
Dbm\Viewsw swoim projekcie (PSR-4). - Upewnij się, że masz zdefiniowane globalnie stałe (projekt przykładowy):
define('BASE_DIRECTORY', dirname(__DIR__));. - Ustaw katalog
templatesivar/cachez prawidłowymi uprawnieniami do zapisu.
# Szybki start
use Dbm\Views\{
TemplateEngine,
TemplateCompiler,
TemplateCache
};
use Dbm\Views\Extension\FilterExtension;
$templatesDir = __DIR__ . '/templates';
$cacheDir = __DIR__ . '/var/cache';
$filters = new FilterExtension();
$compiler = new TemplateCompiler($templatesDir, $filters);
$cache = new TemplateCache($cacheDir);
$engine = TemplateEngine::createFromComponents($compiler, $cache);
// lub: $engine = TemplateEngine::createFromPaths($templatesDir, $cacheDir);
echo $engine->render('home.phtml', ['title' => 'Witaj']);
Sugerowane podejście: użyj fabryki createFromComponents() zamiast konstruktora. To czystsze i bardziej przewidywalne API.
# API — klasy i ich role
# TemplateEngine
Główna klasa integrująca kompilator, cache i runtime. Odpowiada za publiczne API: render(), renderContent() itp.
Rekomendowane konstruktory/fabryki:
TemplateEngine::createFromComponents(TemplateCompiler $compiler, TemplateCache $cache)
# TemplateCompiler
Konwertuje plik szablonu do PHP. Udostępnia metody pomocnicze (getter ścieżki i filters) dla integracji i testów:
compile(string $templateName): stringgetTemplatesPath(): stringgetFilters(): FilterExtension
# FilterExtension
Rejestr i generator filtrów. Pozwala rejestrować filtry i generować wyrażenia PHP:
applyPhp(string $expr, array $filters): stringregister(string $name, callable $phpGenerator): void
# TemplateCache
Zarządza zapisem i sprawdzaniem świeżości plików cache:
getCachePath(string $template): stringisFresh(string $templatePath, string $cachePath): boolwrite(string $cachePath, string $code): voidclear(): int,clearExpired(string $templatesDir): int
# TemplateRuntime
Bazowa klasa wykonywana po załadowaniu skompilowanej klasy szablonu. Udostępnia:
- Bloki (
startBlock,endBlock,yieldBlock), renderPartial(),- delegację metod do kontrolera/engine,
getEngineInstance().
# TemplateException / RuntimeException
Dedykowane wyjątki dla problemów z kompilacją, zapisem cache itp.
# Składnia szablonów
Krótka ściąga:
{{ expr }}— echo z escapowaniem:htmlspecialchars((string)(expr ?? ""), ENT_QUOTES, "UTF-8"){{ expr|raw }}— echo bez escapowania{{ value|upper|escape }}— łańcuch filtrów{% if (cond) %} ... {% endif %}— warunki{% foreach (items as item) %} ... {% endforeach %}— pętle{% block name %} ... {% endblock %}— bloki{% yield name %}— wstawienie bloku{% extends 'parent.phtml' %}— dziedziczenie layoutu{% include 'partial.phtml' with { 'a': 1 } %}— partial z lokalnymi danymi{{ var|raw_allowed(['br','b']) }}— filtr zezwalający tylko na podane tagi HTML
# Filtry domyślne i rozszerzanie
Przykładowe wbudowane filtry: escape (alias e), raw (alias safe), upper, lower, trim, length, nl2br, strip, json, url, join, number, date, raw_allowed.
Możesz dodać własny filtr:
$filters->register('truncate', function(string $expr, string $args = '50') {
return "mb_substr({$expr}, 0, {$args}) . (mb_strlen({$expr}) > {$args} ? '...' : '')";
});
# Filtr raw_allowed(['br','b'])
Implementacja używa strip_tags($value, '<br><b>'). Upewnij się, że parametry są przekazywane jako tablica lub jako literal w filtrze (raw_allowed(['br','br'])).
# Obsługa błędów i debugowanie
- Nie używamy operatora
@do tłumienia błędów (zamiast tego: jawne sprawdzanie i rzucanie wyjątków). Wyjątkiem może być@unlink()przy czyszczeniu cache, gdy operacja jest best-effort. enableDebugger— przy włączeniu zapisuje kopie skompilowanych plików w katalogu debugowym oraz pozwala na bardziej przejrzyste komunikaty (np. HTML-komentarze w widoku podczas błędu partiala).enableLint— (opcjonalne) uruchomieniephp -lna pliku wygenerowanym przed przeniesieniem go do cache.
# Testowanie
Zalecany stack: PHPUnit. Przykłady testów:
- Test prostego renderu z filtrem (
{{ name|upper }}). - Test partiala i przekazywania danych (
include ... with {...}). - Test bloków i dziedziczenia (
extends+block+yield). - Testy integracyjne kończące się na wywołaniu
render()i porównaniu stringów.
Przykład testu (szybka wersja):
final class TemplateEngineTest extends TestCase
{
protected function setUp(): void
{
$this->tplDir = __DIR__ . '/templates';
$this->cacheDir = __DIR__ . '/cache';
if (!is_dir($this->tplDir)) mkdir($this->tplDir, 0777, true);
if (!is_dir($this->cacheDir)) mkdir($this->cacheDir, 0777, true);
$filters = new FilterExtension();
$compiler = new TemplateCompiler($this->tplDir, $filters);
$cache = new TemplateCache($this->cacheDir);
$this->engine = TemplateEngine::createFromComponents($compiler, $cache);
}
public function testSimpleRender(): void
{
file_put_contents($this->tplDir . '/simple.phtml', 'Hello {{ name|upper }}');
$result = $this->engine->render('simple.phtml', ['name' => 'world']);
$this->assertStringContainsString('WORLD', $result);
}
}
# Dobre praktyki i wskazówki migracyjne
- Preferuj DI: przekazuj gotowe obiekty (
TemplateCompiler,TemplateCache) doTemplateEnginew celu lepszej testowalności. Alternatywnie, udostępnij fabryczne metodycreateFromPaths()dla wygody. - Nie używaj
@: nie tłumisz ostrzeżeń — radź sobie z nimi jawnie (throw/exceptions) lub obsłuż w logiczny sposób. - Zadbaj o uprawnienia: katalog cache musi być zapisywalny przez proces PHP.
- Filtry: rejestruj nowe filtry w jednym miejscu (konfiguracja lub container).