Config Migrations

Inline migrations are great and provide a lot of flexibility. However, they have a problem: You cannot have circular dependencies. For example when creating a template my-parent and a template my-child you'll likely want to set allowed children of my-parent to my-child and allowed parents of my-child to my-parent.

These kind of circular dependencies can be solved by using config migrations, which are part of the RockMigrations module as of version 6.0.0;

Using Config Migrations

All you have to do to use config migrations is to create a PHP file in one of the supported directories:

  • site/RockMigrations/[type]/[name].php
  • site/modules/[module-name]/RockMigrations/[type]/[name].php

Where [type] is one of fields, templates, roles, permissions and [name] is the name of the field, template, role or permission.

Example Migration Files

Field

// site/RockMigrations/fields/myfield.php
return [
  'label' => 'My Field Label',
  'type' => 'textarea*Language',
];

Please note the type textarea*Language. This is a magic property that tells RockMigrations to use type textarea if language support is not enabled and textareaLanguage otherwise. You can use any type that RockMigrations supports, like text, textarea, checkbox, etc.;

Template

// site/RockMigrations/templates/my-template.php
// return template data
return [
  'fields' => [
    'title',
    'foo',
    'bar',
  ],
  'childTemplates' => [
    'my-child-template',
  ],
  'noSettings' => true,
];

Role

// site/RockMigrations/roles/my-role.php
// return permissions of this role
return [
  'page-edit',
  'page-delete',
];

Permission

// site/RockMigrations/permissions/my-permission.php
// return permission description as string
return 'My Permission Description';

Benefits

Using config migrations has several benefits, the most important being to avoid circular dependencies and to have a single source of truth for your data. Other benefits include:

Faster migrations while developing

RockMigrations will only migrate changed files during development. That means if you work on a complex pageClass with 100 fields and change one field inside that file, RockMigrations will have to run all migrations for all fields.

When using config migrations, you will have one file for each field, template, role or permission. That means if you change one of them, only that file will be migrated.

Automatic Tagging

If you create a field or a template from within a module migrations folder (eg /site/modules/MyModule/RockMigrations/fields/myfield.php), RockMigrations will automatically tag it with the module name. This way you can easily find out from which module a field or template originates and you get a cleaner field and template management screen:

RockMigrations - Config Migrations

Using Intellisense

I decided to use PHP files rather than YAML or JSON, because in PHP files we get full intellisense support to make development faster and maintenance easier:

RockMigrations - Config Migrations

Class Constant Traits

This feature requires at least PHP8.2 to work.

As you might have noticed I don't like to type long field or template names as strings like rockcommerce_mylongfieldname. Instead I use class constants, which have two benefits: First, I can't make typos and second, I get autocompletion again.

The idea is that all fields that are created from within a module are available as a class constant from that module. The easiest way to explain this is by example.

Let's say we have a module called MyModule and we create a field called myfield in it. This field's name would be mymodule_myfield, but we can also use the MyModule::field_myfield constant to access the fieldname once we setup class constant traits.

To do so, we need to do two things:

  • Create the file site/modules/MyModule/RockMigrations/RockMigrationsConstants.php and do a modules refresh to populate it
  • Let your module use the RockMigrationsConstants trait

The trait file in /site/modules/MyModule/RockMigrations/RockMigrationsConstants.php could look like this:

<?php

namespace MyModule;

// DO NOT MODIFY THIS FILE!
// IT IS AUTO-GENERATED BY ROCKMIGRATIONS!

trait RockMigrationsConstants
{
  const field_myfield = 'mymodule_myfield';
}

This file will be auto-generated by RockMigrations and should not be modified. Whenever you add a new config migration this file will be updated automatically.

The code for the MyModule.module.php file could look like this:

require_once __DIR__ . '/RockMigrationsConstants.php';
class MyModule extends WireData implements Module, ConfigurableModule
{
  use \MyModule\RockMigrationsConstants;
  // rest of the class
}