Yet another web developer blog

How to create a custom Drupal Entity Type in a single PHP file

Most of instructions about creating a new custom Drupal Entity Type describes that you need to create a lot of files: routing, links, form, list builder, interfaces, etc.

But if you need to create just a simple custom Content Entity Type for your own needs and with mostly default functionality, you can simply describe it in a one PHP file, with reuse of Drupal Core classes for all other functionality (User Interface, Permissions, List Builder, etc)!

Here is the example:

<?php

namespace Drupal\my_module\Entity;

use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\EntityTypeInterface;

/**
 * Defines the MyCustomItem entity.
 *
 * @ingroup my_module
 *
 * @ContentEntityType(
 *   id = "my_module_item",
 *   label = @Translation("My module item"),
 *   base_table = "my_module_item",
 *   entity_keys = {
 *     "id" = "id",
 *     "published" = "status",
 *   },
 *   handlers = {
 *     "access" = "Drupal\entity\EntityAccessControlHandler",
 *     "form" = {
 *       "add" = "Drupal\Core\Entity\ContentEntityForm",
 *       "edit" = "Drupal\Core\Entity\ContentEntityForm",
 *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
 *     },
 *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder.php",
 *     "local_action_provider" = {
 *       "collection" = "Drupal\entity\Menu\EntityCollectionLocalActionProvider",
 *     },
 *     "permission_provider" = "Drupal\entity\EntityPermissionProvider",
 *     "route_provider" = {
 *       "default" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
 *     },
 *     "views_data" = "Drupal\views\EntityViewsData",
 *   },
 *   persistent_cache = TRUE,
 *   translatable = FALSE,
 *   admin_permission = "my_module administer",
 *   links = {
 *     "canonical" = "/admin/structure/my-module-items/{my_module_item}",
 *     "collection" = "/admin/structure/my-module-items",
 *     "add-form" = "/admin/structure/my-module-items/add",
 *     "edit-form" = "/admin/structure/my-module-items/{my_module_item}/edit",
 *     "delete-form" = "/admin/structure/my-module-items/{my_module_item}/delete",
 *   },
 * )
 */
// On Drupal 8.4+ you can also use `extend EditorialContentEntityBase` that
// provides `Changed`, `Published` and `RevisionLog` properties by default.
class MyModuleItem extends ContentEntityBase implements EntityPublishedInterface {

  // You can remove `implements EntityPublishedInterface`,
  // `EntityPublishedTrait`, `publishedBaseFieldDefinitions() calls, 
  // and `"published" = "status"` annotation, if you don't need 
  // such functionality in your entity type.
  use EntityPublishedTrait;

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields = parent::baseFieldDefinitions($entity_type);

    // Add the published field.
    $fields += static::publishedBaseFieldDefinitions($entity_type);

    $fields['my_custom_string'] = BaseFieldDefinition::create('string')
      ->setRequired(TRUE)
      ->setLabel('My custom string')
      ->setSettings([
        'max_length' => 32,
      ]);

    return $fields;
  }

}

So it reuses default classes, provided by Drupal Core, for all handlers, and all works out of the box!

And if you need to customize some handlers and other parts - just point to your custom classes in definition annotation and clear the cache.

Full list of options, that can be used in Entity Declaration block, you can lookup here: Structure of an Entity annotation.

More documentation about customizing handlers you can find in the Drupal.org article: Creating a content entity type in Drupal 8.

Tags