Installation
composer require symfony/templating
No additional configuration is needed for basic usage—just autoload the Symfony\Component\Templating\TemplateNameParser and Symfony\Component\Templating\EngineInterface classes.
First Use Case: Rendering a Template
use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\Templating\TemplateNameParser;
// Initialize the parser (handles template name resolution)
$parser = new TemplateNameParser();
// Use a templating engine (e.g., PHP, Twig, or a custom one)
$engine = new \Symfony\Component\Templating\PhpEngine(
new \Symfony\Component\Templating\Loader\FilesystemLoader('/path/to/templates')
);
// Render a template
$content = $engine->render('template.html.twig', ['name' => 'John']);
Where to Look First
EngineInterface: The main interface for templating engines.TemplateNameParser: Resolves template names (e.g., @Bundle/Controller/template.html.twig).LoaderInterface: Loads template content (e.g., FilesystemLoader, FilesystemLoader for files, ChainLoader for multiple sources).PhpEngine: Renders PHP templates (e.g., .html.php).TwigEngine: Integrates with Twig (requires twig/twig).PhpEngine is the simplest for quick prototyping.$loader = new \Symfony\Component\Templating\Loader\FilesystemLoader('/templates');
$engine = new \Symfony\Component\Templating\PhpEngine($loader);
$loaders = [
new \Symfony\Component\Templating\Loader\FilesystemLoader('/app/templates'),
new \Symfony\Component\Templating\Loader\FilesystemLoader('/vendor/templates'),
];
$loader = new \Symfony\Component\Templating\Loader\ChainLoader($loaders);
LoaderInterface for dynamic templates (e.g., database-backed templates).Use PHP templating with yield and extends (similar to Twig):
// base.html.php
<html>
<body>
<?php yield('content') ?>
</body>
</html>
// child.html.php
<?php $view->extend('base.html.php') ?>
<?php $view->block('content') ?>
<h1>Hello, <?php echo $name ?></h1>
<?php endblock() ?>
Render with:
$engine->render('child.html.php', ['name' => 'John']);
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('templating', function () {
$loader = new \Symfony\Component\Templating\Loader\FilesystemLoader(resource_path('views'));
return new \Symfony\Component\Templating\PhpEngine($loader);
});
}
// app/Helpers/Templating.php
function renderTemplate(string $template, array $data = []): string
{
return app('templating')->render($template, $data);
}
PhpEngine to render Blade templates (if pre-compiled to PHP).$parser = new TemplateNameParser();
$templateName = $parser->parse('@AcmeBundle/Template/template.html.twig');
// Resolves to '/path/to/AcmeBundle/Resources/views/Template/template.html.twig'
try {
$engine->render($templateName, $data);
} catch (\Symfony\Component\Templating\TemplateNotFoundException $e) {
// Fallback to a default template
$engine->render('default.html.php', $data);
}
$cacheLoader = new \Symfony\Component\Templating\Loader\FilesystemLoader(
'/templates',
new \Symfony\Component\Cache\Simple\FilesystemCache('/cache')
);
$cacheKey = 'template_' . md5($template . serialize($data));
$content = Cache::remember($cacheKey, 3600, function () use ($engine, $template, $data) {
return $engine->render($template, $data);
});
Template Path Resolution
FilesystemLoader throws TemplateNotFoundException if the path is incorrect.$loader = new \Symfony\Component\Templating\Loader\FilesystemLoader(
app_path('Resources/views') // Laravel-specific
);
Namespace Collisions
@Bundle/Template/template.html.twig may not resolve if the bundle structure isn’t standard.TemplateNameParser or use absolute paths.PHP Engine Limitations
PhpEngine doesn’t support Twig’s advanced features (e.g., filters, tests).TwigEngine for Twig-specific functionality or pre-process templates.Memory Leaks with Caching
Psr6CacheAdapter) and clear stale entries.Security Risks
$allowedTemplates = ['home.html.php', 'about.html.php'];
if (!in_array($template, $allowedTemplates)) {
throw new \InvalidArgumentException('Template not allowed.');
}
Enable Debug Mode
Symfony’s templating component integrates with the DebugClassLoader for stack traces:
$loader = new \Symfony\Component\Templating\Loader\FilesystemLoader(
'/templates',
null,
true // Enable debug mode
);
Log Template Not Found Errors
Catch TemplateNotFoundException and log the missing template:
try {
$engine->render($template, $data);
} catch (\Symfony\Component\Templating\TemplateNotFoundException $e) {
\Log::error("Template not found: {$e->getTemplateName()}");
throw $e;
}
Inspect Rendered Output
Use ob_start() to capture output for debugging:
ob_start();
$engine->render($template, $data);
$output = ob_get_clean();
\Log::debug("Rendered template output: {$output}");
Custom Templating Engine
Implement EngineInterface for a new engine (e.g., Mustache, Smarty):
class MyEngine implements EngineInterface
{
public function render(string $name, array $parameters): string
{
// Custom logic here
return "Rendered {$name} with " . count($parameters) . " parameters";
}
}
Template Pre-Processing
Extend LoaderInterface to modify templates before rendering:
class PreprocessingLoader implements LoaderInterface
{
private $decorated;
public function __construct(LoaderInterface $decorated)
{
$this->decorated = $decorated;
}
public function load(string $name): string
{
$content = $this->decorated->load($name);
return $this->preprocess($content);
}
private function preprocess(string $content):
How can I help you explore Laravel packages today?