Drupal 8 Configuration Management

Preview:

DESCRIPTION

The configuration management system in Drupal 8 seems like a great idea, but what is it? In this session I hope to show what configuration management is, why it is needed and how it will make all of our lives as Drupal site builders better.

Citation preview

Drupal 8Configuration Management

Phil Norton Drupal Camp Yorkshire 2014

DrupalCamp Yorkshire 2014

Me

• Phil Norton (@philipnorton42)

• #! code (www.hashbangcode.com)

• Technical Lead at Access

• Help run NWDUG

What Is Drupal Config?

!A quick quiz

Blog post

Permissions

Vocabulary

Taxonomy term

Field definition

Menu

Variable

Menu item

User

Contents of a block

Configuration Content

Blog Post !Taxonomy Term !Menu Item !Block Content

Permissions !

Field Definition !

Vocabulary !

Menu !

Variable

TAC !

Webform !

Default Content

!Views

Configuration Content

Blog Post !Taxonomy Term !Menu Item !Block Content

Permissions !

Field Definition !

Vocabulary !

Menu !

Variable

TAC !

Webform !

Default Content

!Views

Content !!

Session !!

State !!

Configuration

An article page, uploaded files

Logged in status, shopping carts

Last cron run

Everything else

Challenge• Developer:

• Wants to work on code

• Wants to change the config

• Wants to deploy across environments

• Client:

• Wants to work on content

• Doesn’t want to lose work

Current Situation

Drupal 7 Configuration

• Features

• Install/Update hooks

• Install Profiles

How do we currently manage configuration in Drupal?

Features• Export and import of certain configurations as

modules

• Not all modules supported so there tends to be gaps in the configuration

• Adding Features support for modules is not easy

• Features ‘Overridden’ sadness

Install/Update Hooks

• Create tables

• Set up variables

• Fill in ‘gaps’ in Features modules

Install Profiles

• Combine Features modules and install hooks

• Full site setup out of the box

• Limited Drupal API available

• Doesn’t always work as planned

What’s Next In Drupal 8?

Drupal 8 Initiatives• Configuration Management

• Web Services

• Multilingual

• HTML 5

• Mobile

CMIConfiguration Management Initiative

http://bit.ly/1tDBbsA !

http://drupal8cmi.org

CMI• Lead by Greg Dunlap - (heyrocker)

Also involved are:

• Joel Farris (senpai)

• Jonathan Lambert (jlambert)

• David Strauss (davidstrauss)

• Larry Garfield (crell)

• Karoly Negeyesi (chx)

• Angie Byron (webchick)

• Alex Pott (alexpott)

• And many others…

CMI

To build Drupal from the ground up to be better at configuration management

CMI• Move configuration management into core

• Allow storage of configuration in files

• Allow the transfer of configuration between environments

• Create an API to allow custom configurations

• Integrate UUID into core so certain configurations can be given machine names

Usage

Behind The Scenes

• Active configuration is stored in the database

• Clicking Export collates the configuration that each module defines and combines it with the current active configuration

• Export contains the active configuration in the form of YAML files

Behind The Scenes• YAML files are used to store the configuration

• A ‘staging’ and an ‘active’ directory are defined in settings.php

• Used to store and compare the current configuration

• By default the directories are stored in the location /sites/default/files/config_<hash>/

active

• Originally intended to be used as the location of the active configuration

• Active configuration is now stored in the database

• Configuration development module (https://drupal.org/project/config_devel)

staging

• Stores current imported configuration as YAML files

• Shows difference between configuration changes

• Changes made here can be imported into active configuration

YAML!YAML Ain't Markup Language

!(Yet Another Markup Language)

YAML• Data orientated format

• Has several benefits over other formats like INI, JSON, XML

• Support for hierarchical values

• Lists and associative arrays possible

• Used extensively in Drupal 8

YAML• Simple values defined by

key: value

• Hierarchical values defined with whitespace

keys: key1: value key2: value

YAML

Comments start the line with a ‘#’

!

# This is a comment item: value

YAML Lists!- item1 - item2 - item3 !![item1, item2, item3] !!- {name: 'webserver1', ip: ‘192.168.100.100’} - {name: 'webserver2', ip: ‘192.168.100.101’} - {name: 'webserver3', ip: ‘192.168.100.102’}

uuid: ''name: Drupalmail: ''slogan: ''page: 403: '' 404: '' front: useradmin_compact_mode: falseweight_select_max: 100langcode: en

core/modules/system/config/install/system.site.yml

YAML Filenames In Drupal 8

• < module >.< component >.yml system.settings.yml views.settings.yml

• < module >.< component >.< entity >.yml image.style.medium.ymlviews.view.content.yml

Configuration API

Configuration Schema

• Needed to define what your configuration will hold

• Kwalify inspired format

• Used to define what types of data the configuration will contain

• See more at: https://drupal.org/node/1905070

system.schema.ymlsystem.site: type: mapping label: 'Site information' mapping: uuid: type: string label: 'Site UUID' name: type: label label: 'Site name' mail: type: email label: 'E-mail address' slogan: type: label label: 'Slogan' page: type: mapping label: 'Pages' mapping: 403: type: path label: 'Default 403 (access denied) page' 404: type: path label: 'Default 404 (not found) page' front: type: path label: 'Default front page' admin_compact_mode: type: boolean label: 'Compact mode' weight_select_max: type: integer label: 'Weight element maximum value' langcode: type: string label: 'Default language'

system.schema.yml

system.site: type: mapping label: 'Site information' mapping: uuid: type: string label: 'Site UUID' name: type: label label: 'Site name'

Schema name

Also shows the configuration

filename “system.site.yml”

Used to reference this configuration

system.schema.yml

system.site: type: mapping label: 'Site information' mapping: uuid: type: string label: 'Site UUID' name: type: label label: 'Site name'

Container data type

‘mapping’ is for key value sets

allows for associative arrays of different data

types

system.schema.yml

system.site: type: mapping label: 'Site information' mapping: uuid: type: string label: 'Site UUID' name: type: label label: 'Site name'

Label

Used as an interface label

system.schema.yml

system.site: type: mapping label: 'Site information' mapping: uuid: type: string label: 'Site UUID' name: type: label label: 'Site name'

Start of mapping section

item keyitem typeitem label

Simple Configuration• Can be single values or arrays of values

• Used to store global configuration options

• Easy to implement:

• Create schema YAML file in < module >/config/install/schema

• Create config YAML file < module >/config/install

Getting Configurationuuid: ''name: Drupalmail: ''slogan: ''page: 403: '' 404: '' front: useradmin_compact_mode: falseweight_select_max: 100langcode: en!!$config = \Drupal::config('system.site'); $email = $config->get('mail');

!$cofig = \Drupal::config(‘system.site')$page403 = $config->get('page.403');

Getting Configurationuuid: ''name: Drupalmail: ''slogan: ''page: 403: '' 404: '' front: useradmin_compact_mode: falseweight_select_max: 100langcode: en!!$email = \Drupal::config('system.site')->get('mail');

!$page403 = \Drupal::config('system.site')->get('page.403');

!

Setting Configuration$config = \Drupal::config('system.site'); $config->set(‘mail’, ‘test@example.com’); $config->save();

!!$config = \Drupal::config(‘system.site’)->set('mail', ‘test@example.com’); $config->save();!!\Drupal::config(‘system.site’)->set('mail', ‘test@example.com)->save();

Clear Configuration

$config = \Drupal::config('system.site');$config->clear('mail')->save();

!\Drupal::config('system.site')->delete();

Configuration Entities

• Used to store custom entity configurations

• More complex and therefore harder to implement

• Used for configurations that have multiple entries Example: Views, Image cache settings, Contact form categories

Contact Category Interface

namespace Drupal\contact;!use Drupal\Core\Config\Entity\ConfigEntityInterface;!/** * Provides an interface defining a contact category entity. */interface CategoryInterface extends ConfigEntityInterface {!}

Contact Category Entitynamespace Drupal\contact\Entity;!use Drupal\Core\Config\Entity\ConfigEntityBase;use Drupal\Core\Entity\EntityStorageInterface;use Drupal\contact\CategoryInterface;!/** * Defines the contact category entity. * * @ConfigEntityType( * id = "contact_category", * label = @Translation("Contact category"), * controllers = { * "access" = "Drupal\contact\CategoryAccessController", * "list_builder" = "Drupal\contact\CategoryListBuilder", * "form" = { * "add" = "Drupal\contact\CategoryForm", * "edit" = "Drupal\contact\CategoryForm", * "delete" = "Drupal\contact\Form\CategoryDeleteForm" * } * }, * config_prefix = "category", * admin_permission = "administer contact forms", * bundle_of = "contact_message", * entity_keys = { * "id" = "id", * "label" = "label" * }, * links = { * "delete-form" = "contact.category_delete", * "edit-form" = "contact.category_edit" * } * ) */class Category extends ConfigEntityBase implements CategoryInterface {

class Category extends ConfigEntityBase implements CategoryInterface {! /** * The category ID. * * @var string */ public $id;! /** * The category label. * * @var string */ public $label;! /** * List of recipient e-mail addresses. * * @var array */ public $recipients = array();! /** * An auto-reply message to send to the message author. * * @var string */ public $reply = '';! /** * Weight of this category (used for sorting). * * @var int */ public $weight = 0;

contact.category.personal.ymlid: personallabel: 'Personal contact form'recipients: { }reply: ''weight: 0status: trueuuid: 43155e41-8a58-4264-ab00-be97a0736aa0langcode: endependencies: { }!!$contact_category = $this->entityManager() ->getStorage('contact_category') ->load('personal');!$contact_category->label();

contact.category.personal.ymlid: personallabel: 'Personal contact form'recipients: { }reply: ''weight: 0status: trueuuid: 43155e41-8a58-4264-ab00-be97a0736aa0langcode: endependencies: { }!!$config = \Drupal::config('contact.category.personal')->get();$label = $config['label'];!$label = \Drupal::config(‘contact.category.personal')->get('label');

Drush• Full Drush integration available

• Need Drush version 7.x

• Currently in dev branch of Drush

• List of Drush commands:http://www.drushcommands.com/drush-7x/config/config-list

Drush

Export config from the active configuration to the staging directory drush config-export drush cex

Drush

Import the staging configuration into the active configuration drush config-import drush cim

Workflow

• Staging config should become part of your codebase

• New configuration changes should be exported and integrated into code base

• Configuration in code should then be used to move configuration between servers

Dev Stage Live

export

deploy deploy

import import

Git

Config

Code

Git

Config

Code

Git

Config

Code

Workflow

Dev Stage Live

drush cex

deploy deploy

drush cim drush cim

Git

Config

Code

Git

Config

Code

Git

Config

Code

Drush Workflow

Roll Your Own Configurations

!!!!

Create a module that stores simple configurations

MyModule

• A module that integrates with the configuration management API

• Defines a single configuration item

• Defines a page to display the configuration

• Defines a form to change the configuration

MyModule Configuration• mymodule.info.yml file defines the module

• mymodule.settings.yml contains the module configuration

• mymodule.schema.yml contains information about the configuration item being defined

• mymodule.routing.yml defines routes to a page and a form

name: 'MyModule'type: moduledescription: 'My module'version: VERSIONcore: 8.x

mymodule.info.yml

configitem: ''

/config/install/mymodule.settings.yml

mymodule.settings: type: mapping label: 'My Module Settings' mapping: configitem: type: string label: 'A config item'

/config/schema/mymodule.schema.yml

mymodule.page: path: '/mymodule' defaults: _content: '\Drupal\mymodule\Controller\MyModuleController::description' requirements: _access: 'TRUE'!mymodule.admin: path: '/mymodule/edit' defaults: _form: '\Drupal\mymodule\Form\MyModuleAdminForm' requirements: _access: 'TRUE'

mymodule.routing.yml

MyModule Page

• mymodule.routing.yml defines the route to the page

• Destination MyModuleController::description() loads the configuration and displays it

namespace Drupal\mymodule\Controller;!use Drupal\Core\Controller\ControllerBase;!/** * Custom page. */class MyModuleController extends ControllerBase {! /** * An example page. * * @return string * A render array containing some page content. */ public function description() {! $mymodule_config = \Drupal::config('mymodule.settings');! $output = array();! $output['mymodule_output'] = array( '#markup' => t('The value of configitem is "!configitem"', array('!configitem' => $mymodule_config->get('configitem'))) );! return $output; }}

lib/Drupal/mymodule/Controller/MyModuleController.php

MyModule Form

• mymodule.routing.yml defines the route to the form

• Class MyModuleAdminForm defines a form that loads the configuration

• Configuration is saved upon submission of the form

namespace Drupal\mymodule\Form;!use Drupal\Core\Form\ConfigFormBase;!/** * Configure MyModule admin settings for this site. */class MyModuleAdminForm extends ConfigFormBase {! /** * Implements \Drupal\Core\Form\FormInterface::getFormID(). */ public function getFormID() { return 'mymodule_edit_form'; }! /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ public function buildForm(array $form, array &$form_state) { $config = $this->configFactory()->get('mymodule.settings');! $form['configitem'] = array( '#type' => 'textfield', '#title' => t('Config Settings'), '#default_value' => $config->get('configitem') );! return parent::buildForm($form, $form_state); }! /** * Implements \Drupal\Core\Form\FormInterface::submitForm(). */ public function submitForm(array &$form, array &$form_state) { $config = $this->configFactory()->get('mymodule.settings');! $config->set('configitem', $form_state['values']['configitem'])->save();! parent::submitForm($form, $form_state); }}

lib/Drupal/mymodule/Form/MyModuleAdminForm.php

! /** * Implements \Drupal\Core\Form\FormInterface::buildForm(). */ public function buildForm(array $form, array &$form_state) { $config = $this->configFactory()->get('mymodule.settings');! $form['configitem'] = array( '#type' => 'textfield', '#title' => t('Config Settings'), '#default_value' => $config->get('configitem') );! return parent::buildForm($form, $form_state); }

lib/Drupal/mymodule/Form/MyModuleAdminForm.php

!! /** * Implements \Drupal\Core\Form\FormInterface::submitForm(). */ public function submitForm(array &$form, array &$form_state) { $config = $this->configFactory()->get('mymodule.settings');! $config->set('configitem', $form_state['values']['configitem'])->save();! parent::submitForm($form, $form_state); }

lib/Drupal/mymodule/Form/MyModuleAdminForm.php

configitem: 'another value'

Drupal 7

• Configuration management has been back ported into Drupal 7

• Configuration Management module https://drupal.org/project/configuration

Resources• Creating Drupal 8.x modules

https://drupal.org/developing/modules/8

!• Configuration API in Drupal 8

https://drupal.org/node/1667894

!• Understanding Drupal 8's config entities

http://www.previousnext.com.au/blog/understanding-drupal-8s-config-entities

!• Configuration schema/metadata

https://drupal.org/node/1905070

!• Configuration inspector for Drupal 8

https://drupal.org/project/config_inspector

Drupal 8 CMI Needs You!

• Lots of work still needs to be done on CMI

• Go to http://drupal8cmi.org/ and pick an issue to work on

Me

• Phil Norton (@philipnorton42)

• #! code (www.hashbangcode.com)

• Technical Lead at Access

• Help run NWDUG

Recommended