Deploy to Heroku buttons with Laravel

I submitted Cachet to Reddit earlier yesterday morning and had great feedback from it all! It's been great! I'm happy to see that people like the idea and that it's useful to people.

One of the first issues submitted was adding a Deploy to Heroku button. I was a bit apprehensive about this at first because I've never used it and expected it to be quite cumbersome, but it's something I've been meaning to take a look at, so it's as good as an excuse as any!

It turns out that it's really easy to make it work with PHP, and more specifically Laravel in this case too! This blog post is going to be a quick walkthrough as to how I got Cachet setup with the Deploy to Heroku button.

Heroku deployment

Before we can begin, we need to setup our Laravel project with some extra configurations, so that it knows how to behave when deployed to Heroku.

Within bootstrap/start.php file, we need to change how Laravel detects the environment. Later on, we'll set an environment variable up so that we know to use Heroku:

$env = $app->detectEnvironment(function() {
    // Take care of Heroku deployment for us.
    if ($envName = getenv('ENV')) {
        return $envName;
    }

    // Always fall back to local.
    return 'local';
});

We could do another check after the condition for ENV so that it doesn't always use local as an environment, but this will do for now if we're only developing locally or deploying to Heroku.

Re-configure database

Let's create a new directory /app/config/heroku, the bootstrap changes above mean that on Heroku, Laravel will use any configurations within that directory.

Inside the directory we create database.php with this content:

<?php

    $dbURL = parse_url(getenv('CLEARDB_DATABASE_URL'));
    $dbName = substr($dbURL["path"], 1);

    return array(
        'default' => 'cleardb',
        'connections' => array(
            'cleardb' => array(
                'driver'    => 'mysql',
                'host'      => $dbURL['host'],
                'database'  => $dbName,
                'username'  => $dbURL['user'],
                'password'  => $dbURL['pass'],
                'charset'   => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix'    => '',
            ),
        )
    );

Breaking it down:

  1. ClearDB will create an environment variable for us named CLEARDB_DATABASE_URL which we split into multiple parts for the connection string.
  2. We change the default database connection to the one we're about to create.
  3. Now we need to add the cleardb configuration to the connections array. We use the results from step 1 to make a new connection.

Create the manifest file

For Heroku to know what application we're deploying, we need a manifest file. In this case, the manifest that Heroku uses is an app.json file in the root of your repository.

Let's break down the important parts of Cachet's manifest file:

{
    "name": "Cachet",
    "description": "Single-site Status Page with Laravel",
    "website": "http://james-brooks.uk/cachet",
    "repository": "https://github.com/jbrooksuk/Cachet",
    "keywords": ["cachet", "laravel", "status", "page"],
    "addons": ["cleardb"],
    "env": {
        "ENV": "heroku",
        "APP_NAME": "My Status Page"
    },
    "scripts": {
        "postdeploy": "php artisan migrate"
    }
}

The name, description, website, repository and keywords are all self-explanatory, but for more information you can check out the Heroku schema reference.

Addons

Following on from the database configuration we setup, we need to tell Heroku that we want a database addon. ClearDB offers a free basic database that we can use, so we want it added to our app once it's setup.

Env

Earlier we added a condition in boostrap/start.php that will check the environment variable ENV. In this section we add the ENV variable and set the value to heroku, now our database configuration is automatically taken care of for us, thanks Laravel!

Scripts

To make sure that our table migrations are taken care of we want to call run the Artisan command after the application has been deployed. It's the same as calling:

$ php artisan migrate

Procfile

The last thing that we to do is create a Procfile in the root of our direction (same as app.json). This tells the server what it's going to be running, so that the buildstep is ready.

$ touch Procfile
$ echo "web: vendor/bin/heroku-php-apache2 public" >> Procfile

Deployed!

And that's it! We've gone from a normal application to deploying on Heroku with only a couple of steps.


comments powered by Disqus