Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twigbridge Laravel Package

rcrowe/twigbridge

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require rcrowe/twigbridge
    php artisan vendor:publish --provider="TwigBridge\ServiceProvider"
    

    This publishes the default config file to config/twig.php.

  2. First Twig View: Create a .twig file in resources/views/ (e.g., welcome.twig):

    <h1>{{ 'Hello, ' ~ user.name }}!</h1>
    

    Render it via a route:

    Route::get('/', fn() => view('welcome', ['user' => new class { public $name = 'Twig'; }]));
    
  3. Key Config: Update config/twig.php to define:

    • paths (custom view paths, e.g., ['custom' => resource_path('views/custom')]).
    • cache (enable/disable Twig cache for development/production).
    • extensions (register custom Twig extensions).

First Use Case

Replace a Blade template with Twig for a complex email template (e.g., resources/views/emails/welcome.twig):

{% extends 'layouts.email.twig' %}

{% block content %}
  <p>Hi {{ user.name }},</p>
  <p>Your verification link: <a href="{{ url('verify', token) }}">Verify</a></p>
{% endblock %}

Pass data via a controller:

Mail::send('emails.welcome', ['user' => $user, 'token' => $token]);

Implementation Patterns

Core Workflows

  1. Hybrid Blade/Twig Projects:

    • Use Blade for most views, Twig for templates requiring advanced logic (e.g., email templates, PDF generation).
    • Example: Override Laravel’s default mail template engine:
      // config/mail.php
      'markdown' => [
          'engine' => Twig::class,
      ],
      
  2. Dynamic Template Rendering:

    • Pass data and logic to Twig views:
      // Controller
      return view('dashboard.twig', [
          'stats' => $this->getStats(),
          'filters' => $request->filters,
      ]);
      
      {# dashboard.twig #}
      {% for stat in stats %}
        <div>{{ stat.label }}: {{ stat.value|upper }}</div>
      {% endfor %}
      
  3. Reusable Components:

    • Create Twig includes (_partials/header.twig) and extends:
      {# _partials/header.twig #}
      <header>
        <h1>{{ title|default('Default Title') }}</h1>
      </header>
      
      {# page.twig #}
      {% include '_partials/header.twig' with {'title': 'Home'} %}
      
  4. Form Handling:

    • Leverage Twig’s form extensions for validation/error display:
      <form method="POST">
        <input type="text" name="email" value="{{ form.email.value }}">
        {% for error in form.email.errors %}
          <span class="error">{{ error }}</span>
        {% endfor %}
      </form>
      
      Pass the Form object from Laravel:
      return view('contact.twig', ['form' => $form]);
      
  5. API Responses:

    • Render Twig as JSON for API clients:
      return response()->json(['html' => view('email_body.twig', $data)->render()]);
      

Integration Tips

  • Laravel Mix/Vite: TwigBridge plays well with asset pipelines. Use {{ asset('js/app.js') }} in Twig as usual. Example:

    <script src="{{ asset('js/app.js') }}"></script>
    
  • Service Providers: Bind custom Twig extensions in a service provider:

    public function boot()
    {
        Twig::getEnvironment()->addExtension(new \App\Twig\CustomExtension());
    }
    
  • Testing: Mock Twig views in PHPUnit:

    $view = new \TwigBridge\ViewFactory();
    $html = $view->make('welcome.twig', ['user' => $user])->render();
    $this->assertStringContainsString('Hello', $html);
    

Gotchas and Tips

Pitfalls

  1. Caching Quirks:

    • TwigBridge caches compiled templates by default in production. Clear cache after changes:
      php artisan twig:clear
      
    • Debug cache issues with:
      'cache' => false, // config/twig.php
      
  2. Namespace Collisions:

    • Avoid naming Twig files identically to Blade files (e.g., home.blade.php vs. home.twig). Use distinct namespaces or prefixes.
  3. Extension Loading Order:

    • Extensions registered in config/twig.php under extensions must implement Twig\Extension\ExtensionInterface. Load them after the default extensions to avoid overrides.
  4. Laravel Helpers in Twig:

    • Not all Laravel helpers (e.g., old(), csrf_field()) are auto-available in Twig. Use the TwigBridge\Twig\Extension\LaravelExtension or manually register:
      Twig::getEnvironment()->addFunction(new \Twig\TwigFunction('csrf_field', fn() => csrf_token()));
      
  5. Form Request Binding:

    • For Illuminate\Http\Request objects passed to Twig, use old() carefully:
      <input value="{{ old('email', form.email.value) }}">
      

Debugging

  • Template Not Found: Ensure .twig files are in resources/views/ or a path listed in config/twig.php['paths']. Check for typos in view names.

  • Undefined Variables: Twig is strict about undefined variables. Use default filter:

    {{ user.name|default('Guest') }}
    
  • Syntax Errors: Twig errors often point to line numbers in the compiled template (not the original .twig file). Check the storage/framework/views directory for compiled files.

Extension Points

  1. Custom Filters: Create a filter for Laravel-specific logic:

    // app/Twig/AppExtension.php
    use Twig\TwigFilterMethod;
    
    class AppExtension extends \Twig\Extension\AbstractExtension
    {
        public function getFilters()
        {
            return [
                new TwigFilterMethod($this, 'laravelRoute', ['is_safe' => ['html']]),
            ];
        }
    
        public function laravelRoute($name, $params = [])
        {
            return route($name, $params);
        }
    }
    

    Register in config/twig.php:

    'extensions' => [
        \App\Twig\AppExtension::class,
    ],
    
  2. Global Variables: Add globals via the service provider:

    public function boot()
    {
        Twig::share('app_name', config('app.name'));
        Twig::share('settings', $this->app->make('App\Services\SettingsService'));
    }
    

    Use in Twig:

    <title>{{ app_name }} - {{ settings.title }}</title>
    
  3. Overriding Default Extensions: Disable built-in extensions (e.g., LaravelExtension) and replace them:

    'extensions' => [
        \App\Twig\CustomLaravelExtension::class,
    ],
    

Performance Tips

  • Precompile Templates: For production, precompile templates to reduce runtime overhead:

    php artisan twig:compile
    
  • Avoid Complex Logic: Offload heavy logic to PHP controllers. Use Twig for presentation only:

    {# Bad: #}
    {% if user.isPremium and user.subscription.active and now < user.subscription.expires %}
      <div>Premium Content</div>
    {% endif %}
    
    {# Good: #}
    {% if user.isPremium %}
      {% include 'premium_content.twig' %}
    {% endif %}
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime