A blog about hacking, but really more in a golfish sense.

Platform.sh from scratch - PostgreSQL

Hi there and welcome back to Platform from scratch. Today we're going to take a very simple Laravel application that will make use of Postgres on the backend as a database.

The complete example application can be found here - https://github.com/JGrubb/platformsh-laravel-example

The very first step of this will be to add in the appropriate .platform/services.yaml file. This file was left intentionally empty in the setup for this Laravel application, as we didn't have a need for a working database and were just getting our app set up and running. Now however, we're going to add a very simple configuration into services.yaml.

# This is the "name" of this service and can be any arbitrary string.
# You could name this "foo" and that's the name you'd use in your
# .platform.app.yaml file in the next step.
pgsql:
# This is the actual service you'll be using.
type: postgresql:9.3
# How much space you want to give this in megabytes.
# 1 gig will get us going
disk: 1024

relationships:
# This config takes the form of "relationship_name: service_name:driver"
#
# Instead of "database", you could also call this "bar" and that's how it'll
# show up in the $PLATFORM_RELATIONSHIPS environment variable. I'll show
# you how that manifests itself in just a moment.
#
# "pgsql" in this case is the name you gave it in services.yaml and
# "postgresql" is the part that you can't just arbitrarily name. That
# is the hint to our container build system that you need a PG database
# service.
database: "pgsql:postgresql"

Commit this and push it up to your platform remote. This will trigger a rebuild of your application, and when that's done let's SSH into your environment with the Platform CLI - $ platform ssh.

Once you're in, try this - echo $PLATFORM_RELATIONSHIPS. You'll get a big base64 encoded string as a result. This is because you can't set complex objects or even JSON as an environment variable, so let's decode that by piping it to base64 --decode - echo $PLATFORM_RELATIONSHIPS | base64 --decode

So the basic gist of how you establish a connection to any kind of service that you set up in services.yaml should now be clearer than it was before, and we'll now set about adding the code to our Laravel app that will make use of these environment variables.

<?php
// at the top of config/database.php. This will decode the base64
// encoded envvar and expand it into the variables that Laravel is
// expecting.
if ($relationships = getenv('PLATFORM_RELATIONSHIPS')){
$pltrels = json_decode(base64_decode($relationships), TRUE);
$database = $pltrels['database'][0];
putenv("DB_CONNECTION={$database['scheme']}");
putenv("DB_HOST={$database['host']}");
putenv("DB_PORT={$database['port']}");
putenv("DB_DATABASE={$database['path']}");
putenv("DB_USERNAME={$database['username']}");
putenv("DB_PASSWORD={$database['password']}");
}

This particular piece of code is not Postgres specific, and in fact will work just fine with MySQL as well. The beauties of abstraction...

The final step in this process is optional, but if you want to have artisan migrate the database on deploy rather than logging into the server and running it manually you'd add this to the bottom of your hooks.deploy in .platform.app.yaml --

hooks:
deploy:
# other commands
php artisan migrate --force

The --force flag will allow migrate to run in a "production" environment.