Laravel Automatic Caching Tutorial: Building a Robust Automated System

Integrate GitHub Actions with Laravel to improve app performance through automated Eloquent query caching.

Laravel Automatic Caching Tutorial: Building a Robust Automated System

As a developer working on large Laravel applications, you’ve probably encountered the performance hit that comes with frequent database queries. Eager loading and caching can only do so much to mitigate this issue. At some point, you may have found yourself manually implementing query caching for specific models or even worse, resorting to using third-party libraries with limited flexibility.

You’ll build a robust automated caching system for your Laravel application by the end of this tutorial. Specifically, you’ll learn how to integrate GitHub Actions to automate Eloquent query caching and create a custom cache key resolver. With these tools in hand, you’ll be able to optimize your application’s performance without sacrificing maintainability or ease of use.

Setting Up GitHub Actions for Laravel

To automate Eloquent query caching with GitHub Actions, you’ll first need to set up a basic workflow for your Laravel project. This will involve creating a new file in the .github/workflows directory of your repository.

Create a new file called laravel.yml (or any other name that makes sense for your project) within this directory:

name: Laravel Workflow

on:
  push:
    branches: [main]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install dependencies
        run: |
          composer install --no-dev --optimize-autoloader
      - name: Copy .env file
        run: |
          cp .env .github/workflows/.env

This workflow will trigger on push events to the main branch, install dependencies, and copy the .env file into the workflow directory.

In your project’s root directory, create a new file called .github/workflows/caching.yml. This file will contain the specific actions for automating Eloquent query caching:

name: Laravel Query Caching

on:
  push:
    branches: [main]

jobs:
  cache-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install dependencies
        run: |
          composer install --no-dev --optimize-autoloader

Note that we’re setting up the basic workflow for our project. In the next section, we’ll configure Eloquent query caching in Laravel.

Configuring Eloquent Query Caching in Laravel

To enable Eloquent query caching, we need to configure it through Laravel’s cache configuration file. Open your project’s config/cache.php file and locate the cache' => [] array.

// config/cache.php
return [
    // ... other configurations ...
    'connections' => [
        'default' => [
            'driver' => 'file',
            'key' => env('CACHE_KEY', 'some-key'),
            'store_hours' => 120,
        ],
    ],
];

In the cache configuration, we’re setting up a file-based cache store. You can adjust this to use other cache drivers like Redis or Memcached if your project requires it.

Next, we need to enable query caching for Eloquent. Open your config/database.php file and locate the query_log' => true line.

// config/database.php
return [
    // ... other configurations ...
    'query_log' => true,
];

By setting this to true, we’re enabling query logging, which will store executed queries in our database. This allows Eloquent to cache frequently accessed queries and reduce the load on your database.

With these changes, Eloquent is now configured for query caching. However, we still need to automate the caching process using GitHub Actions. In the next section, we’ll create a cache key resolver using Laravel’s service container to automatically generate unique cache keys for our queries.

Creating a Cache Key Resolver using Laravel’s Service Container

To automate Eloquent query caching with GitHub Actions, we need a way to determine cache keys for our database queries. We can leverage Laravel’s service container to create a cache key resolver that generates unique cache keys based on the query parameters.

First, let’s create a new class CacheKeyResolver.php in the app/Services directory:

// app/Services/CacheKeyResolver.php

namespace App\Services;

use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Request;

class CacheKeyResolver
{
    public function resolve(Request $request): string
    {
        // Generate a unique cache key based on the query parameters
        $cacheKey = md5(json_encode([
            $request->method,
            $request->url,
            json_encode($request->all()),
        ]));

        return 'eloquent:' . Hash::make($cacheKey);
    }
}

This class uses Laravel’s Request facade to extract the query parameters and generates a unique cache key using the md5 function.

Next, let’s register the CacheKeyResolver service in the Laravel container:

// app/Providers/AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Config;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // Register the CacheKeyResolver service
        Config::set('cache.key_resolver', 'App\Services\CacheKeyResolver');
    }

    // ...
}

We’ll configure Laravel to use this cache key resolver in the next section.

Automating Eloquent Query Caching with GitHub Actions

Setting up a GitHub Action for Eloquent Query Caching

In the previous sections, we’ve set up Eloquent query caching and created a cache key resolver using Laravel’s service container. Now, let’s automate this process by creating a GitHub Action that runs whenever our code changes.

First, create a new file in your repository’s .github/workflows directory: cache-queries.yml. This is where we’ll define the workflow for automating Eloquent query caching.

name: Cache Queries

on:
  push:
    branches:
      - main
    paths:
      - app/Models/**
      - database/seeds/**
      - database/migrations/**
      - routes/**
      - app/Providers**

jobs:
  cache-queries:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install dependencies
        run: |
          composer install --no-dev

      - name: Cache queries using Artisan command
        run: |
          php artisan cache:query --force

This workflow listens for changes on specific files and directories, installs dependencies, and then runs the cache:query Artisan command with the --force option. This will rebuild and cache all Eloquent queries.

Note that we’re running this job on every push to the main branch, but you can adjust the on trigger according to your project’s needs.

This concludes our tutorial on automating Eloquent query caching with GitHub Actions. By following these steps, you’ll have a robust system for automatically rebuilding and caching database queries whenever code changes are pushed to your repository.

Testing the Automated Caching Setup

Now that we have our automated caching setup in place, it’s essential to verify its correctness and performance. Let’s create a test suite to validate our implementation.

Firstly, let’s update our tests/Unit/Models/UserTest.php file with some test cases:

use Tests\TestCase;
use App\Models\User;

class UserTest extends TestCase
{
    public function test_caching_query()
    {
        $user = User::where('email', 'john.doe@example.com')->first();
        
        // Assert that the query was cached
        $this->assertNotNull($user);
        $this->assertTrue(cache()->has(User::$cacheKey));
        
        // Update the user to trigger cache update
        $user->update(['name' => 'John Doe Updated']);
        
        // Assert that the updated query is not retrieved from cache
        $updatedUser = User::where('email', 'john.doe@example.com')->first();
        $this->assertNotEquals($user, $updatedUser);
    }
}

We’ll also need to add a test for the cache key resolver. Since we’re using Laravel’s service container, we can create a test case for it in tests/Unit/Services/CachingServiceTest.php:

use Tests\TestCase;
use App\Services\CachingService;

class CachingServiceTest extends TestCase
{
    public function test_resolve_cache_key()
    {
        $cachingService = app(CachingService::class);
        
        // Assert that the cache key is correctly resolved
        $cacheKey = 'user:1';
        $this->assertEquals($cacheKey, $cachingService->resolveCacheKey(User::$cacheKey));
    }
}

These test cases will ensure our automated caching setup is working as expected.

Integrating Dependabot to Keep Dependencies Up-to-Date

Now that our automated caching setup is in place, let’s ensure our dependencies remain up-to-date. This is crucial for maintaining security and stability in our project.

First, we need to install the Dependabot package using Composer:

composer require --dev dependabot/dependabot-cli

Next, configure the dependabot.yml file by running the following command:

vendor/bin/dependabot config init

This will create a basic configuration for our project. We need to update this file to include our repository information and specify the packages we want Dependabot to monitor.

Here’s an example of what the dependabot.yml file might look like:

version: 2
updates:
  package-ecosystem: composer
repos:
  laravel-notification-channels/socialite:
    github-repo: socialite-php/socialite

This configuration tells Dependabot to monitor our Composer dependencies and updates for the socialite package.

Finally, we need to configure GitHub Actions to run the Dependabot workflow on each push event. Add the following YAML snippet to your .github/workflows/dependabot.yml file:

name: Dependabot

on:
  push:
    branches: [ main ]

jobs:
  dependabot:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install dependencies
        run: composer install --no-dev
      - name: Run Dependabot
        run: vendor/bin/dependabot update

This will ensure that our dependencies are updated automatically whenever changes are pushed to the main branch. With this setup, we can focus on developing and testing our application, knowing that our dependencies are always up-to-date.

By following these steps, we’ve integrated Dependabot into our workflow, ensuring our project’s dependencies remain secure and stable.

Monitoring and Debugging the Automated Caching Process

Now that we have automated Eloquent query caching with GitHub Actions, it’s essential to monitor and debug the process to ensure everything works as expected.

To monitor the automated caching process, you can use Laravel’s built-in logging features. In your config/logging.php file, update the stacks array to include a new stack for GitHub Actions:

'github-actions' => [
    'driver' => 'single',
    'handler' => [
        'class' => \Monolog\Handler\RotatingFileHandler::class,
        'level' => env('LOG_LEVEL', 'debug'),
        'path' => storage_path('logs/github-actions.log'),
        'max_files' => 7,
        'days' => 3,
    ],
],

Then, in your app/Providers/AppServiceProvider.php file, add the following code to enable logging for GitHub Actions:

use Monolog\Logger;
// ...

public function boot()
{
    // ...
    $logger = new Logger('github-actions');
    $logger->pushProcessor(new ContextProcessor(['action' => 'cached']));
    $logger->pushHandler(new RotatingFileHandler(storage_path('logs/github-actions.log')));
}

To debug issues with automated caching, you can check the GitHub Actions logs for errors or exceptions. You can also use Laravel’s built-in artisan command to clear and re-cache your application:

php artisan cache:clear && php artisan cache:rebuild

This will reset the cache and rebuild it from scratch, allowing you to troubleshoot any caching-related issues.

With these tools in place, you’ll be well-equipped to monitor and debug the automated caching process.

Frequently Asked Questions

How do I automate Eloquent query caching using GitHub Actions?

To automate Eloquent query caching, you’ll need to create a new workflow file in the .github/workflows directory of your repository and add specific actions for caching.

What is the purpose of creating two separate workflow files (laravel.yml and caching.yml)?

The first workflow file sets up the basic build process, while the second workflow file contains the specific actions for automating Eloquent query caching.

How do I configure Eloquent query caching in Laravel’s cache configuration file?

You’ll need to open your project’s config/cache.php file and locate the cache' => [] array, where you can adjust the cache driver and settings as needed.

Can I use a different cache driver like Redis or Memcached instead of the default file-based cache store?

Yes, you can adjust the cache configuration to use other drivers like Redis or Memcached if your project requires it.

Comments

comments