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

Doctrine Adapter Laravel Package

cache/doctrine-adapter

PSR-6 cache pool adapter backed by Doctrine Cache. Wraps Doctrine cache drivers (e.g., MemcachedCache) in a standards-compliant PSR-6 CacheItemPool for easy integration with php-cache features like tagging and hierarchy support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require cache/doctrine-adapter doctrine/cache
    
    • Ensure doctrine/cache is installed (required dependency).
  2. Configure Laravel Cache Driver: Add the Doctrine adapter to config/cache.php:

    'doctrine_memcached' => [
        'driver' => 'doctrine',
        'key'    => env('CACHE_DOCTRINE_KEY', 'default'),
        'store'  => \Cache\Adapter\Doctrine\DoctrineCachePool::class,
        'options' => [
            'doctrine_cache' => new \Doctrine\Common\Cache\MemcachedCache(
                new \Memcached(),
                // Optional: Configure Memcached connection
                ['host' => 'localhost', 'port' => 11211]
            ),
        ],
    ],
    
  3. First Use Case: Use the cache in a Laravel controller or service:

    use Illuminate\Support\Facades\Cache;
    
    // Store with tags
    Cache::tags(['users', 'profiles'])->put('user:1', $userData, now()->addHours(1));
    
    // Retrieve
    $userData = Cache::tags(['users'])->get('user:1');
    
    // Invalidate by tag
    Cache::forgetTags(['users']);
    
  4. Verify Integration:

    • Test tag-based invalidation with Cache::forgetTags().
    • Check key serialization (ensure no {}()/@:` characters are used).

Implementation Patterns

Usage Patterns

1. Basic CRUD Operations

// Store
Cache::put('key', $value, $ttl);

// Retrieve
$value = Cache::get('key');

// Delete
Cache::forget('key');

2. Tag-Based Caching

// Store with tags
Cache::tags(['products', 'electronics'])->put('product:101', $product, now()->addMinutes(30));

// Bulk invalidation
Cache::forgetTags(['products']); // Clears all tagged items

3. Hierarchical Caching (Advanced)

If using Doctrine’s hierarchical cache providers (e.g., ApcuCache + RedisCache), configure the adapter to leverage multiple layers:

$hierarchicalCache = new \Doctrine\Common\Cache\HierarchicalCache(
    new \Doctrine\Common\Cache\ApcuCache(),
    new \Doctrine\Common\Cache\RedisCache()
);
$pool = new DoctrineCachePool($hierarchicalCache);

4. Integration with Laravel Queues

Use the cache in queued jobs or commands:

Cache::put('job:result:123', $result, now()->addMinutes(5));

5. Cache Middleware

Leverage Laravel’s CacheResponseMiddleware for HTTP caching:

Route::middleware(['throttle:60', 'cache.headers'])->group(function () {
    // Routes cached with headers
});

Workflows

Cache Invalidation Workflow

  1. Trigger: Update an Eloquent model (e.g., User).
  2. Invalidate: Clear tags associated with the model:
    $user->save(); // Triggers observers/events
    Cache::forgetTags(['users']); // Invalidate all user-related caches
    
  3. Fallback: Use Cache::remember() to repopulate caches on next request.

Key Management Workflow

  1. Sanitize Keys: Ensure keys comply with PSR-6 (no {}()/@:`):
    $sanitizedKey = Str::of($key)->replaceMatched('/[{}()\/\\@:]/', '');
    Cache::put($sanitizedKey, $value);
    
  2. Prefix Keys: Use a consistent prefix (e.g., app:) to avoid collisions:
    Cache::tags(['app:users'])->put('app:user:1', $data);
    

Debugging Workflow

  1. Log Cache Hits/Misses:
    $item = Cache::store('doctrine_memcached')->getItem('key');
    logger()->debug('Cache hit', ['key' => $key, 'hit' => $item->isHit()]);
    
  2. Inspect Doctrine Cache Stats:
    $doctrineCache = Cache::store('doctrine_memcached')->getStore();
    if ($doctrineCache instanceof DoctrineCachePool) {
        $stats = $doctrineCache->getDoctrineCache()->getStats();
        logger()->debug('Doctrine Cache Stats', $stats);
    }
    

Integration Tips

1. Laravel Service Provider

Register the cache driver in a service provider:

use Cache\Adapter\Doctrine\DoctrineCachePool;
use Doctrine\Common\Cache\MemcachedCache;

public function register()
{
    $memcached = new \Memcached();
    $memcached->addServer('localhost', 11211);

    $this->app->bind('doctrine.cache', function () {
        return new DoctrineCachePool(new MemcachedCache($memcached));
    });
}

2. Dynamic Configuration

Load cache configuration from environment variables:

'doctrine_redis' => [
    'driver' => 'doctrine',
    'key' => env('CACHE_DOCTRINE_KEY'),
    'store' => DoctrineCachePool::class,
    'options' => [
        'doctrine_cache' => new \Doctrine\Common\Cache\RedisCache(
            new \Redis(),
            ['prefix' => env('CACHE_REDIS_PREFIX', 'doctrine_')]
        ),
    ],
],

3. Fallback Strategy

Implement a fallback to the file driver if the Doctrine cache fails:

try {
    return Cache::store('doctrine_memcached')->get($key);
} catch (\Exception $e) {
    return Cache::store('file')->get($key);
}

4. Testing

Use Laravel’s Cache facade in tests with a mock Doctrine cache:

use Doctrine\Common\Cache\ArrayCache;

$mockCache = new DoctrineCachePool(new ArrayCache());
Cache::shouldReceive('store')->andReturn(new CacheManager([
    'doctrine' => $mockCache,
]));

Gotchas and Tips

Pitfalls

1. Key Validation Errors

  • Issue: PSR-6 keys cannot contain {}()/@:`. Laravel’s Eloquent or custom key generation might include these.
  • Fix: Sanitize keys before storage:
    $key = Str::of($originalKey)->replaceMatched('/[{}()\/\\@:]/', '_');
    Cache::put($key, $value);
    
  • Tip: Use a consistent prefix (e.g., app:) to avoid collisions and simplify sanitization.

2. Tagging Mismatches

  • Issue: Doctrine’s tagging implementation may not fully align with Laravel’s Cache::tags() behavior (e.g., wildcard support).
  • Fix: Test tag-based invalidation thoroughly:
    Cache::tags(['users', 'admins'])->put('user:1', $data);
    Cache::forgetTags(['users']); // Should clear 'user:1' but not 'admin:1'
    
  • Tip: Avoid relying on advanced tag features (e.g., nested tags) unless documented.

3. Performance Overhead

  • Issue: The adapter adds a thin abstraction layer, which may introduce minor latency.
  • Fix: Benchmark against native drivers (e.g., memcached vs. doctrine_memcached):
    php artisan cache:clear
    # Run load tests and compare response times
    
  • Tip: Use Cache::remember() to minimize redundant operations.

4. Stale Releases

  • Issue: Last release was in 2022; no active maintenance.
  • Fix:
    • Fork the repository if critical bugs arise.
    • Monitor the PHP-Cache organization for updates.
    • Pin versions in composer.json:
      "cache/doctrine-adapter": "1.2.0",
      "doctrine/cache": "1.11.0"
      

5. Dependency Conflicts

  • Issue: Conflicts with other Doctrine packages (e.g., doctrine/dbal, doctrine/orm).
  • Fix: Use composer why-not to resolve version conflicts:
    composer why-not doctrine/cache
    
  • Tip: Explicitly require doctrine/cache to avoid version skew.

Debugging Tips

1. Enable Debug Logging

Configure

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.
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle
dmstr/api-platform-utils-bundle
dmstr/api-configuration-bundle
chrisdev/ux-components
baks-dev/finances
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle