Migrating new features with Fork CMS

You've spent the last few weeks working on this brand new feature for your fancy website and it looks amazing! You and your peers thoroughly tested everything, so it's time to deploy this feature to production. You deploy your project with the Fork CMS Capistrano gem and everything seems to go well.

When checking the production website you suddenly encounter a 500 error! Not sure what went wrong, you quickly revert your feature and deploy again. All is well... You import the production database to your local system and start debugging, only to find out you forgot to add that database field you added a week ago.

Sound familiar? 

Enter migrations

The Fork CMS Capistrano gem has recently been updated to its 3rd version which introduces migrations. Migrations are a collection of update.sql and locale.xml files which get imported if you deploy them for the first time. These allow you to instantly update the database to hold the data exactly when you need them. Remember the days of making sure your database is prepared for your new feature or scouring your website for missing labels? Those days are now over.

Okay but.. how does it work?

It's really easy! Say a client of yours has a website which displays their products. This client just expanded their product range which causes them to have several similar products where the only difference is the colour. To deal with this, you are requested to display a products colour on the website.

No problem, let's create a new feature to add colours to the products in our products module. We're going to need some database changes along with some new labels to display this information on the website. To start off, we create a folder called product-colours in a migrations folder we've placed in our root.

Database changes

To hold the product's colours we want to add a new field to our products table. We do this by writing a simple query:

ALTER TABLE `products` ADD `color` VARCHAR(255);

Simple, right? Now to make sure this will also be added to our production database when deploying we create a file called update.sql in our previously created product-colours folder. In this file we simply add the query, done!

Locale changes

So now we have everything in place to hold a product's colour. Time to display this on our website! In our template, we might write something along the lines of

<p>
  <strong>{{ 'lbl.Color'|trans|ucfirst }}</strong>: {{ product.color }}
</p>

When we render our page we will be presented with the following string:

{$lblColor}: red

This, of course, means we need to add the Color label. Now, instead of going to your backend to add the label or even just add it to your database manually, we're going to create a locale.xml file. You might recognise this name because it's used in the installer of every Fork CMS module! When you need to update locale inside a feature, create a locale.xml file in the specific migration folder:

<?xml version="1.0" encoding="utf-8"?>
<locale>
  <Frontend>
    <Core>
      <item type="label" name="Color">
        <translation language="en"><![CDATA[color]]></translation>
        <translation language="fr"><![CDATA[couleur]]></translation>
        <translation language="nl"><![CDATA[kleur]]></translation>
        <translation language="de"><![CDATA[farbe]]></translation>
      </item>
    </Core>
  </Frontend>
</locale>

You can now import this file in your backend or through the bin/console forkcms:locale:import console command to check if everything is working as intended. If it does, move it into your migration folder if you haven't already.

Deploying

Everything is in place to deploy our new feature at this point. We do this by executing cap production deploy in the terminal. Our Capistrano gem will hook in at the right time to execute our new migrations, ensuring everything in the database is in sync with the code we've just developed! Amazing, right?

What if something goes wrong?

Let's just assume some of us have made some silly mistakes at some point in our development careers. You were unlucky enough to make a typo in one of your migrations and the deploy script now throws an error when deploying. Ouch.

Your database is probably corrupted at this point

No worries though, the deploy script has your back! If you go to your website right now, you will see a snazzy screen saying your website is undergoing some maintenance.

So what about my database?

Easy! Roll back your deploy by running cap production deploy:rollback and everything will work as it did before giving you plenty of time to fix your typo. This is the magic of migrations at work!

Recap

Migrations allow you ensure minimal downtime, minimal errors and minimal headaches when creating new features or bugfixes. It is also useful when programming with multiple developers on the same project. Developer 1 develops a feature and developer 2 needs to enhance it, no need to transfer databases because everything you need to migrate is in the codebase. 

File structure

Root
├── migrations
│   ├── product-colors
│   │   ├─── update.sql
│   │   └─── locale.xml

update.sql

ALTER TABLE `products` ADD `color` VARCHAR(255);

locale.xml

<?xml version="1.0" encoding="utf-8"?>
<locale>
  <Frontend>
    <Core>
      <item type="label" name="Color">
        <translation language="en"><![CDATA[color]]></translation>
        <translation language="fr"><![CDATA[couleur]]></translation>
        <translation language="nl"><![CDATA[kleur]]></translation>
        <translation language="de"><![CDATA[farbe]]></translation>
      </item>
    </Core>
  </Frontend>
</locale>