Last updated January 25, 2015. Created on October 11, 2012.
Edited by TravisCarden, Kyna, gausarts, gnuget. Log in to edit this page.

This page provides an example of how to create a configuration entity type, with administration management pages, for Drupal 8. For an introduction to the concepts of simple configuration vs. configuration entities, see https://drupal.org/node/2120523

Set up module and admin menu entry

example/example.info.yml

name: Example
type: module
description: 'Manages example configuration.'

Routing

example/example.routing.yml

The routing.yml file defines the routes for the management pages: list, add, edit, delete.

example.list:
  path: '/admin/config/system/example'
  defaults:
    _entity_list: 'example'
    _title: 'Example Configuration'
  requirements:
    _permission: 'administer site configuration'

example.add:
  path: '/admin/config/system/example/add'
  defaults:
    _entity_form: 'example.add'
    _title: 'Add example'
  requirements:
    _permission: 'administer site configuration'

entity.example.edit_form:
  path: '/admin/config/system/example/{example}'
  defaults:
    _entity_form: 'example.edit'
    _title: 'Edit example'
  requirements:
    _permission: 'administer site configuration'

entity.example.delete_form:
  path: '/admin/config/system/example/{example}/delete'
  defaults:
    _entity_form: 'example.delete'
    _title: 'Delete example'
  requirements:
    _permission: 'administer site configuration'

example/example.links.action.yml

This makes the "Add" link appear on the List page.

example.add:
  route_name: 'example.add'
  title: 'Add Example'
  appears_on:
    - example.list

Entity type classes

example/src/ExampleInterface.php

Assuming that your configuration entity has properties, you will need to define some set/get methods on an interface.

<?php
/**
 * @file
 * Contains \Drupal\example\ExampleInterface.
 */

namespace Drupal\example;

use
Drupal\Core\Config\Entity\ConfigEntityInterface;

/**
 * Provides an interface defining a Example entity.
 */
interface ExampleInterface extends ConfigEntityInterface {
 
// Add get/set methods for your configuration properties here.
}
?>

example/src/Entity/Example.php

This file defines the configuration entity class.

<?php
/**
 * @file
 * Contains \Drupal\example\Entity\Example.
 */

namespace Drupal\example\Entity;

use
Drupal\Core\Config\Entity\ConfigEntityBase;
use
Drupal\example\ExampleInterface;

/**
 * Defines the Example entity.
 *
 * @ConfigEntityType(
 *   id = "example",
 *   label = @Translation("Example"),
 *   handlers = {
 *     "list_builder" = "Drupal\example\Controller\ExampleListBuilder",
 *     "form" = {
 *       "add" = "Drupal\example\Form\ExampleForm",
 *       "edit" = "Drupal\example\Form\ExampleForm",
 *       "delete" = "Drupal\example\Form\ExampleDeleteForm"
 *     }
 *   },
 *   config_prefix = "example",
 *   admin_permission = "administer site configuration",
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "label",
 *   },
 *   links = {
 *     "edit-form" = "/admin/config/system/example/{example}",
 *     "delete-form" = "/admin/config/system/example/{example}/delete"
 *   }
 * )
 */
class Example extends ConfigEntityBase implements ExampleInterface {

 
/**
   * The Example ID.
   *
   * @var string
   */
 
public $id;

 
/**
   * The Example label.
   *
   * @var string
   */
 
public $label;

 
// Your specific configuration property get/set methods go here,
  // implementing the interface.
}
?>

The admin_permission key automatically allows all access for users with that permission. In case more logic is required, a custom access controller can be specified.

Configuration schema file

example/config/schema/example.schema.yml

example.example.*:
  type: config_entity
  label: 'Example config'
  mapping:
    id:
      type: string
      label: 'ID'
    label:
        type: label
        label: 'Label'

in example.schema.yml add the properties/attributes defined in \Drupal\example\Entity\Example

example.example.* is a configuration variable to refer to our class properties/attributes and you can specify different variable name for your entity by adding "config_prefix" e.g :


@ConfigEntityType(
..
... config_prefix = "variable_name" ...

then you can refer to it like the following :

example.variable_name.*: ....

for more information on Configuration schema see Configuration schema/metadata

Entity controller classes

example/src/Form/ExampleForm.php

<?php
/**
 * @file
 * Contains \Drupal\example\Form\ExampleForm.
 */

namespace Drupal\example\Form;

use
Drupal\Core\Entity\EntityInterface;
use
Drupal\Core\Entity\EntityForm;
use
Symfony\Component\DependencyInjection\ContainerInterface;
use
Drupal\Core\Entity\Query\QueryFactory;
use
Drupal\Core\Form\FormStateInterface;

class
ExampleForm extends EntityForm {
 
 
/**
   * @param \Drupal\Core\Entity\Query\QueryFactory $entity_query
   *   The entity query.
   */
 
public function __construct(QueryFactory $entity_query) {
   
$this->entityQuery = $entity_query;
  }

 
/**
   * {@inheritdoc}
   */
 
public static function create(ContainerInterface $container) {
    return new static(
     
$container->get('entity.query')
    );
  }

 
/**
   * {@inheritdoc}
   */
 
public function form(array $form, FormStateInterface $form_state) {
   
$form = parent::form($form, $form_state);

   
$example = $this->entity;

   
$form['label'] = array(
     
'#type' => 'textfield',
     
'#title' => $this->t('Label'),
     
'#maxlength' => 255,
     
'#default_value' => $example->label(),
     
'#description' => $this->t("Label for the Example."),
     
'#required' => TRUE,
    );
   
$form['id'] = array(
     
'#type' => 'machine_name',
     
'#default_value' => $example->id(),
     
'#machine_name' => array(
       
'exists' => array($this, 'exist'),
      ),
     
'#disabled' => !$example->isNew(),
    );

   
// You will need additional form elements for your custom properties.

   
return $form;
  }

 
/**
   * {@inheritdoc}
   */
 
public function save(array $form, FormStateInterface $form_state) {
   
$example = $this->entity;
   
$status = $example->save();

    if (
$status) {
     
drupal_set_message($this->t('Saved the %label Example.', array(
       
'%label' => $example->label(),
      )));
    }
    else {
     
drupal_set_message($this->t('The %label Example was not saved.', array(
       
'%label' => $example->label(),
      )));
    }

   
$form_state->setRedirect('example.list');
  }

  public function
exist($id) {
   
$entity = $this->entityQuery->get('example')
      ->
condition('id', $id)
      ->
execute();
    return (bool)
$entity;
  }
}
?>

example/src/Controller/ExampleListBuilder.php

<?php
/**
 * @file
 * Contains \Drupal\example\Controller\ExampleListBuilder.
 */

namespace Drupal\example\Controller;

use
Drupal\Core\Config\Entity\ConfigEntityListBuilder;
use
Drupal\Core\Entity\EntityInterface;

/**
 * Provides a listing of Example.
 */
class ExampleListBuilder extends ConfigEntityListBuilder {

 
/**
   * {@inheritdoc}
   */
 
public function buildHeader() {
   
$header['label'] = $this->t('Example');
   
$header['id'] = $this->t('Machine name');
    return
$header + parent::buildHeader();
  }

 
/**
   * {@inheritdoc}
   */
 
public function buildRow(EntityInterface $entity) {
   
$row['label'] = $this->getLabel($entity);
   
$row['id'] = $entity->id();

   
// You probably want a few more properties here...

   
return $row + parent::buildRow($entity);
  }

}
?>

example/src/Form/ExampleDeleteForm.php

<?php
/**
 * @file
 * Contains \Drupal\example\Form\ExampleDeleteForm.
 */

namespace Drupal\example\Form;

use
Drupal\Core\Entity\EntityConfirmFormBase;
use
Drupal\Core\Url;
use
Drupal\Core\Form\FormStateInterface;

/**
 * Builds the form to delete a Example.
 */

class ExampleDeleteForm extends EntityConfirmFormBase {

 
/**
   * {@inheritdoc}
   */
 
public function getQuestion() {
    return
$this->t('Are you sure you want to delete %name?', array('%name' => $this->entity->label()));
  }

 
/**
   * {@inheritdoc}
   */
 
public function getCancelUrl() {
    return new
Url('example.list');
  }

 
/**
   * {@inheritdoc}
   */
 
public function getConfirmText() {
    return
$this->t('Delete');
  }

 
/**
   * {@inheritdoc}
   */
 
public function submitForm(array &$form, FormStateInterface $form_state) {
   
$this->entity->delete();
   
drupal_set_message($this->t('Category %label has been deleted.', array('%label' => $this->entity->label())));

   
$form_state->setRedirectUrl($this->getCancelUrl());
  }
}
?>

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

ivanjaros’s picture

Isn't there a config file missing?

vacho’s picture

In file example/example.routing.yml

this code:

example.add:
  path: '/admin/config/system/example/add'
  defaults:
    _entity_form: example.add
    _title: 'Add example'
  requirements:
    _entity_access: 'example.add'

y replace by

example.add:
  path: '/admin/config/system/example/add'
  defaults:
    _entity_form: example.add
    _title: 'Add example'
  requirements:
    _permission: 'administer content types'

similar to what I found at Node entity.
Otherwise I can not "add" because I do not find prevent permissions where set

jienckebd’s picture

Great tutorial!

In example/src/Entity/Example.php, I think:

"list_builder" = "Drupal\example\ExampleListBuilder",

should be:

"list_builder" = "Drupal\example\Controller\ExampleListBuilder",

Kyna’s picture

Nice tuto !

And I confirm :
"list_builder" = "Drupal\example\ExampleListBuilder",
"list_builder" = "Drupal\example\Controller\ExampleListBuilder",

And :
public function submitForm(array $form, FormStateInterface $form_state) {
public function submitForm(array &$form, FormStateInterface $form_state) {

I have edited this tutorial for fix this errors.