Skip to content

Instantly share code, notes, and snippets.

@lolandese
Last active January 14, 2022 13:36
Show Gist options
  • Save lolandese/eb0e2392264aca7d736dd712e432410e to your computer and use it in GitHub Desktop.
Save lolandese/eb0e2392264aca7d736dd712e432410e to your computer and use it in GitHub Desktop.
Convert a Drupal YAML configuration file to an array as a working PHP code snippet to write its values to the database. This is code to generate code. Short URL: https://git.io/fjjDu
<?php
/**
* @file
* Convert a YAML file to PHP code to write its values to the database.
*/
use Drupal\Component\Serialization\Yaml;
// Replace 'filter.format.full_html' with any other existing configuration
// object. The configuration YAML file must exist. Export the configuration
// first if that is not the case.
$input = 'filter.format.full_html';
// Parse the YAML file and convert it to a PHP array.
$yamlDecoded = Yaml::decode(file_get_contents(dirname(\Drupal::root()) . '/config/' . CONFIG_SYNC_DIRECTORY . '/' . $input . '.yml'));
// Remove the 'UUID' and '_core'. Not needed in the generated code.
unset($yamlDecoded['uuid']);
unset($yamlDecoded['_core']);
// Create a variable name based on the configuration object name.
$dynamic_var = '$' . str_replace('.', '_', $input);
// Create a parsable string representation of the YAML file.
$output = print_r(var_export($yamlDecoded, TRUE), TRUE);
// Sanitize the output according to the Drupal coding standard.
$target = [
'/array \(/',
'/\)/',
'/true/',
'/false/',
'/=>[ \t]+' . PHP_EOL . '[ \t]+\[' . PHP_EOL . '[ \t]+\],/',
'/=>[ \t]+' . PHP_EOL . '/',
];
$replacement = [
'[',
']',
'TRUE',
'FALSE',
'=> [],',
'=>' . PHP_EOL,
];
$output = preg_replace($target, $replacement, $output);
// Generate the PHP code snippet.
print('<h2>PHP code to copy and paste</h2>');
print('<pre>' . highlight_string("<?php
/**
* @file
* Set a complete configuration object in the database.
*/
// Still to export to the configuration YAML file (drush cex).
// Code generated with https://git.io/fjjDu (leave for future reference).
$dynamic_var = $output;
\Drupal::configFactory()->getEditable('$input')->setData($dynamic_var)
->save();
", TRUE) . '</pre>');
@lolandese
Copy link
Author

lolandese commented Sep 6, 2019

Set a Drupal 8 configuration object programmatically

The above code generates the needed PHP code from a known configuration YAML file to set the values in the database accordingly. Doing it programmatically instead of an import. Code to generate code.

This might be needed:

  • to set a certain configuration if certain conditions are met, wrapping it in an if statement
  • to set a certain configuration dynamically, for example, for all available content types, wrapping it in a foreach loop
  • as part of an automated process to set up an environment with certain configuration through PHP after a Drupal bootstrap.

Instructions

In short, you need a local Drupal 8 site to generate the configuration that you need, export that into a YAML file and use that as the input for the code snippet above.

Use a (local) sandbox site to generate your code from a configuration YAML file

  • Use the PHP filter on a content type to insert the code above on a node that executes a PHP snippet.
  • Enable the filter on a dedicated new content type 'PHP code'.

Set the configuration

  • Set some configuration. In the example above we enabled translations for the content type "Basic page".
  • Export this configuration to generate the updated YAML file (drush cex).

Execute the PHP code snippet

  • Create a new node of the content type 'PHP code' using the PHP text format
  • Copy-paste the Raw code above into the node body field.
  • On line 13 replace the machine name ID of the configuration object with your own (the same as the YAML file but without the file extension .yml).
  • Save the node to execute the PHP and generate the code snippet. If all went fine you should see the generated code snippet to copy-paste into a new node (see below).

Test and apply

  • Create a new node with the PHP text format and paste the generated snippet and save. If all went well again, the new node is saved without errors.
  • Make a small change to detect if the code has its effect and save again.
  • Check the configuration change by exporting the configuration and inspecting the YAML file or, to inspect the database value directly, use drush cedit filter.format.full_html (change with your own machine name for the config object).
  • If all fine, use the snippet in your code base. Make adjustments (see the suggestions below) and correct the indenting if necessary.

Suggestions for the generated code

Obviously you can wrap the generated code in a conditional, only setting a certain configuration in a specific context, or use dynamic variables.

To illustrate, as an example, the content type machine name 'page' could be replaced with a variable $content_type in the generated example code from the comment below (output). Let's say, if we are inside a class now using dependency injection, the first line to set our configuration object would look like:

use Drupal\Core\Config\ConfigFactoryInterface;

...

$this->configFactory->getEditable('language.content_settings.node.' . $content_type)->setData([

Also other occurrences of 'page' should also be replaced with $content_type like:

  'dependencies' => [
    'config' => ['node.type.' . $content_type],
  'id' => 'node.' . $content_type,
  'target_bundle' => $content_type,

Wrapping the whole code snippet then inside a foreach loop to set a certain configuration for each content type:

        use Drupal\Core\Entity\EntityTypeBundleInfoInterface;

        // Enable translations for each existing content type.
        $bundle_info = $this->entityTypeBundleInfo->getBundleInfo('node');
        foreach ($bundle_info as $content_type => $value) {
          ....
        }

Documentation

Simple Configuration API - Writing configuration - Drupal 8 guide on Drupal.org

@lolandese
Copy link
Author

lolandese commented Sep 6, 2019

An example of usage

Input (to insert on line 13 in the snippet)

filter.format.full_html

Output (executing the snippet)

Does comply with both Drupal Code Sniffer and Best Practice standards.

PHP code to copy and paste

<?php

/**
 * @file
 * Set a complete configuration object in the database.
 */

// Still to export to the configuration YAML file (drush cex).
// Code generated with https://git.io/fjjDu (leave for future reference).
$filter_format_full_html = [
  'langcode' => 'es',
  'status' => TRUE,
  'dependencies' =>
  [
    'module' =>
    [
      0 => 'editor',
    ],
  ],
  'name' => 'Full HTML',
  'format' => 'full_html',
  'weight' => 2,
  'filters' =>
  [
    'filter_align' =>
    [
      'id' => 'filter_align',
      'provider' => 'filter',
      'status' => TRUE,
      'weight' => 8,
      'settings' => [],
    ],
    'filter_caption' =>
    [
      'id' => 'filter_caption',
      'provider' => 'filter',
      'status' => TRUE,
      'weight' => 9,
      'settings' => [],
    ],
    'filter_htmlcorrector' =>
    [
      'id' => 'filter_htmlcorrector',
      'provider' => 'filter',
      'status' => TRUE,
      'weight' => 10,
      'settings' => [],
    ],
    'editor_file_reference' =>
    [
      'id' => 'editor_file_reference',
      'provider' => 'editor',
      'status' => TRUE,
      'weight' => 11,
      'settings' => [],
    ],
  ],
];
\Drupal::configFactory()->getEditable('filter.format.full_html')->setData($filter_format_full_html)
  ->save();

@lolandese
Copy link
Author

lolandese commented Sep 7, 2019

To convert a Drupal YAML snippet to a working PHP code snippet, go to https://git.io/Jem8t.

This can also be just a part of a YAML, either from a file or from the database suggested as export at admin/config/development/configuration/single/export.

@todo
Add error handling, messaging and logging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment