Deploy CakePHP on Heroku

Heroku’s not just for Rails anymore, folks. If you’re more PHP-inclined and lean toward frameworks such as CakePHP, you might enjoy trying Heroku’s current Celadon Cedar stack as your platform.

Here I’ll step through the Blog Tutorial in the the CakePHP Cookbook, with the few extra steps needed to get it running on Heroku. As prerequisites, you should be familiar with this tutorial in its generic form, and with the basics of using Heroku.

Obviously, if you’ve baked some Cake before, you only need to look at the Heroku parts. And if you’re comfortable with both CakePHP and Heroku, just skip to the steps about the database configuration.

The section titles below match those in the Blog Tutorial. I’m not going to reproduce that tutorial in detail, but if you need more explanation, you can follow along there.

Getting Cake

Heroku works using git, so the first task is to create a git repository containing the CakePHP code.

The Cake developers also use git to write Cake itself, so there is a catch to be aware of. The .gitignore file that comes with Cake is set to exclude /app/Config and /app/tmp. Because the app will need those directories, the corresponding lines need to be removed from .gitignore. However, files put in tmp during testing shouldn’t be included, so a separate .gitignore needs to be added inside tmp, containing a wildcard followed by a negated list of everything that’s there now. My description is probably a bit confusing, so I’ll illustrate with an example of what app/tmp/.gitignore should end up looking like:

*
!.gitignore
!cache
!cache/persistent
!cache/persistent/empty
!cache/models
!cache/models/empty
!cache/views
!cache/views/empty
!logs
!logs/empty
!tests
!tests/empty
!sessions
!sessions/empty

Here are the commands I used to perform the above steps and create a “vanilla” app repository based on CakePHP 2.2.1:

# create an empty git repository
git init blog
cd blog
 
# download and unpack the cake source
wget -O- https://github.com/cakephp/cakephp/tarball/2.2.1 | tar --strip-components=1 -xzf-
 
# make sure '/app/Config' and '/app/tmp' aren't excluded by .gitignore
sed -ri '/\/app\/(Config|tmp)/d' .gitignore
 
# ...but make sure anything added to '/app/tmp' later gets excluded
pushd app/tmp
echo '*' > .gitignore
find . -mindepth 1 | sed 's/^\.\//!/' >> .gitignore
popd
 
# perform an initial commit
git add .
git commit -am 'vanilla cake'

Creating the blog database

Now it’s time to create a Heroku app and connect it to a database. ClearDB provides a free MySQL database, but Heroku Postgres would be another option if you prefer PostgreSQL.

# create a heroku app
heroku create --stack cedar
 
# create the database
heroku addons:add cleardb:ignite

Next, we need to execute the SQL from the tutorial to set up the blog database. The database connection information is available from Heroku. The command

heroku config

will output the app configuration. The line beginning with CLEARDB_DATABASE_URL contains the database URL (in JDBC syntax), which is something of the following form:

mysql://username:password@host/database?reconnect=true

Mine looked like this:

mysql://b0f7309de5b736:bb6bffba@us-cdbr-east.cleardb.com/heroku_e7718533edda49a?reconnect=true

I saved the SQL snippet from the tutorial into a file called database.sql and ran the following command to import it, though you can use any preferred means:

mysql -u b0f7309de5b736 -p -h us-cdbr-east.cleardb.com heroku_e7718533edda49a < database.sql

Cake database configuration

The meat of this whole process is getting the database configuration right. ClearDB provides some useful syntax, but the CakePHP database.php needs to be restructured a bit to make this work, because PHP class properties can only be constants.

First, initialize the database configuration file.

git mv app/Config/database.php.default app/Config/database.php

Open app/Config/database.php in your editor of choice. You’ll see that the basic layout looks like this:

class DATABASE_CONFIG {
    public $default = array();
    public $test = array();
}

That structure, unfortunately, doesn’t provide anywhere to parse the CLEARDB_DATABASE_URL. But if we move everything inside a new __construct() function, we can use ClearDB’s suggested code with no problems.

class DATABASE_CONFIG {
    function __construct() {
        $url = parse_url(getenv('CLEARDB_DATABASE_URL'));
        $this->default = array(
            'host' => $url['host'],
            'login' => $url['user'],
            'password' => $url['pass'],
            'database' => substr($url['path'],1),
        );
        $this->test = array();
    }
}

…or, more fully:

class DATABASE_CONFIG {
 
    function __construct() {
 
        $url = parse_url(getenv('CLEARDB_DATABASE_URL'));
 
        $this->default = array(
            'datasource' => 'Database/Mysql',
            'persistent' => false,
            'host' => $url['host'],
            'login' => $url['user'],
            'password' => $url['pass'],
            'database' => substr($url['path'],1),
            'prefix' => '',
            //'encoding' => 'utf8',
        );
 
        $this->test = array(
            'datasource' => 'Database/Mysql',
            'persistent' => false,
            'host' => 'localhost',
            'login' => 'user',
            'password' => 'password',
            'database' => 'test_database_name',
            'prefix' => '',
            //'encoding' => 'utf8',
        );
 
    }
 
}

Sweet. Let’s commit that.

git commit -am 'configured database connection'

Note that this connection doesn’t use SSL due to MySQL SSL not yet being available in CakePHP. If that concerns you, you might be better off using Heroku’s own pgsql.

Creating the blog application

Go through the rest of the steps in the blog tutorial to create the models, views, and controllers. Again, I won’t bore you or tire my fingers by repeating that process here. When you’ve finished those steps, perform a final commit.

# do the rest of the stuff in the blog tutorial
# ...
 
# perform a final commit
git add .
git commit -am 'blog tutorial'

Deploying to Heroku

All that’s left to do is to push the code to Heroku:

# push to heroku
git push heroku master

Easy peasy. Let’s see what we’ve wrought:

# open the app in a web browser
heroku apps:open

That’s it! Your Cake-powered blog app is running on Heroku.

  • styks1987

    What about uploading files?

  • styks1987

    Inside the app. Say a user uploads an image for their profile.

  • @styks1987 You would need to use something like Amazon S3. See this page from Heroku: https://devcenter.heroku.com/articles/s3

  • styks1987

    @dnrce Great thanks

  • angelxmoreno

    Are there any issues with CakePHP’s default logging and caching system writing to local files?

  • @angelxmoreno  Heroku provides non-persistent write access. CakePHP will be able to write to the log and cache, but it’s part of the dyno state and doesn’t get permanently stored anywhere.

  • smaugstheswagger

    Why some developers prefer Heroku? There are other similar platforms for deploying CakePHP app, like Cloudways, that are as good as Heroku,