Skip to content

Plugins Reference#

Entity Builder uses three plugin types: Operations, Validators, and Extensions.

Plugin Types Overview#

flowchart TB
    subgraph Plugins["Entity Builder Plugins"]
        OP[EbOperation<br/>Execute changes]
        VAL[EbValidator<br/>Cross-cutting validation]
        EXT[EbExtension<br/>Add YAML keys & operations]
    end

    subgraph Managers["Plugin Managers"]
        OPM[plugin.manager.eb_operation]
        VALM[plugin.manager.eb_validator]
        EXTM[plugin.manager.eb_extension]
    end

    OP --> OPM
    VAL --> VALM
    EXT --> EXTM

EbOperation Plugins#

Operations are the executable units that create, update, or delete Drupal entities.

Core Operations#

Plugin ID Label Type Description
create_bundle Create Bundle create Creates content type, vocabulary, media type
update_bundle Update Bundle update Updates bundle configuration
delete_bundle Delete Bundle delete Deletes a bundle
create_field Create Field create Creates field storage and instance
update_field Update Field update Updates field configuration
delete_field Delete Field delete Deletes field instance
hide_field Hide Field update Hides field from display
reorder_fields Reorder Fields update Changes field display order
configure_form_mode Configure Form Mode update Configures widget settings
configure_view_mode Configure View Mode update Configures formatter settings
create_menu Create Menu create Creates custom menu
create_menu_link Create Menu Link create Creates menu link

Extension Operations#

Module Plugin ID Description
eb_field_group create_field_group Creates field group
eb_field_group update_field_group Updates field group
eb_field_group delete_field_group Deletes field group
eb_pathauto create_pathauto_pattern Creates URL pattern
eb_auto_entitylabel configure_auto_entitylabel Configures auto labels

Operation Attribute#

1
2
3
4
5
6
#[EbOperation(
    id: 'my_operation',
    label: new TranslatableMarkup('My Operation'),
    description: new TranslatableMarkup('Description'),
    operationType: 'create',  // create, update, delete
)]

Operation Interfaces#

Interface Methods Purpose
OperationInterface setData(), getData(), validate() Base interface
FullOperationInterface execute() Executable operations
ReversibleOperationInterface rollback() Rollback support
PreviewableOperationInterface preview() Preview generation

Creating an Operation#

<?php

namespace Drupal\my_module\Plugin\EbOperation;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\eb\Attribute\EbOperation;
use Drupal\eb\PluginBase\OperationBase;
use Drupal\eb\Result\ExecutionResult;
use Drupal\eb\Result\PreviewResult;
use Drupal\eb\Result\RollbackResult;
use Drupal\eb\Result\ValidationResult;

#[EbOperation(
    id: 'create_my_entity',
    label: new TranslatableMarkup('Create My Entity'),
    description: new TranslatableMarkup('Creates a my entity'),
    operationType: 'create',
)]
class CreateMyEntityOperation extends OperationBase {

  /**
   * {@inheritdoc}
   */
  public function validate(): ValidationResult {
    $result = new ValidationResult();
    $this->validateRequiredFields(['entity_id', 'label'], $result);
    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function preview(): PreviewResult {
    $preview = new PreviewResult();
    $preview->addOperation(
      'create',
      'my_entity',
      $this->getDataValue('entity_id'),
      $this->t('Create @label', ['@label' => $this->getDataValue('label')])
    );
    return $preview;
  }

  /**
   * {@inheritdoc}
   */
  public function execute(): ExecutionResult {
    // Create the entity
    $entity = $this->entityTypeManager
      ->getStorage('my_entity')
      ->create([
        'id' => $this->getDataValue('entity_id'),
        'label' => $this->getDataValue('label'),
      ]);
    $entity->save();

    $result = new ExecutionResult(TRUE);
    $result->addMessage($this->t('Created @label', ['@label' => $entity->label()]));
    $result->setRollbackData(['entity_id' => $entity->id(), 'was_new' => TRUE]);
    return $result;
  }

  /**
   * {@inheritdoc}
   */
  public function rollback(): RollbackResult {
    $rollbackData = $this->getDataValue('_rollback_data', []);
    $entityId = $rollbackData['entity_id'] ?? $this->getDataValue('entity_id');

    $entity = $this->entityTypeManager->getStorage('my_entity')->load($entityId);
    if ($entity && ($rollbackData['was_new'] ?? FALSE)) {
      $entity->delete();
    }

    $result = new RollbackResult(TRUE);
    $result->addMessage($this->t('Deleted @id', ['@id' => $entityId]));
    return $result;
  }

}

EbValidator Plugins#

Validators check cross-cutting concerns across all operations.

Core Validators#

Plugin ID Description
dependency_validator Verifies entity/bundle/field existence
required_fields_validator Checks required properties
unique_name_validator Prevents naming conflicts
field_type_validator Validates field type exists
widget_compatibility_validator Checks widget-field compatibility
formatter_compatibility_validator Checks formatter-field compatibility
circular_dependency_validator Detects circular dependencies

Validator Attribute#

1
2
3
4
5
#[EbValidator(
    id: 'my_validator',
    label: new TranslatableMarkup('My Validator'),
    description: new TranslatableMarkup('Validates custom rules'),
)]

Creating a Validator#

<?php

namespace Drupal\my_module\Plugin\EbValidator;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\eb\Attribute\EbValidator;
use Drupal\eb\PluginBase\ValidatorBase;
use Drupal\eb\PluginInterfaces\OperationInterface;
use Drupal\eb\Result\ValidationResult;

#[EbValidator(
    id: 'naming_convention_validator',
    label: new TranslatableMarkup('Naming Convention Validator'),
    description: new TranslatableMarkup('Enforces naming conventions'),
)]
class NamingConventionValidator extends ValidatorBase {

  /**
   * {@inheritdoc}
   */
  public function validate(OperationInterface $operation, array $context = []): ValidationResult {
    $result = new ValidationResult();
    $operationType = $operation->getDataValue('operation');

    if ($operationType === 'create_bundle') {
      $bundleId = $operation->getDataValue('bundle_id');

      // Enforce prefix
      if (!str_starts_with($bundleId, 'myapp_')) {
        $result->addError(
          'Bundle ID must start with "myapp_".',
          'bundle_id',
          'naming_convention'
        );
      }
    }

    return $result;
  }

}

EbExtension Plugins#

Extensions add custom YAML keys, operations, and integration logic.

Core Extensions#

Module Plugin ID YAML Keys Operations
eb_field_group field_group field_group_definitions create_field_group, etc.
eb_pathauto pathauto - (bundle column) create_pathauto_pattern
eb_auto_entitylabel auto_entitylabel - (bundle columns) configure_auto_entitylabel

Extension Attribute#

1
2
3
4
5
6
7
8
#[EbExtension(
    id: 'my_extension',
    label: new TranslatableMarkup('My Extension'),
    description: new TranslatableMarkup('Adds my functionality'),
    yaml_keys: ['my_definitions'],
    operations: ['create_my_entity', 'update_my_entity'],
    module_dependencies: ['my_dependency'],
)]

Extension Interface#

Method Purpose
buildOperations(array $data) Convert YAML to operations
getOperationDependencies(array $operation, array $batch) Declare dependencies
detectChanges(array $operation, array $context) Change detection for sync mode
checkDependencies(array $operation) Verify dependencies exist
appliesTo(array $operation) Check if extension handles operation
getYamlKeys() Get YAML keys from plugin definition
getOperations() Get operations from plugin definition
extractConfig(string $entityType, string $bundle) Export existing config

Creating an Extension#

See the Creating Extensions guide for complete examples.

Plugin Discovery#

List All Plugins#

// Operations
$operationManager = \Drupal::service('plugin.manager.eb_operation');
$definitions = $operationManager->getDefinitions();

// Validators
$validatorManager = \Drupal::service('plugin.manager.eb_validator');
$definitions = $validatorManager->getDefinitions();

// Extensions
$extensionManager = \Drupal::service('plugin.manager.eb_extension');
$extensions = $extensionManager->getExtensions();

Create Plugin Instance#

// Create operation instance
$operation = $operationManager->createInstance('create_field', [
  'entity_type' => 'node',
  'bundle' => 'article',
  'field_name' => 'field_body',
  'field_type' => 'text_long',
]);

// Create validator instance
$validator = $validatorManager->createInstance('dependency_validator');

Extension Manager Methods#

$extensionManager = \Drupal::service('plugin.manager.eb_extension');

// Get extensions for operation type
$extensions = $extensionManager->getExtensionsForOperation('create_field_group');

// Get extensions for YAML key
$extensions = $extensionManager->getExtensionsForYamlKey('field_group_definitions');

// Get all definition keys from extensions
$keys = $extensionManager->getAllDefinitionKeys();

Plugin Namespace Locations#

Plugin Type Namespace Directory
EbOperation Drupal\{module}\Plugin\EbOperation src/Plugin/EbOperation/
EbValidator Drupal\{module}\Plugin\EbValidator src/Plugin/EbValidator/
EbExtension Drupal\{module}\Plugin\EbExtension src/Plugin/EbExtension/

Best Practices#

  1. Use base classes - Extend OperationBase, ValidatorBase, EbExtensionBase
  2. Implement all interfaces - Full operations need preview, execute, rollback
  3. Store rollback data - Enable undo functionality
  4. Handle exceptions - Use specific exception types with meaningful messages
  5. Log operations - Use the logger channel for audit trail
  6. Test thoroughly - Write unit tests for all plugin methods