Drupal 8 Configuration system for coders and site builders Friday 23 August 13
who am I? Kristof De Jaeger @swentel Co-maintainer of Field API Lead maintainer of Display Suite Developer @ Wunderkraut Friday 23 August 13
Outline • What’s the problem • How did we solve it • Simple static settings • Configuration entities • Deployment - with demo • Configuration schema • Context, events and overrides Friday 23 August 13
What problems are we trying to solve? • Variable soup Live Save textSetting 1 Setting 2 label Database Database Dev TEST test test test test test test test test test test test test test test node/4admin/config/foo Welcome This is real content on the live site that end users are viewing node/4 Save old textSetting 1 Setting 2 label admin/config/foo Friday 23 August 13
Live Save textSetting 1 Setting 2 label Database Database Dev TEST test test test test test test test test test test test test test test node/4admin/config/foo Welcome This is real content on the live site that end users are viewing node/4 Save old textSetting 1 Setting 2 label admin/config/foo Danger! Want to bring over configuration changes from dev, but not overwrite live content! What problems are we trying to solve? Friday 23 August 13
What problems are we trying to solve? variable_set()/variable_get() ctools_export_object()/ ctools_export_load_object() db_select()/db_update()/ db_delete() $conf[...]; hook_update_N() drush fu http://www.flickr.com/photos/bean/322616749 napkins Friday 23 August 13
The solution • Files using theYAML specification • Active and staging directory • Cached in the database using a standard cache interface • Config directory changed via settings.php Friday 23 August 13
The anatomy of a configuration file Friday 23 August 13
system.site.yml Friday 23 August 13
system.site.yml Friday 23 August 13
system.site.yml Friday 23 August 13
name: 'Configuration management' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node system.site.yml Friday 23 August 13
The API Drupal::config() ->get() ->set() ->save() Friday 23 August 13
Accessing data Friday 23 August 13
name: 'Configuration management' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node $site_name = Drupal::config('system.site')->get('name'); Friday 23 August 13
$page_data = Drupal::config('system.site')->get('page'); name: 'Configuration management' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node Friday 23 August 13
$frontpage = Drupal::config('system.site')- >get('page.front'); name: 'Configuration management' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node Friday 23 August 13
$all_the_data = Drupal::config('system.site')->get(); name: 'Configuration management' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node Friday 23 August 13
Saving data Friday 23 August 13
name: 'CMI is good' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: '' 404: '' front: node Drupal::config('system.site') ->set('name', 'CMI is good') ->save(); Friday 23 August 13
name: 'CMI is great' mail: admin@example.com slogan: 'makes Drupal 8 cex -y' page: 403: access-denied 404: not-found front: user Drupal::config('system.site') ->set('name', 'CMI is great') ->set('page', array( 403 => 'access-denied', 404 => 'not-found', front => 'user', )) ->save(); Friday 23 August 13
Friday 23 August 13
• system_settings_form is dead • add your own submit callback • you are responsible for saving configuration • ship with default configuration file simple settings Friday 23 August 13
{system} {date_format_locale} {date_formats} {date_format_type} {field_config} {field_config_instance} {filter} {filter_format} {node_type} {role}{role_permission} {variable} {language} Friday 23 August 13
Config all the things! Friday 23 August 13
Config entities Friday 23 August 13
use DrupalCoreConfigEntityConfigEntityBase; use DrupalCoreAnnotationPlugin; use DrupalCoreAnnotationTranslation; /** * Defines the contact category entity. * * @EntityType( * id = "contact_category", * label = @Translation("Category"), * module = "contact", * controllers = { * controller_class = "DrupalcontactCategoryStorageController", * list = "DrupalcontactCategoryListController", * form = { * "add" = "DrupalcontactCategoryFormController" * "edit" = "DrupalcontactCategoryFormController" * } * } * uri_callback = "contact_category_uri", * config_prefix = "contact.category", * entity_keys = { * "id" = "id", * "label" = "label", * "uuid" = "uuid" * } * ) */ class Category extends ConfigEntityBase implements CategoryInterface { /** * The category ID.Friday 23 August 13
use DrupalCoreConfigEntityConfigEntityBase; use DrupalCoreAnnotationPlugin; use DrupalCoreAnnotationTranslation; /** * Defines the contact category entity. * * @EntityType( * id = "contact_category", * label = @Translation("Category"), * module = "contact", * controllers = { * controller_class = "DrupalcontactCategoryStorageController", * list = "DrupalcontactCategoryListController", * form = { * "add" = "DrupalcontactCategoryFormController" * "edit" = "DrupalcontactCategoryFormController" * } * } * uri_callback = "contact_category_uri", * config_prefix = "contact.category", * entity_keys = { * "id" = "id", * "label" = "label", * "uuid" = "uuid" * } * ) */ class Category extends ConfigEntityBase implements CategoryInterface { /** * The category ID.Friday 23 August 13
namespace DrupalcontactPluginCoreEntity; use DrupalCoreConfigEntityConfigEntityBase; use DrupalCoreAnnotationPlugin; use DrupalCoreAnnotationTranslation; /** * Defines the contact category entity. * * @Plugin( * id = "contact_category", * label = @Translation("Category"), * module = "contact", * controllers = { * controller_class = "DrupalCoreConfigEntityConfigStorageController", * list = "DrupalcontactCategoryListController", * form = { * "add" = "DrupalcontactCategoryFormController" * } * }, * uri_callback = "contact_category_uri", * config_prefix = "contact.category", * entity_keys = { * "id" = "id", * "label" = "label", * "uuid" = "uuid" * } * ) */ class Category extends ConfigEntityBase implements ContactInterface { /** * The category ID. Friday 23 August 13
use DrupalCoreConfigEntityConfigEntityBase; use DrupalCoreAnnotationPlugin; use DrupalCoreAnnotationTranslation; /** * Defines the contact category entity. * * @EntityType( * id = "contact_category", * label = @Translation("Category"), * module = "contact", * controllers = { * controller_class = "DrupalCoreConfigEntityConfigStorageController", * list = "DrupalcontactCategoryListController", * form = { * "add" = "DrupalcontactCategoryFormController" * "edit" = "DrupalcontactCategoryFormController" * } * } * uri_callback = "contact_category_uri", * config_prefix = "contact.category", * entity_keys = { * "id" = "id", * "label" = "label", * "uuid" = "uuid" * } * ) */ class Category extends ConfigEntityBase implements ContactInterface { /** * The category ID.Friday 23 August 13
*/ class Category extends ConfigEntityBase { /** * The category ID. */ public $id; /** * The category UUID. */ public $uuid; /** * The category label. */ public $label; /** * List of recipient e-mail addresses. */ public $recipients = array(); /** * An auto-reply message to send to the message author. */ public $reply = ''; /** * Weight of this category (used for sorting). */ public $weight = 0; } Friday 23 August 13
id: feedback uuid: de77e4f3-f94b-41a5-ad05-5c32fa08444f label: 'Website feedback' recipients: - '' reply: '' weight: '0' langcode: und contact.category.feedback.yml Friday 23 August 13
(config) entity API • entity_load • entity_save • $object->any_method() Friday 23 August 13
Deployment Friday 23 August 13
Database Development environment Active Directory 1 Friday 23 August 13
Database Development environment Active Directory 1 Friday 23 August 13
Database Development environment Active Directory 1 2 Friday 23 August 13
Database Production environment Staging Directory Active Directory 3 admin/config/development/sync Friday 23 August 13
Database Production environment Staging Directory Active Directory 3 4 admin/config/development/sync Friday 23 August 13
Demo time • No partial imports ! Friday 23 August 13
Drush integration Friday 23 August 13
Advanced workflows • https://drupal.org/sandbox/dereine/2057465 Friday 23 August 13
Don’t hack core Friday 23 August 13
Don’t hack active config Friday 23 August 13
State API Drupal::state()->set('update.last_check', $now); //... $last_check = Drupal::state()->get('update.last_check') ?: 0; Only useful for this environment? Use state(). Friday 23 August 13
Configuration schema Friday 23 August 13
system.maintenance.yml enabled: '0' message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.' Friday 23 August 13
system.schema.yml system.maintenance: type: mapping label: 'Maintenance mode' mapping: "enabled": type: boolean label: "Put site into maintenance mode" "message": type: text label: "Message to display when in maintenance mode" Friday 23 August 13
Basic scalar types from typed data boolean: label: 'Boolean' class: 'DrupalCoreTypedDataTypeBoolean' email: label: 'Email' class: 'DrupalCoreTypedDataTypeEmail' integer: label: 'Integer' class: 'DrupalCoreTypedDataTypeInteger' string: label: 'String' class: 'DrupalCoreTypedDataTypeString' uri: label: 'Uri' class: 'DrupalCoreTypedDataTypeUri' Friday 23 August 13
Basic data types for configuration undefined: label: 'Undefined' class: 'DrupalCoreConfigSchemaProperty' mapping: label: Mapping class: 'DrupalCoreConfigSchemaMapping' sequence: label: Sequence class: 'DrupalCoreConfigSchemaSequence' Friday 23 August 13
Simple extended data types # Human readable string that must be plain text and editable with a text field. label: type: string label: 'Label' translatable: true # Internal Drupal path path: type: string label: 'Path' # Human readable string that can contain multiple lines of text or HTML. text: type: string label: 'Text' translatable: true Friday 23 August 13
Complex extended data type # Mail text with subject and body parts. mail: type: mapping label: "Mail" mapping: "subject": type: text label: "Subject" "body": type: text label: "Body" Friday 23 August 13
Config inspector module Friday 23 August 13
Context system, Events & Overrides Friday 23 August 13
global $conf; $conf['system.maintenance']['message'] = 'Sorry, our site is down now.'; Global overrides Friday 23 August 13
class ConfigGlobalOverrideSubscriber implements EventSubscriberInterface { static function getSubscribedEvents() { $events['config.init'][] = array('configInit', 30); return $events; } public function configInit(ConfigEvent $event) { global $conf; $config = $event->getConfig(); if (isset($conf[$config->getName()])) { $config->setOverride($conf[$config->getName()]); } } } Global overrides Friday 23 August 13
Break out of contexts // Enter the override-free context, so we can ensure no overrides are applied. config_context_enter('config.context.free'); // Get system site maintenance message text from the original config. $message = config('system.maintenance')->get('message'); // Leave the override-free context. config_context_leave(); Friday 23 August 13
Get into contexts // Enter a user specific context. $context = config_context_enter("DrupaluserUserConfigContext"); // Set the account to use on the context. $context->setAccount($account); $mail_config = Drupal::config('user.mail'); // Do stuff... config_context_leave(); Friday 23 August 13
Language overrides block.block.bartik.login.yml id: bartik.login uuid: 7012ebfd-7083-47ef-b... weight: '0' status: '1' langcode: en region: sidebar_first plugin: user_login_block settings: label: 'User login' module: user label_display: visible cache: '-1' ...... locale.hu.block.block.bartik.login.yml settings: label: 'Belépés' locale.nl.block.block.bartik.login.yml settings: label: 'Inloggen' Friday 23 August 13
recap and advice • key names/properties should have meaning • Use config entities instead of tables • Use getters/setters/methods on entities • Include config schema (translation!) • Upgrade functions available in update.inc Friday 23 August 13
Please try it out! • #drupal-cmi - Dedicated IRC channel • docs - https://drupal.org/node/1667894 • help along - http://drupal.org/core-mentoring-hours Friday 23 August 13
• http://groups.drupal.org/cmi - Discussion • http://v.gd/cmi_issues - Issues • http://groups.drupal.org/core - Core announcements • #drupal-cmi - Dedicated IRC channel • http://drupal.org/core-mentoring-hours Friday 23 August 13
Questions ? Friday 23 August 13
Thanks @heyrocker @webchick @moshe_weitzman @GaborHojtsy @alexpott Friday 23 August 13

Drupal 8 configuration system for coders and site builders - DrupalCamp Baltics 2013