Skip to content

Defining Node

Define a Plugin

Create a FlowDropNodeProcessor plugin in your module.

<?php

namespace Drupal\my_module\Plugin\FlowDropNodeProcessor;

use Drupal\flowdrop\Attribute\FlowDropNodeProcessor;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\flowdrop\Plugin\FlowDropNodeProcessor\AbstractFlowDropNodeProcessor;
use Drupal\flowdrop\DTO\ParameterBagInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

#[FlowDropNodeProcessor(
  id: "your_plugin_id",
  label: new TranslatableMarkup("Your Plugin Label"),
  type: "default",
  supportedTypes: ["default"],
  category: "your_category",
  description: "Brief description of what this plugin does",
  version: "1.0.0",
  tags: ["tag1", "tag2", "tag3"]
)]
class YourPlugin extends AbstractFlowDropNodeProcessor {

  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected LoggerChannelInterface $logger,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition
  ): static {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get("logger.channel.flowdrop"),
    );
  }

  protected function getLogger(): LoggerChannelInterface {
    return $this->logger;
  }

  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "input_data" => [
          "type" => "mixed",
          "description" => "Data input from workflow",
        ],
        "option" => [
          "type" => "string",
          "description" => "Configuration option",
          "default" => "default_value",
          "enum" => ["option1", "option2", "option3"],
        ],
      ],
    ];
  }

  protected function process(ParameterBagInterface $params): array {
    $inputData = $params->get("input_data");
    $option = $params->getString("option", "default_value");

    // Your processing logic here...

    return ["result" => $inputData];
  }
}

Required Parameters

Parameter Example Description
id "custom_processor" Unique identifier (lowercase, underscores)
label new TranslatableMarkup("Custom Processor") Human-readable name
type "default" Node type for frontend (usually "default")
supportedTypes ["default"] All supported node types
category "processing" Component category
Example

Input Component

#[FlowDropNodeProcessor(
  id: "custom_input",
  label: new TranslatableMarkup("Custom Input"),
  type: "default",
  supportedTypes: ["default"],
  category: "inputs",
  description: "Custom data input component",
  tags: ["input", "custom", "data"]
)]
class CustomInput extends AbstractFlowDropNodeProcessor {
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "value" => [
          "type" => "string",
          "description" => "The input value",
          "default" => "",
        ],
      ],
    ];
  }

  protected function process(ParameterBagInterface $params): array {
    return ["text" => $params->getString("value")];
  }
}

AI Model Component

#[FlowDropNodeProcessor(
  id: "custom_ai_model",
  label: new TranslatableMarkup("Custom AI Model"),
  type: "default",
  supportedTypes: ["default"],
  category: "models",
  description: "Custom AI model integration",
  version: "1.2.0",
  tags: ["ai", "model", "custom", "integration"]
)]
class CustomAiModel extends AbstractFlowDropNodeProcessor {
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "prompt" => [
          "type" => "string",
          "description" => "The input prompt",
        ],
        "model" => [
          "type" => "string",
          "description" => "Model identifier",
          "default" => "gpt-4",
          "enum" => ["gpt-4", "gpt-3.5-turbo"],
        ],
      ],
    ];
  }

  protected function process(ParameterBagInterface $params): array {
    $prompt = $params->getString("prompt");
    $model = $params->getString("model", "gpt-4");
    return ["response" => "AI response here"];
  }
}

Processing Component

#[FlowDropNodeProcessor(
  id: "data_transformer",
  label: new TranslatableMarkup("Data Transformer"),
  type: "default",
  supportedTypes: ["default"],
  category: "processing",
  description: "Transforms data between formats",
  tags: ["data", "transform", "processing"]
)]
class DataTransformer extends AbstractFlowDropNodeProcessor {
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "data" => [
          "type" => "mixed",
          "description" => "Data to transform",
        ],
        "format" => [
          "type" => "string",
          "description" => "Output format",
          "default" => "json",
          "enum" => ["json", "xml", "csv"],
        ],
      ],
    ];
  }

  protected function process(ParameterBagInterface $params): array {
    $data = $params->get("data");
    $format = $params->getString("format", "json");
    return ["transformed" => $data];
  }
}

Tool Component

#[FlowDropNodeProcessor(
  id: "custom_api",
  label: new TranslatableMarkup("Custom API"),
  type: "default",
  supportedTypes: ["default"],
  category: "tools",
  description: "Custom API integration",
  tags: ["api", "http", "integration", "custom"]
)]
class CustomApi extends AbstractFlowDropNodeProcessor {
  public function getParameterSchema(): array {
    return [
      "type" => "object",
      "properties" => [
        "endpoint" => [
          "type" => "string",
          "description" => "API endpoint URL",
          "format" => "uri",
        ],
        "method" => [
          "type" => "string",
          "description" => "HTTP method",
          "default" => "GET",
          "enum" => ["GET", "POST", "PUT", "DELETE"],
        ],
      ],
    ];
  }

  protected function process(ParameterBagInterface $params): array {
    $endpoint = $params->getString("endpoint");
    $method = $params->getString("method", "GET");
    return ["response" => []];
  }
}

Creating Plugin Instance

Use the plugin.manager.flowdrop_node_processor service to create plugin instances:

<?php
// Get service and create instance
$plugin_manager = \Drupal::service("plugin.manager.flowdrop_node_processor");
$plugin = $plugin_manager->createInstance("text_input", ["defaultValue" => "Hello"]);

// Available methods
$definitions = $plugin_manager->getDefinitions();           // Get all plugins
$definition = $plugin_manager->getDefinition("plugin_id");  // Get specific plugin
$exists = $plugin_manager->hasDefinition("plugin_id");      // Check if exists
Example
use Drupal\flowdrop\DTO\ParameterBag;

// In a service or controller
$plugin = $this->pluginManager->createInstance("chat_model");

// Create parameter bag with resolved values
$params = new ParameterBag([
  "prompt" => "Hello, how can I help you?",
  "model" => "gpt-4",
  "temperature" => 0.7,
]);

$output = $plugin->execute($params);

Entity Configuration

The config entity controls which parameters are input ports vs config fields:

# flowdrop_node_type.flowdrop_node_type.your_plugin.yml
id: your_plugin
label: 'Your Plugin'
executor_plugin: your_plugin_id
parameters:
  input_data:
    connectable: true    # Shows as input port
    configurable: false  # Not in config form
    required: true       # Must have value
  option:
    connectable: false   # Config only
    configurable: true   # Shows in config form
    required: false      # Optional

System Defaults

When entity config doesn't specify a flag:

Flag Default Meaning
connectable FALSE Not an input port
configurable FALSE Not shown in config form
required FALSE Optional parameter

ParameterBag Methods

Use typed accessors to retrieve parameter values:

protected function process(ParameterBagInterface $params): array {
  // Get any value
  $data = $params->get("data");

  // Typed accessors with defaults
  $name = $params->getString("name", "default");
  $count = $params->getInt("count", 0);
  $rate = $params->getFloat("rate", 0.5);
  $enabled = $params->getBool("enabled", FALSE);
  $items = $params->getArray("items", []);

  // Check if parameter exists
  if ($params->has("optional_param")) {
    // ...
  }

  return ["result" => $data];
}

Supported JSON Schema Properties

Property Description
type string, number, integer, boolean, array, object, mixed
description Human-readable description
default Default value
enum Array of allowed values
minimum, maximum Numeric constraints
minLength, maxLength String length constraints
pattern Regex pattern for strings
format email, uri, date, date-time, uuid, etc.

Note

For more detailed usage you can check out Flowdrop Node Processor.