PHPackages                             itjonction/blockcache - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. itjonction/blockcache

ActiveLibrary[Caching](/categories/caching)

itjonction/blockcache
=====================

Block caching for both laravel and vanilla php

1.0.4(1y ago)081[2 issues](https://github.com/IT-JONCTION/blockcache/issues)[4 PRs](https://github.com/IT-JONCTION/blockcache/pulls)proprietaryPHP

Since Jul 31Pushed 1y ago7 watchersCompare

[ Source](https://github.com/IT-JONCTION/blockcache)[ Packagist](https://packagist.org/packages/itjonction/blockcache)[ RSS](/packages/itjonction-blockcache/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (8)Versions (10)Used By (0)

Blockcache
==========

[](#blockcache)

Blockcache is a package for Laravel that provides nested block caching for your view logic.

Laravel Installation
--------------------

[](#laravel-installation)

### Step 2: Service Provider

[](#step-2-service-provider)

For your Laravel app, open `config/app.php` and, within the `providers` array, append:

```
Itjonction\Blockcache\BlockcacheServiceProvider::class
```

This will bootstrap the package into Laravel.

### Step 3: Cache Driver

[](#step-3-cache-driver)

For this package to function properly, you must use a Laravel cache driver that supports tagging (like `Cache::tags('foo')`). Drivers such as Memcached and Redis support this feature.

Check your `.env` file, and ensure that your `CACHE_DRIVER` choice accommodates this requirement:

```
CACHE_DRIVER=memcached
```

> Refer to [Laravel's cache configuration documentation](https://laravel.com/docs/5.2/cache#configuration) if you need any help.

Usage
-----

[](#usage)

### The Basics

[](#the-basics)

With the package now installed, you may use the provided `@cache` Blade directive anywhere in your views, like so:

```
@cache('my-cache-key')

        Hello World

@endcache
```

By surrounding this block of HTML with the `@cache` and `@endcache` directives, you are instructing the package to cache the given HTML. While this example is trivial, you can imagine more complex views with nested caches and lazy-loaded relationship calls triggering additional database queries. After the initial page load that caches the HTML fragment, each subsequent refresh will pull from the cache, preventing additional database queries.

In production, this will cache the HTML fragment indefinitely. For local development, the relevant cache will automatically flush each time you refresh the page, allowing you to update your views and templates without needing to clear the cache manually.

Legacy Templates and Classes
----------------------------

[](#legacy-templates-and-classes)

While this package relies on Laravel classes, Laravel doesn't need to be bootstrapped. To use this library in a non-Laravel template, do the following to use `Blockcache` directly:

```
use Itjonction\Blockcache\General\CacheManager;
use Illuminate\Cache\Repository;
use Illuminate\Redis\RedisManager;
use Illuminate\Cache\RedisStore;
use Illuminate\Foundation\Application;

// Configure Redis connection settings
$config = [
    'default' => [
        'url' => env('REDIS_URL', null),
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],
];

// Create the Redis manager instance
$redisManager = new RedisManager($app, 'predis', ['default' => $config['default']]);

// Create the Redis store instance
$redisStore = new RedisStore($redisManager, 'cache');

// Create the Cache repository instance
$cache = new Repository($redisStore);
$cacheManager = new CacheManager($cache);
if (! $cacheManager->startCache('my-cache-key') ){
    echo "view fragment";
}
$output = $cacheManager->endCache();
```

Alternatively, even in legacy code, you can still bootstrap the Laravel application instance:

```
// php/bootstrap/legacy/laravel.php

require_once __DIR__ . '/../../vendor/autoload.php';

use Illuminate\Cache\CacheManager;
use Illuminate\Container\Container;
use Illuminate\Events\Dispatcher;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Redis\RedisManager;

$container = new Container;

// Set up the event dispatcher
$events = new Dispatcher($container);
$container->instance('events', $events);

// Set up the configuration
$config = new ConfigRepository([
    'app' => require __DIR__ . '/../../config/app.php',
    'cache' => require __DIR__ . '/../../config/legacy/cache.php',
    'database' => require __DIR__ . '/../../config/legacy/database.php',
]);
$container->instance('config', $config);

$files = new Filesystem;
$container->instance('files', $files);

// Set up the Redis manager
$redisConfig = $config->get('database.redis');
$redisManager = new RedisManager($container, $redisConfig['client'], $redisConfig);
$container->instance('redis', $redisManager);

// Set up the Cache manager
$cacheManager = new CacheManager($container);
$container->instance('cache', $cacheManager);

return $container;
```

This allows you to cache any view fragment, regardless of whether it's a Blade template or not.

```
use Itjonction\Blockcache\General\CacheManager;
use Illuminate\Foundation\Application;

$container = require_once __DIR__ . '/../path/to/your/bootstrap/legacy/laravel.php';

// Create the Cache repository instance
$cacheManager = new CacheManager($container->make('cache')->store('redis'));
if (! $cacheManager->startCache('my-cache-key') ){
echo "view fragment";
}
$output = $cacheManager->endCache();
```

Since your production server will cache the fragments indefinitely, add a step to your deployment process to clear the relevant cache:

```
Cache::tags('views')->flush();
```

### Caching Models

[](#caching-models)

While you're free to hard-code any string for the cache key, the true power of Russian-Doll caching comes into play when using a cache invalidation strategy, such as a timestamp-based approach.

Consider the following fragment:

```
@cache($post)

        {{ $post->title }}
        Written By: {{ $post->author->username }}

        {{ $post->body }}

@endcache
```

In this example, we're passing the `$post` object to the `@cache` directive instead of a string. The package will look for a `getCacheKey()` method on the model. To enable this, have your Eloquent model use the `Itjonction\Blockcache\HasCacheKey` trait:

```
use Itjonction\Blockcache\HasCacheKey;

class Post extends Eloquent
{
    use HasCacheKey;
}
```

Alternatively, you may use this trait on a parent class that your Eloquent models extend.

Now, the cache key for this fragment will include the object's `id` and `updated_at` timestamp: `App\Post/1-13241235123`.

> The key is that, because we factor the `updated_at` timestamp into the cache key, whenever you update the post, the cache key will change, effectively busting the cache.

Now, you might render your view like this:

**resources/views/cards/\_card.blade.php**

```
@cache($card)

        {{ $card->title }}

            @foreach ($card->notes as $note)
                @include ('cards/_note')
            @endforeach

@endcache
```

**resources/views/cards/\_note.blade.php**

```
@cache($note)
    {{ $note->body }}
@endcache
```

Notice the Russian-Doll style cascading for our caches; if any note is updated, its individual cache will clear, along with its parent, but any siblings will remain untouched.

Legacy Write-Through Cache:

Because the write through cache relies on an `update_at` field in your database you will need to add that field should it not exist. To keep the `updated_at` field accurate in your legacy project, you can use database triggers. Here's a simple approach:

1. **Create a Database Trigger:**Write a trigger that updates the `updated_at` field on every update operation. This ensures the field is always updated, regardless of where the update originates.
2. **MySQL Trigger Example:**If you're using MySQL, here's a basic example:

    ```
    DELIMITER //

    CREATE TRIGGER update_timestamp
    BEFORE UPDATE ON your_table_name
    FOR EACH ROW
    BEGIN
      SET NEW.updated_at = NOW();
    END//

    DELIMITER ;
    ```
3. **Add Eloquent Configuration:**Ensure your models use the `updated_at` and `created_at` fields correctly. By default, Eloquent expects these fields.

    ```
    class YourModel extends Model
    {
        public $timestamps = true;
    }
    ```
4. **Update Legacy Code:**Gradually refactor your legacy code to use Eloquent for database operations where possible.
5. This will make it easier to manage and maintain the timestamps.
6. **Manual Updates:**For parts of the application that can't be refactored immediately, ensure the `updated_at` field is manually updated in SQL queries.

    ```
    UPDATE your_table_name SET column1 = value1, updated_at = NOW() WHERE condition;
    ```

By using database triggers and gradually refactoring your legacy code, you can ensure the `updated_at` field remains accurate and consistent.

#### Touching

[](#touching)

For this technique to work properly, we need a mechanism to alert parent relationships (and subsequently bust parent caches) each time a model is updated. Here's a basic workflow:

1. Model is updated in the database.
2. Its `updated_at` timestamp is refreshed, triggering a new cache key for the instance.
3. The model "touches" (or pings) its parent.
4. The parent's `updated_at` timestamp is updated, busting its associated cache.
5. Only the affected fragments re-render. All other cached items remain untouched.

Laravel offers this "touch" functionality out of the box. Consider a `Note` object that needs to alert its parent `Card` relationship each time an update occurs.

```
