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

Twig Template Layout Renderer Laravel Package

apie/twig-template-layout-renderer

Twig-based template layout renderer for the Apie ecosystem. Provides a small component to render templates with a layout using Twig, intended for internal use within Apie packages. Source is maintained in the apie-lib monorepo.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require apie/twig-template-layout-renderer
    

    Requires Twig (install via composer require twig/twig).

  2. Basic Registration In your Laravel service provider (e.g., AppServiceProvider):

    use Apie\TwigTemplateLayoutRenderer\TwigLayoutRenderer;
    
    public function register()
    {
        $this->app->singleton(TwigLayoutRenderer::class, function ($app) {
            return new TwigLayoutRenderer($app['twig']);
        });
    }
    
  3. First Use Case Render a Twig template with a layout:

    $renderer = app(TwigLayoutRenderer::class);
    $content = $renderer->render('partials/content.twig', [
        'title' => 'Hello World'
    ]);
    $layout = $renderer->render('layouts/main.twig', [
        'block_content' => $content
    ]);
    

Implementation Patterns

Core Workflow

  1. Template Segmentation Use layouts (layouts/main.twig) to wrap reusable structures (headers, footers, navigation) and partials (partials/*.twig) for modular content.

    {# layouts/main.twig #}
    <!DOCTYPE html>
    <html>
        <head>
            <title>{% block title %}{% endblock %}</title>
        </head>
        <body>
            {% block content %}{% endblock %}
        </body>
    </html>
    
  2. Dynamic Block Injection Pass rendered partials as block variables:

    $content = $renderer->render('partials/dashboard.twig', ['stats' => $statsData]);
    $layout = $renderer->render('layouts/dashboard.twig', [
        'block_content' => $content,
        'block_sidebar' => $renderer->render('partials/sidebar.twig')
    ]);
    
  3. Integration with Laravel Views Extend Laravel’s view system by creating a custom View facade:

    // app/Providers/AppServiceProvider.php
    View::macro('renderLayout', function ($layout, $data = []) {
        return app(TwigLayoutRenderer::class)->render($layout, $data);
    });
    

    Usage:

    return View::renderLayout('layouts/app.twig', [
        'block_header' => $renderer->render('partials/header.twig')
    ]);
    
  4. API Response Rendering Combine with Laravel’s Response for API-driven templates:

    return response($renderer->render('emails/welcome.twig', $data))
        ->header('Content-Type', 'text/html');
    

Advanced Patterns

  1. Template Inheritance Leverage Twig’s native extends and blocks for nested layouts:

    {# child.twig #}
    {% extends 'layouts/base.twig' %}
    {% block body %}
        <h1>{{ title }}</h1>
        {{ parent() }} {# Inherit parent block content #}
    {% endblock %}
    
  2. Dynamic Layout Selection Use a factory pattern to switch layouts based on context:

    $layoutRenderer = new TwigLayoutRenderer($twig);
    $layout = $layoutRenderer->render(
        $user->preferredLayout ?: 'layouts/default.twig',
        $data
    );
    
  3. Caching Rendered Layouts Cache rendered layouts for performance:

    $cacheKey = 'layout_' . md5(serialize($data));
    $layout = Cache::remember($cacheKey, now()->addHours(1), function () use ($renderer, $data) {
        return $renderer->render('layouts/main.twig', $data);
    });
    
  4. Error Handling Wrap rendering in try-catch blocks to handle template errors gracefully:

    try {
        $layout = $renderer->render('layouts/error.twig', ['error' => $e]);
    } catch (\Twig\Error\LoaderError $e) {
        return response('Template not found', 500);
    }
    

Gotchas and Tips

Common Pitfalls

  1. Block Name Collisions Ensure block names in partials match those in layouts exactly (case-sensitive). Example:

    {# Layout #}
    {% block content %}{% endblock %}
    {# Partial #}
    {% block content %} <!-- Must match -->
        {{ partialContent }}
    {% endblock %}
    
  2. Circular Dependencies Avoid layouts that extend other layouts recursively (e.g., A.twig extends B.twig, which extends A.twig). Twig will throw a LoaderError.

  3. Missing extends in Partials Partials should not use extends; they are meant to be injected into layouts. Doing so will cause Twig to ignore the layout’s blocks.

  4. Twig Environment Configuration Ensure your Twig environment is properly configured (e.g., paths, debug mode) before using the renderer:

    $twig = new \Twig\Environment($loader, [
        'cache' => storage_path('framework/views'),
        'debug' => config('app.debug'),
    ]);
    

Debugging Tips

  1. Enable Twig Debug Mode Set 'debug' => true in your Twig environment to get detailed error messages and template line numbers.

  2. Check Template Paths Verify paths in your Twig\Loader\FilesystemLoader are correct. Use absolute paths if needed:

    $loader = new \Twig\Loader\FilesystemLoader([
        resource_path('views'),
        base_path('vendor/apie/layouts') // Example: Custom vendor layouts
    ]);
    
  3. Inspect Rendered Output Use var_dump() or dd() to debug block variables:

    $data = [
        'block_content' => $renderer->render('partials/debug.twig', ['var' => $var])
    ];
    
  4. Log Template Errors Catch and log Twig errors to track issues:

    try {
        $renderer->render('layouts/main.twig', $data);
    } catch (\Twig\Error\Error $e) {
        \Log::error('Twig Error: ' . $e->getMessage() . ' in ' . $e->getTemplateLine());
    }
    

Extension Points

  1. Custom Block Strategies Extend the renderer to support custom block logic (e.g., merging blocks with defaults):

    class CustomTwigLayoutRenderer extends TwigLayoutRenderer {
        protected function mergeBlocks(array $blocks, array $data): array
        {
            // Custom logic here
            return parent::mergeBlocks($blocks, $data);
        }
    }
    
  2. Pre/Post-Render Hooks Add hooks to modify data before rendering or process output afterward:

    $renderer->addPreRenderHook(function ($template, $data) {
        $data['global_var'] = 'value'; // Inject global data
        return $data;
    });
    
  3. Integration with Laravel Mix Use Laravel Mix to compile Twig templates into static assets for production:

    // mix.js
    mix.copy('resources/views', 'public/views');
    

    Then configure Twig to load from public/views in production.

  4. Support for Alternative Template Engines While this package is Twig-specific, you could abstract the renderer to support other engines (e.g., Blade) by implementing a common interface:

    interface TemplateRendererInterface {
        public function render(string $template, array $data);
    }
    
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.
babenkoivan/elastic-client
innmind/static-analysis
innmind/coding-standard
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php