Everything Is Entity or Entity is Everything in Drupal 8

By yuseferi, 7 October, 2016
Everything Is Entity or Entity is Everything in Drupal 8

Much like previous versions of Drupal, version 8 of the CMS revolves around the concept of Entities. These are objects that have an ID, Language, Type, and Storage. Some optional properties are URLs, Bundles, and labels. They can be viewed, loaded, created, saved, and deleted, as well as have access permissions set for them. Most things in Drupal are entities, such as Users, Nodes, or Blocks. Many of the core services provide functionality for interacting with entities, and a great deal of caching functionality serves to make entities perform better.

Most entities exposed to the user will also be fieldable, which means any amount of fields can be attached, transversed, and modified either by code or in the admin GUI.

Entity Inheritance

While all entities in Drupal inherit basic functionality from the core entity class, they tend to fall into two different categories: configuration entities and content entities. Configuration entities provide storage for variables that inform the structure and functionality of Drupal sites - how the site serves content. These are things like Languages, Filters, Database Logs and the like. Content entities provide storage for what the site serves, as dictated by what entity they are and how configuration entities modify their behavior.

Core Entities

Configuration Entities

While no means a comprehensive list, these are many of the core configuration entities that are important to the functioning of a Drupal site.

  • Dates & Times

  • Display Modes - Display modes will be covered in depth later, but suffice to say there are View and Edit (Form) modes for most entities.

  • Content Configurations - Almost all Content Entities have a Configuration Entities to go alongside them to configure how they function.

  • GUI Editors

  • Field Configurations - When fields get attached to an entity, they'll have a Configuration Entity as well.

  • Filters

  • Languages

  • Search

  • System - This is the general configuration for the site.

  • Tests

  • Views

Content Entities

  • Feeds

  • Blocks

  • Comments

  • Contacts

  • Files

  • Menu Links

  • Nodes

  • Shortcuts

  • Taxonomy

  • Users

When You Need a Custom Entity

If most content on a site is just a collection of fields, why would you need any other entity than Content entities (nodes)? The answer is that not all entities need to be user-editable, revisionable, and translatable - core things like Users or new features such as tickets in an Events system and global configuration in a custom admin menu.

Here’s a handy checklist to use:

  • Fields are not editable by the user and instead are manipulated by custom code

  • Revisions are not needed

  • Translation is not needed

  • Custom functions control the creation, editing, and saving of the data

Building a Custom Entity

Custom entities in Drupal 8 are a bit clearer than in Drupal 7 since they always contain two things in a single file:

  1. A class annotation that extends any of the classes that extend \Drupal\Component\Annotation\AnnotationInterface.

  2. A class that extends the base \Drupal\Core\Entity\EntityInterface

This means that the class documentation has an @EntityTypeOrSomeSuch annotation declaring configuration about the custom entity, and implements the functions described in the Drupal EntityInterface PHP Interface file. Entities reside in the my_module\Entity namespace - the directory equivalent of my_module/src/Entity/.

Here’s an example entity class for creating Global Admin Configs stored as field values:

<?php

namespace Drupal\admin_config\Entity;

use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\ContentEntityInterface;

/**
* Defines the ContentConfig entity class.
*
* This is a basic content entity that can have fields attached to it.
* It is meant to be used for one-off storage such as site-wide content
* that needs to be stored in the database instead of interfacing with Drupal's
* configuration mechanisms.
*
* @ContentEntityType(
* id = "content_config",
* label = @Translation("Content Config"),
* label_singular = @Translation("content config"),
* label_plural = @Translation("content configs"),
* label_count = @PluralTranslation(
* singular = "@count content config",
* plural = "@count content configs"
* ),
* bundle_label = @Translation("Content Config bundle"),
* bundle_entity_type = "content_config_bundle",
* handlers = {
* "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
* "storage_schema" = "Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema",
* "form" = {
* "default" = "Drupal\admin_config\Form\ContentConfigForm",
* },
* },
* base_table = "content_config",
* data_table = "content_config_field_data",
* translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "bundle" = "bundle",
* "label" = "label",
* "langcode" = "langcode",
* "uuid" = "uuid",
* },
* )
*/
class ContentConfig extends ContentEntityBase implements ContentEntityInterface {

 /**
 * {@inheritdoc}
 */
 public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) {
   if (!empty($values['id'])) {
     parent::__construct($values, $entity_type, $bundle, $translations);
     return;
   }

   $entity_type_manager = $this->entityTypeManager();
   $field_storage_config = $entity_type_manager
     ->getStorage('field_storage_config');
   $field_config = $entity_type_manager
     ->getStorage('field_config');
   $form_display = $entity_type_manager
     ->getStorage('entity_form_display');
   $view_display = $entity_type_manager
     ->getStorage('entity_view_display');
   $field_configs = $field_config->loadByProperties([
     'entity_type' => 'content_config',
     'bundle' => $bundle,
   ]);

   if (empty($field_configs)) {
     // Create the implementation.
     \Drupal::moduleHandler()
       ->invokeAll("admin_config_$bundle", [
         $field_storage_config,
         $field_config,
         $form_display,
         $view_display,
       ]);
   }

   parent::__construct($values, $entity_type, $bundle, $translations);
 }

}

This entity exists as a content entity with fields and full sets of storage, but relies on a newly created hook, hook_admin_config_BUNDLE, to create the field storage, config, form, and view displays. This custom entity would be useful in a case where we’d want to programmatically provide fields for bundle content implementations, like in the case of a custom admin menu with custom fields for storing globals such as images and text.

Additional Resources
Entity API - Drupal 8

 

(+)