Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Configuring the Platform.sh Deploy

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

We just deployed a semi-working version of our site to platform.sh! All it took was one command to bootstrap a few config files and another to create the project inside of platform.sh.

But... we had some errors and warnings along the way. On top of the output, we see a warning about using an old composer version. In a minute, we'll see how and why composer is used during the deploy. But when it is, for some reason, it's currently using an old version of Composer.

Fortunately, it warns us and tells us how to fix it.

.platform.app.yaml and How Deploying Works

Copy this dependencies line. Then, open .platform.app.yaml. This is the main deploy file: almost every deploy tweak you'll make will be made here.

There are two steps to the deploy process. The first is the build step where it's building your code: you can think of this as the step that prepares all the physical files that your project needs. Once the build step is done, it spins up a container, puts the files inside and then runs the second and final part of the process: the deploy step. This is where you can run some final commands.

See these symfony-build and symfony-deploy scripts? These are pre-made scripts that contain most of what your app needs to deploy. If you downloaded them and opened them up, you'd see things like running composer install, warming up the cache and running database migrations. We can add custom stuff above or below.

The config has mounts - for directories that you want to keep persistent between deploys - PHP extensions, your PHP version, and quite a bit more.

Using a Newer Composer Version

Anywhere inside, paste the dependencies line... and make sure it's not indented.

... lines 1 - 4
dependencies:
php:
composer/composer: "^2"
... lines 8 - 53

And just like that, we're using Composer version 2.

Setting up the Database Serve

The second error that we had, down near the bottom, was,

could not find driver

This come from when the symfony-deploy script tries to run our database migrations. Locally, we're using Postgres. You can see that in docker-compose.yml. Do we have a database up on Platform.sh yet? The answer is... actually yes.

In addition to the main deploy file - .platform.app.yaml - we have a /.platform directory with a few other files. The most important is services.yaml. This is where we define services like databases, Redis, Elasticsearch and others. When we initialized the project, it noticed that we're using Postgres and added a database for us!

... line 1
database:
type: postgresql:15
disk: 1024

The error we're getting isn't because it can't find the database: it's because our PHP install is missing the PDO_PGSQL driver! And thanks to .platform.app.yaml, adding that is easy.

Find extensions, and add pdo_pgsql.

... lines 1 - 8
runtime:
extensions:
... lines 11 - 15
- pdo_pgsql
... lines 17 - 53

Ok, ready to re-deploy? Remember: deploying happens via a push, so we need to commit these files. Run git commit -m with an inspirational message.

git commit -m "tweaking deploy script"

Now run:

symfony deploy

This runs the same steps as our first deploy, which we now understand include a build step then a deploy step. It'll take a minute or two, but should be a bit faster because it doesn't need to re-provision the SSL certificate.

Viewing the Logs

At the very end... the migration command still failed, but with a different error:

Connection refused

Ah, ignore that for a minute. Instead, go back to the site and refresh. The homepage still works. But... that's because our homepage doesn't use the database. If you hit "Browse Mixes"... 500 error! That 500 error is probably due to a database connection problem. But let's pretend that we have no idea what's causing this. How could we figure that out? This is where the

symfony logs

command comes in handy. This connects to whatever platform.sh "environment" - or "server" - that our current git branch is connected to and sends back log info. There are a bunch of choices - but hit 2 to go to the "app" log. This represents the Symfony logs coming from our app. And... oooh. I see several:

connection to server [..] failed: Connection refused

Adding the Database "Relationship"

Let's think about this. We apparently do have Postgres set up, thanks to the services.yaml file. But we never configured our app to talk to it. Remember, in .env, we have a DATABASE_URL env var that's supposed to point our database. We never configured that on our production site, so it's just using this default value. And no surprise, that's not working.

How can we configure DATABASE_URL to point to... wherever this database server is? The answer is... we... uh... don't? And it's pretty cool.

Platform.sh has this idea of relationships. You have a number of services in services.yaml. But your app can't talk to these until you link them together using what's called a "relationship".

Search .platform.app.yaml for "relationships". It's not here yet, so let's add that. Each "relationship" has an internal name. It could technically be anything, but, in practice, you should use database. We'll see the significance of that in a moment. Set this to the word database, because that's the key we have here, then : followed by the type of the service, which is postgresql.

... lines 1 - 17
relationships:
database: "database:postgresql"
... lines 20 - 56

This syntax has always looked weird to me. The important thing is that the key could be anything, like banana, but this database refers to this database over in services.yaml, and postgresql refers to this postgresql.

But though the first database key could be anything, I used database on purpose. Symfony does a really nice thing when it deploys via Platform.sh. It sees this relationship, notices it's for a database, and then automatically exposes an environment variable containing the connection info to that database!

What's this environment variable called? Since we used the key "database", it will be called DATABASE_URL. In other words, it's going to set this environment variable for us. I'll prove it!

SSHing onto the Container

One of my favorite things about Platform.sh is that you can SSH onto your container. Watch:

symfony ssh

There we go. Once here, if you want to see every environment variable, run:

printenv

Look at that! You won't see anything that starts with "database", but we should after we deploy this next change. Type exit, run

git status

and then

git add -p

That's what we want! Commit with

git commit -m "adding database relation"

And

symfony deploy

This time, it deploys way faster. Because we didn't change any application code, platform.sh was smart enough to use our old app code, instead of doing all that building again. We can see that:

Reusing existing build for this tree ID

And hey! This time, we see that it Successfully migrated! Yea! it ran our migration with zero problems. When we spin over and check the site... it works. It's still missing all of our styling... but we'll fix that next. The important thing is that the database is working.

You can see the difference that made if you run

symfony ssh

and

printenv

This time, there are several DATABASE_ variables, including the most important DATABASE_URL.

Ok, the final missing piece from our deployed site is... all of its assets! Let's see what's needed to deploy an AssetMapper site next.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^4.0", // v4.2.0
        "doctrine/doctrine-bundle": "^2.7", // 2.10.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.4
        "doctrine/orm": "^2.12", // 2.15.2
        "knplabs/knp-time-bundle": "^1.18", // v1.20.0
        "pagerfanta/doctrine-orm-adapter": "^4.0", // v4.1.0
        "pagerfanta/twig": "^4.0", // v4.1.0
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.1
        "symfony/asset": "6.3.*", // v6.3.0
        "symfony/asset-mapper": "6.3.*", // v6.3.0
        "symfony/console": "6.3.*", // v6.3.0
        "symfony/dotenv": "6.3.*", // v6.3.0
        "symfony/flex": "^2", // v2.3.1
        "symfony/framework-bundle": "6.3.*", // v6.3.0
        "symfony/http-client": "6.3.*", // v6.3.0
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "6.3.*", // v6.3.0
        "symfony/runtime": "6.3.*", // v6.3.0
        "symfony/stimulus-bundle": "^2.9", // v2.9.1
        "symfony/twig-bundle": "6.3.*", // v6.3.0
        "symfony/ux-turbo": "^2.9", // v2.9.1
        "symfony/web-link": "6.3.*", // v6.3.0
        "symfony/yaml": "6.3.*", // v6.3.0
        "twig/extra-bundle": "^2.12|^3.0", // v3.6.1
        "twig/twig": "^2.12|^3.0" // v3.6.1
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.4
        "symfony/debug-bundle": "6.3.*", // v6.3.0
        "symfony/maker-bundle": "^1.41", // v1.49.0
        "symfony/stopwatch": "6.3.*", // v6.3.0
        "symfony/web-profiler-bundle": "6.3.*", // v6.3.0
        "zenstruck/foundry": "^1.21" // v1.33.0
    }
}
userVoice