By: Raman
April 19 2018

How to create Custom Entity in Drupal 8

Entities in Drupal provide a structured way of storing and managing data. With the inclusion of Entity API in Drupal 8, it becomes even easier to manage existing, and creating new entities. Similar entities are grouped into Entity Types, which further have subtypes known as Bundles, to which fields can be attached.

For example, the node entity type has two bundles — Articles, and Basic page. The bundles share some common properties and also have some fields that are unique to them.

Drupal core provides with many built-in entity types and also allows us to define custom entity types and bundles. There are two types of entity types — Content Entities and Configuration Entities.

Configuration Entities Content Entities

They store data about your Drupal site (metadata)

They store data on your Drupal site

Non-Fieldable

Fieldable

Non-Revisionable

Revisionable

Drupal core includes action, block, block_comment_type, comment_type, contact_type, contact_form, configurable_language, editor, field_storage_config, field_config, filter_format, image_style, menu, language_content_settings, migration, node_type, rdf_mapping, search_page, response_image_style, taxonomy_vocabulary, shortcut_set, tour, user_role, and view

Drupal core includes aggregator_feed, aggregator_item, block_content, comment, contact_message, file, node, menu_link_content, shortcut, taxonomy_term, and user

When to use Custom Entities?

Before actually defining custom entity types, let us understand the situations where they should be used:

  1. Boost in Performance

    In most cases, nodes can be used to store any kind of content. However, nodes implement tons of hooks and add the functionalities that might not be required. Moreover, all the content data is stored in a single database table. This can cause performance issues when the number of content items increases. Here, custom entities can be used to boost the performance
     
  2. Build a better admin UX

    At times, it is necessary to provide better administration forms and menus for the site builders as well as the content editors. The menus, paths, and form displays can be configured as required.
     
  3. Defining custom functionalities

    We can implement custom methods to our entity types, add custom menu items, and paths. We may also define custom data storage and workflows as per requirements.

Custom entity types allow us to define custom functionality, boost performance, and have total control over the structure of data, admin menus, paths, and storage schema.

Creating Custom Entity using Drupal Console

To define custom entities, we must create a module and then add a custom entity. Drupal Console can be used to generate most of the boilerplate code, however, some knowledge of object-oriented programming, PHP, and YML is required to be able to add custom functionality to our entity.

Let's consider an example of a Book entity with the following properties — Title, ISBN, Author(s), and Price, with two bundles or subtypes — EBook (File size, Download URL) and PaperBook (Weight, In Stock).

  1. Navigate to the root directory of your Drupal site.
    ​​​​​​​$ cd /var/www/html/drupal8
  2. Generate module boilerplate using Drupal Console.

    $ drupal generate:module
  3. Answer a series of questions generated by the module generator.

    // Welcome to the Drupal module generator
    ​
    Enter the new module name: > Books
    ​
    Enter the module machine name [books]: >
    ​
    Enter the module Path [modules/custom]: >
    ​
    Enter module description [My Awesome Module]: > Provides custom entity to store information about books
    ​
    Enter package name [Custom]: >
    ​
    Enter Drupal Core version [8.x]: >
    ​
    Do you want to generate a .module file? (yes/no) [yes]: >
    ​
    Define module as feature (yes/no) [no]: >
    ​
    Do you want to add a composer.json file to your module? (yes/no) [yes]: >
    ​
    Would you like to add module dependencies? (yes/no) [no]: >
    ​
    Do you want to generate a unit test class? (yes/no) [yes]: > no
    ​
    Do you want to generate a themeable template? (yes/no) [yes]: > no
    ​
    Do you want proceed with the operation? (yes/no) [yes]: >
    ​
    Generated or updated files
    Generation path: /var/www/html/drupal8
    1 - /var/www/html/drupal8/modules/custom/books/books.info.yml
    2 - /var/www/html/drupal8/modules/custom/books/books.module
    3 - /var/www/html/drupal8/modules/custom/books/composer.json
    ​
    Generated lines: "43"
  4. Generate custom entity using Drupal Console. For this example, we are creating a content entity type. Configuration entity type can be created using drupal generate:entity:config 

    $ drupal generate:entity:content
  5. Answer a series of questions generated by the entity generator.

    // Welcome to the Drupal Content Entity generator
    Enter the module name [addtoany]: > books
    ​
    Enter the class of your new content entity [DefaultEntity]: > BookEntity
    ​
    Enter the machine name of your new content entity [book_entity]: >
    ​
    Enter the label of your new content entity [Book entity]: >
    ​
    Enter the base-path for the content entity routes [/admin/structure]: >
    ​
    Do you want this (content) entity to have bundles? (yes/no) [no]: > yes
    ​
    Is your entity translatable? (yes/no) [yes]: >
    ​
    Is your entity revisionable? (yes/no) [yes]: >
    ​
    // generate:entity:config
    ​
    Enter the base-path for the config entity routes [/admin/structure]:>
    ​
    Generated or updated filesGeneration path: /var/www/html/drupal8
    1 - modules/custom/books/books.permissions.yml
    2 - modules/custom/books/books.links.menu.yml
    3 - modules/custom/books/books.links.task.yml
    4 - modules/custom/books/books.links.action.yml
    5 - modules/custom/books/src/BookEntityAccessControlHandler.php
    6 - modules/custom/books/src/BookEntityTranslationHandler.php
    7 - modules/custom/books/src/Entity/BookEntityInterface.php
    8 - modules/custom/books/src/Entity/BookEntity.php
    9 - modules/custom/books/src/BookEntityHtmlRouteProvider.php
    10 - modules/custom/books/src/Entity/BookEntityViewsData.php
    11 - modules/custom/books/src/BookEntityListBuilder.php
    12 - modules/custom/books/src/Form/BookEntitySettingsForm.php
    13 - modules/custom/books/src/Form/BookEntityForm.php
    14 - modules/custom/books/src/Form/BookEntityDeleteForm.php
    15 - modules/custom/books/book_entity.page.inc
    16 - modules/custom/books/templates/book_entity.html.twig
    17 - modules/custom/books/src/Form/BookEntityRevisionDeleteForm.php
    18 - modules/custom/books/src/Form/BookEntityRevisionRevertTranslationForm.php
    19 - modules/custom/books/src/Form/BookEntityRevisionRevertForm.php
    20 - modules/custom/books/src/BookEntityStorage.php
    21 - modules/custom/books/src/BookEntityStorageInterface.php
    22 - modules/custom/books/src/Controller/BookEntityController.php
    23 - modules/custom/books/templates//book-entity-content-add-list.html.twig
    24 - modules/custom/books/books.module
    25 - modules/custom/books/books.module
    26 - modules/custom/books/config/schema/book_entity_type.schema.yml
    27 - modules/custom/books/books.links.menu.yml
    28 - modules/custom/books/books.links.action.yml
    29 - modules/custom/books/src/Entity/BookEntityTypeInterface.php
    30 - modules/custom/books/src/Entity/BookEntityType.php
    31 - modules/custom/books/src/BookEntityTypeHtmlRouteProvider.php
    32 - modules/custom/books/src/Form/BookEntityTypeForm.php
    33 - modules/custom/books/src/Form/BookEntityTypeDeleteForm.php
    34 - modules/custom/books/src/BookEntityTypeListBuilder.php
    
    Generated lines: "1978"
    Directory structure of the generated module
    Directory Structure of the generated Module
  6. Drupal Console has generated the module under modules/custom/books. Now, to add custom properties to the Book entity type, open up the file modules/custom/books/src/Entity/BookEntity.php in any IDE or text editor and add the following lines of code under the baseFieldDefinitions method of the class BookEntity. 

     $fields['isbn'] = BaseFieldDefinition::create('integer')
         ->setLabel(t('ISBN'))
         ->setDescription(t('ISBN of the Book'))
         ->setRevisionable(TRUE)
         ->setTranslatable(TRUE)
         ->setDisplayOptions('form', array(
           'type' => 'string_textfield',
           'settings' => array(
             'display_label' => TRUE,
           ),
         ))
        ->setDisplayOptions('view', array(
           'label' => 'hidden',
           'type' => 'string',
         ))
         ->setDisplayConfigurable('form', TRUE)
         ->setRequired(TRUE);    
        
       $fields['author'] = BaseFieldDefinition::create('string')
         ->setLabel(t('Author'))
         ->setDescription(t('Author(s) of the book'))
         ->setRevisionable(TRUE)
         ->setTranslatable(TRUE)
         ->setDisplayOptions('form', array(
           'type' => 'string_textfield',
           'settings' => array(
             'display_label' => TRUE,
           ),
         ))
        ->setDisplayOptions('view', array(
           'label' => 'hidden',
           'type' => 'string',
         ))
         ->setDisplayConfigurable('form', TRUE)
         ->setRequired(TRUE);
    
    
       $fields['price'] = BaseFieldDefinition::create('float')
         ->setLabel(t('Price'))
         ->setDescription(t('Price of the Book'))
         ->setRevisionable(TRUE)
         ->setTranslatable(TRUE)
         ->setDisplayOptions('form', array(
           'type' => 'string_textfield',
           'settings' => array(
             'display_label' => TRUE,
           ),
         ))
        ->setDisplayOptions('view', array(
           'label' => 'hidden',
           'type' => 'string',
         ))
         ->setDisplayConfigurable('form', TRUE)
         ->setRequired(TRUE);
  7. Various other aspects of the entity can be customized such as admin menus, paths, and forms, constraints and properties can be applied to the fields. Refer the docs for complete reference. For now, let’s install the newly created module.

$ drush en books -y

or

$ drupal module:install books

In case you make any changes to the entity after installing the module, make sure to run drupal update:entities to apply the updates.

Creating Bundles and Adding Fields to Them

Bundles can be created and fields can be attached to them using the UI.

  1. Navigate to Manage → Structure and click on “Add Book Entity type”
     
  2. Add a suitable label and click on “Save”
     
  3. Click on “Manage Fields” from the drop-down menu and add fields to the bundle as required.
    ​​​​​​​
  4. Repeat this process for all the bundles

You can now create entities of your custom entity types. By default, the menu for creating new entity will be present under admin/structure/{your-custom-entity}.This can be altered by changing the parent key under entity.book_entity.collection in the modules/custom/books/books.links.menu.yml file.

form displays of paper book and EBook bundles
Form displays of the paper book and ebook bundles

Conclusion

Entities are building blocks and integral of a Drupal site. Custom entity types allow us to define custom functionality, boost performance, and have total control over the structure of data, admin menus, paths, and storage schema. They can be created with little or no effort using the Drupal Console.

Let us know in the comments below how your custom entity helped you out.