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

Cache Extra Laravel Package

twig/cache-extra

Twig extension integrating Symfony Cache to cache template fragments. Adds a single cache tag for easy fragment caching in Twig views, improving performance with configurable cache backends via the Symfony Cache component.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install Dependencies:

    composer require twig/cache-extra symfony/cache symfony/cache-common
    
    • twig/cache-extra: Core package.
    • symfony/cache: Required for CacheInterface.
    • symfony/cache-common: Common cache utilities (e.g., adapters).
  2. Configure Symfony Cache Adapter: In config/cache.php, extend Laravel’s cache config to include Symfony adapters:

    'adapters' => [
        'symfony_redis' => [
            'driver' => 'redis',
            'connection' => 'cache',
            'adapter' => \Symfony\Component\Cache\Adapter\RedisAdapter::class,
        ],
    ],
    
  3. Register Twig Extension: In AppServiceProvider::boot():

    $twig = $this->app['view']->getEngine();
    $twig->addExtension(new \Twig\Extension\CacheExtension(
        $this->app->make(\Symfony\Component\Cache\CacheInterface::class)
    ));
    
  4. First Cache Usage: In a Twig template (e.g., resources/views/partials/header.twig):

    {% cache 'header_fragment_v1' %}
        <header>
            {{ include('nav') }}
            {{ include('promo_banner') }}
        </header>
    {% endcache %}
    
    • Key: Must be unique per fragment (e.g., include version or context).
    • Output: Check storage/framework/cache/data/ for generated files.
  5. Verify Cache Hit:

    • Clear cache: php artisan cache:clear.
    • Refresh the page twice. Second load should be faster (cache hit).

Implementation Patterns

1. Laravel-Centric Integration

Symfony Cache ↔ Laravel Cache Bridge

  • Use a single Redis/APCu adapter for both stacks to avoid duplication:
    // config/cache.php
    'adapters' => [
        'shared' => [
            'driver' => 'redis',
            'connection' => 'cache',
            'adapter' => \Symfony\Component\Cache\Adapter\RedisAdapter::class,
            'laravel_alias' => 'symfony_redis', // Link to Laravel's cache
        ],
    ],
    
  • Bind Symfony Cache to Laravel’s cache manager:
    $this->app->singleton(\Symfony\Component\Cache\CacheInterface::class, function ($app) {
        return new \Symfony\Component\Cache\Adapter\RedisAdapter(
            $app['redis']->connection('cache')
        );
    });
    

Cache Tag Invalidation Sync

  • Listen to Laravel’s CacheTagsPruned event to invalidate Symfony Cache:
    use Symfony\Component\Cache\CacheItem;
    
    Cache::tags(['products'])->flush();
    // Invalidate Symfony Cache for tagged items:
    $symfonyCache = app(\Symfony\Component\Cache\CacheInterface::class);
    $symfonyCache->deleteItem('products:*'); // Wildcard or specific keys.
    

2. Template Patterns

A. Dynamic Fragment Caching

  • Cache fragments with runtime-generated keys:
    {% cache 'user_feed_' ~ user.id ~ '_' ~ current_page %}
        {{ render_feed(user, current_page) }}
    {% endcache %}
    
  • Use Case: Paginated user feeds, personalized dashboards.

B. Conditional Caching

  • Cache only when conditions are met:
    {% if is_logged_in %}
        {% cache 'user_prefs_' ~ user.id %}
            {{ render_preferences() }}
        {% endcache %}
    {% endif %}
    
  • Use Case: Avoid caching public content for anonymous users.

C. Nested Caching

  • Combine with Laravel’s @cache for hybrid caching:
    {% cache 'sidebar' %}
        @cache(['key' => 'sidebar_items', 'tags' => ['sidebar']])
            {{ render_sidebar_items() }}
        @endcache
    {% endcache %}
    
  • Note: Avoid nesting to prevent cache stampedes.

D. Cache with TTL

  • Set time-to-live (TTL) for fragments:
    {% cache 'homepage_hero' with {'ttl' => 3600} %}
        {{ render_hero() }}
    {% endcache %}
    
  • Default TTL: 0 (no expiration). Set in Symfony Cache adapter config.

3. Advanced Patterns

A. Cache Warming

  • Pre-load critical fragments during low-traffic periods:
    // app/Console/Commands/WarmCache.php
    use Symfony\Component\Cache\CacheItem;
    
    public function handle()
    {
        $cache = app(\Symfony\Component\Cache\CacheInterface::class);
        $cache->get('homepage_header', function (CacheItem $item) {
            $item->expiresAfter(3600);
            return view('partials.header')->render();
        });
    }
    
  • Schedule with Laravel’s scheduler:
    $schedule->command('cache:warm')->dailyAt('2:00');
    

B. Cache Versioning

  • Append version to keys to force refreshes:
    {% cache 'product_' ~ product.id ~ '_v' ~ config('app.cache_version') %}
        {{ render_product(product) }}
    {% endcache %}
    
  • Use Case: Deployments where template changes require cache invalidation.

C. Fallback Logic

  • Provide fallback content if cache fails:
    {% cache 'fallback_example' %}
        {{ render_expensive_operation() }}
    {% else %}
        {{ include('fallback_content') }}
    {% endcache %}
    

4. Laravel-Specific Tips

A. Blade-to-Twig Migration

  • Replace Blade’s @cache with Twig syntax:
    Blade Twig
    @cache(['key' => 'x']) ... @endcache {% cache 'x' %} ... {% endcache %}
    @cache(['tags' => ['y']]) ... @endcache {% cache 'y:*' %} ... {% endcache %}

B. Cache Driver Aliasing

  • Alias Symfony Cache to Laravel’s cache facade for consistency:
    // config/app.php
    'aliases' => [
        'SymfonyCache' => \Symfony\Component\Cache\CacheInterface::class,
    ],
    
  • Use in templates:
    {% cache 'key' %}
        {{ SymfonyCache.get('key', function() { return 'fallback'; }) }}
    {% endcache %}
    

C. Testing Cached Fragments

  • Mock Symfony Cache in tests:
    $cache = Mockery::mock(\Symfony\Component\Cache\CacheInterface::class);
    $cache->shouldReceive('get')
          ->once()
          ->andReturnUsing(function ($key, $callback) {
              return $callback(new CacheItem());
          });
    
    $this->app->instance(\Symfony\Component\Cache\CacheInterface::class, $cache);
    

Gotchas and Tips

Pitfalls

  1. Key Collisions:

    • Issue: Duplicate keys (e.g., 'header' vs. 'header_v1') cause cache stampedes.
    • Fix: Always include version/context in keys (e.g., 'header_v1_' ~ locale).
  2. Symfony Cache vs. Laravel Cache Conflicts:

    • Issue: Two cache layers may invalidate each other’s data.
    • Fix: Use a single adapter (e.g., Redis) for both stacks. Avoid mixing file/database drivers.
  3. TTL Misconfiguration:

    • Issue: Default TTL (0) means cache never expires, leading to stale data.
    • Fix: Set TTL in adapter config or template:
      {% cache 'key' with {'ttl' => 300} %} ... {% endcache %}
      
  4. Blade Template Cache Interference:

    • Issue: Laravel’s Blade cache (bootstrap/cache/) may conflict with Twig cache.
    • Fix: Exclude Twig cache directories from Laravel’s cache clearing:
      // app/Console/Kernel.php
      protected function commands()
      {
          $this->commands([
              \Illuminate\Cache\Console\ClearCacheCommand::class,
          ]);
          // Override clear command to skip Twig cache:
          $this->app['command.cache.clear']->setCachePaths([
              storage_path('framework/cache/data'),
              // Exclude: storage_path('framework/cache/twig/'),
          ]);
      }
      
  5. Cache Tag Invalidation Race Conditions:

    • Issue: Laravel’s CacheTagsPruned event may not sync with Symfony Cache.
    • Fix: Implement a queue job for invalidation:
      Cache::tags(['products'])->flush();
      CacheInvalidationJob::dispatch
      
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope