Working with Laravel config:cache

Laravel provides a static cache utility via Artisan to collapse configuration under config/ into a single file to boost performance. Configuration may be cached using:

php artisan config:cache

When run from terminal, the paths provided may be incorrectly referenced when the application is accessed from the web resulting in application errors.

Solution

Overwrite bootstrap/app.php to use a custom loader. We’ll override a couple methods to bypass cache in CLI SAPI mode (php artisan xx:yy) and opportunistically regenerate the cache whenever remote changes are pushed upstream via git.

Replacing bootstrapper

Create a new file called ApplicationWrapper.php in app/ to provide additional functionality to Illuminate\Foundation\Application:

<?php
namespace App;

use Illuminate\Foundation\Application;

class ApplicationWrapper extends Application {

    public function __construct($basePath)
    {
        if (!isset($_SERVER['SITE_ROOT'])) {
            $_SERVER['SITE_ROOT'] = '';
        }
        parent::__construct($basePath);
    }

   /**
    * Fake configuration cache response for CLI
    * as paths will always be different
    * 
    * @return bool
    */
    public function configurationIsCached() {
        if ($this->runningInConsole()) {
            return false;
        }
        return parent::configurationIsCached();
    }

   /**
    * Emulate \Illuminate\Foundation\Console\ConfigCache\fire()
    *
    * @return bool
    */
    public function doCache() {
       if (!$this->runningInConsole()) {
           $config = $this->app['config']->all();
           $this->files->put(
               $this->getCachedConfigPath(), '<?php return '.var_export($config, true).';'.PHP_EOL
           );
       }
        return true;
    }

    /*
     * Override boot to register production config cache
     * @return boolean
     */
    public function boot()
    {
        parent::boot();
        if ($this->environment() !== "production") {
           return;
        }
        if (!$this->runningInConsole()) {
            $app = $this->app;
            $this->terminating(function() use ($app) {
                $app->configurationIsCached() || $app->doCache();
            });
        } else {
           $path = parent::getCachedConfigPath();
           $this->terminating(function() use ($path) {
              file_exists($path) && unlink($path);
           });
        }

    }
}

A couple notes:

  1. Cache is done post-boot so that configuration is properly loaded. Caching is done once at the end of the request to reduce overhead.
  2. APP_ENV mode is assumed to be “production”; this is controlled by .env.
  3. artisan config:cache will create, then immediately unlink config.php in favor of generation by the web server

Next, adjust bootstrap/app.php to instantiate a new ApplicationWrapper instance rather than Illuminate\Foundation\Application:

Change:

$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

to

$app = new App\ApplicationWrapper(
    realpath(__DIR__.'/../')
);

And that’s it! Run php artisan config:clear to have it automatically regenerate during the next page request.

Regenerating Cache with git

Next, create a post-receive hook in your git repository on the server. Create hooks/post-receive if it does not already exist with the following content:

#!/bin/sh
LIVE="/var/www/"

read oldrev newrev refname
if [[ $refname = "refs/heads/master" ]]; then 
    echo "===== DEPLOYING TO LIVE SITE =====" 
    unset GIT_DIR
    cd $LIVE
    ./build.sh
    echo "===== DONE ====="
fi

And build.sh is a shell script run after every successful git push commit. The following script assumes your Laravel app path is /var/www/laravel-directory and git repository /var/www/git-repository

#!/bin/sh
pushd /var/www/laravel-directory
git pull /var/www/git-repository
# Recompile all class defs into a monolithic file
php artisan optimize --force
php artisan config:clear

Now the next git push will automatically deploy, generate a class loader, and recompile site configuration:

$ git push
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 440 bytes | 0 bytes/s, done.
Total 5 (delta 4), reused 0 (delta 0)
remote: ===== DEPLOYING TO LIVE SITE =====
remote: /var/www/laravel-production /var/www
remote: From ./../git
remote: * branch HEAD -> FETCH_HEAD
remote: Updating b7b99b8..d4f04a5
remote: Fast-forward
remote: config/filesystems.php | 4 ++--
remote: config/view.php | 4 ++--
remote: 2 files changed, 4 insertions(+), 4 deletions(-)
remote: Generating optimized class loader
remote: Compiling common classes
remote: Configuration cache cleared!
remote: ===== DONE =====
To ssh://hostineer#hostineer.com@luna.hostineer.com/var/www/git
 b7b99b8..d4f04a5 master -> master

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.