How to alter configuration entity data in Drupal 8 or add additional data in to the configuration entities

Here I'm going to detail a little bit about altering configuration entities, the config entities is a great addition in D8 and does a tons of helpful stuff for developers and site builders. In this example I'm going to alter and add additional configurations in to the Migrate configuration entity.

I hope you know what are configuration entities and what are content entities. So in brief Content type is a configuration entity while a piece of content/node is a Content entity. Config entities can be exported using Drupal CEX wizard but content entities can't export.

Okay, let's dive in to coding. In this example I'm going to alter Migration Plus contrib modules Migration entity edit page and add additional settings for the form, what we are planning on doing is to add a periodic import on migrations so we can let Migrations run on specific time periods just like Feeds.

Let's look at the Migrate configuration file first.

# Schema for the configuration files of the Migrate Plus module.

migrate_plus.migration.*:
  type: config_entity
  label: 'Migration'
  mapping:
    id:
      type: string
      label: 'ID'
    class:
      type: string
      label: 'Class'
    field_plugin_method:
      type: string
      label: 'Field Plugin Method'
    cck_plugin_method:
      type: string
      label: 'BC layer for Field Plugin Method'
    migration_tags:
      type: sequence
      label: 'Migration Tags'
      sequence:
        type: string
        label: 'Tag'
    migration_group:
      type: string
      label: 'Group'
    label:
      type: label
      label: 'Label'
    source:
      type: migrate_plus.source.[plugin]
      label: 'Source'
    process:
      type: ignore
      label: 'Process'
    destination:
      type: migrate_plus.destination.[plugin]
      label: 'Destination'
    migration_dependencies:
      type: mapping
      label: 'Dependencies'
      mapping:
        required:
          type: sequence
          label: 'Required dependencies'
          sequence:
            type: string
            label: 'Dependency'
        optional:
          type: sequence
          label: 'Optional dependencies'
          sequence:
            type: string
            label: 'Dependency'

I'm going to add one additional item to this config, the way to do is use the third_party_settings. We can use the ThirdPartySettingsInterface for that and we'll need number of stuff in-order to do that. First let's add our config file. Add the file at your modules config/schema folder named MODULE_NAME.schema.yml

migrate_plus.migration.*.third_party.MODULE_NAME:
  type: mapping
  label: 'API Schedular settings'
  mapping:
    interval:
      type: integer
      label: 'Run on every'

Then alter the form

use \Drupal\Core\Form\FormStateInterface;
use \Drupal\migrate_plus\Entity\Migration;

/**
 * Implements hook_form_alter().
 */
function MODULE_NAME_form_migration_edit_form_alter(&$form, FormStateInterface $form_state) {
  // dsm('in');
  $migration = $form_state->getFormObject()->getEntity();
  $times = [900, 1800, 3600, 10800, 21600, 43200, 86400, 259200, 604800, 2419200];

  $period = array_map(function($time) {
    return \Drupal::service('date.formatter')->formatInterval($time);
  }, array_combine($times, $times));

  foreach ($period as &$p) {
    $p = t('Every @p', ['@p' => $p]);
  }
  
  $period = [
    0 => t('Never')
  ] + $period;
  
  $form['interval'] = array(
    '#type' => 'select',
    '#title' => t('Run on every'),
    '#description' => t('Choose how often a migration should be run.'),
    '#default_value' => $migration->getThirdPartySetting('MODULE_NAME', 'interval'),
    '#weight' => 10,
    '#options' => $period
  );
 
  $form['#entity_builders'][] = 'MODULE_NAME_form_migration_edit_form_builder';
}

/**
 * Entity builder for the migration config entity.
 */
function MODULE_NAME_form_migration_edit_form_builder($entity_type, Migration $migration, &$form, FormStateInterface $form_state) {
  if ($form_state->getValue('interval')) {
    $migration->setThirdPartySetting('MODULE_NAME', 'interval', $form_state->getValue('interval'));
    return;
  }
 
  $migration->unsetThirdPartySetting('MODULE_NAME', 'interval');
}

So that's pretty much it, the only new thing here is #entity_builder and is responsible for mapping data to the entity. Now, install the module or do a cache clear to access your new properties.