spiral/twig-bridge
Twig adapter for the Spiral Framework. Adds a Twig view engine via TwigBootloader, with support for custom extensions, options, and processors. Configure eagerly through TwigEngine or lazily through TwigBootloader. Requires spiral/views.
Installation Add the package via Composer:
composer require spiral/twig-bridge
Register the TwigBridge service provider in config/app.php under providers:
Spiral\TwigBridge\TwigBridgeServiceProvider::class,
Basic Configuration Publish the default config (optional):
php artisan vendor:publish --provider="Spiral\TwigBridge\TwigBridgeServiceProvider" --tag="config"
Configure paths in config/twig-bridge.php:
'paths' => [
'templates' => resource_path('views'),
'cache' => storage_path('framework/views'),
],
First Use Case: Rendering a Template
Inject the TwigBridge into a controller or service:
use Spiral\TwigBridge\TwigBridgeInterface;
class HomeController
{
public function __construct(private TwigBridgeInterface $twig)
{
}
public function index()
{
return $this->twig->render('home.index.twig', [
'title' => 'Welcome',
]);
}
}
Template Rendering
render() to output templates directly:
$html = $this->twig->render('email.welcome.twig', ['user' => $user]);
renderStream() to avoid memory issues:
$this->twig->renderStream('report.large.twig', $data);
Reusable Components
{% embed 'layouts/base.twig' %}
{{ block('content') }}
{% endembed %}
{% macro alert(type, message) %}
<div class="alert alert-{{ type }}">{{ message }}</div>
{% endmacro %}
Integration with Laravel
'paths' => [
'templates' => [resource_path('views/twig'), resource_path('views/blade')],
],
public function handle($request, Closure $next)
{
$request->twig = $this->twig;
return $next($request);
}
Dynamic Template Selection
$template = $user->prefersDarkMode() ? 'dark.layout.twig' : 'light.layout.twig';
return $this->twig->render($template, $data);
Testing
TwigBridgeInterface in tests:
$this->mock(TwigBridgeInterface::class)->shouldReceive('render')->once()->andReturn('<html>...</html>');
Caching
'cache' => [
'enabled' => env('APP_ENV') === 'production',
],
php artisan twig:clear-cache
Extensions
$this->twig->getEnvironment()->addExtension(new \Your\CustomExtension());
Error Handling
config/twig-bridge.php:
'debug' => env('APP_DEBUG', false),
Asset Management
asset() function (if integrated with Laravel Mix/Vite):
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
Path Configuration
templates and cache paths are writable:
chmod -R 775 storage/framework/views
Namespace Conflicts
twig namespace by default. Avoid naming conflicts with Laravel’s Blade directives:
{# Not @if, but {% if %} #}
Caching Quirks
php artisan twig:clear-cache
Dependency Injection
TwigBridgeInterface will throw BindingResolutionException.// Avoid:
$this->twig = app(TwigBridgeInterface::class);
Twig vs. Blade Syntax
{# Twig: {% if %} #}
@if(true) {# Blade: @if #}
{{-- This will fail --}}
@endif
Enable Debug Mode
Set debug: true in config/twig-bridge.php to get detailed error messages.
Template Not Found
paths.templates in config and ensure the file exists.Variable Errors
{{ variable|default('fallback') }} to avoid errors.Performance Issues
twig:profile command (if available).Extension Conflicts
$env->removeExtension($extension);
Custom Filters Add a filter to Twig:
$this->twig->getEnvironment()->addFilter(new \Twig\TwigFilter('custom_filter', function ($value) {
return strtoupper($value);
}));
Global Variables Pass data to all templates:
$this->twig->getEnvironment()->addGlobal('app_name', config('app.name'));
Custom Functions Register a Twig function:
$this->twig->getEnvironment()->addFunction(new \Twig\TwigFunction('greet', function ($name) {
return "Hello, $name!";
}));
Event Listeners
Listen to Twig events (e.g., Twig\SourceContextLoadedEvent):
$this->twig->getEnvironment()->addEventListener(\Twig\SourceContextLoadedEvent::class, function ($event) {
// Log template paths
});
Override Default Environment
For advanced use cases, bind a custom Twig\Environment:
$this->app->bind(TwigBridgeInterface::class, function ($app) {
$loader = new \Twig\Loader\FilesystemLoader($app['config']['twig-bridge.paths.templates']);
$env = new \Twig\Environment($loader, [
'cache' => $app['config']['twig-bridge.paths.cache'],
]);
return new TwigBridge($env);
});
How can I help you explore Laravel packages today?