# Defining Node

## Define a Plugin

Create a `FlowDropNodeProcessor` plugin in your module.

```php
<?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"],
        ],
      ],
    ];
  }

  public 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
    ```php
    #[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" => "",
            ],
          ],
        ];
      }

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

    ### AI Model Component
    ```php
    #[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"],
            ],
          ],
        ];
      }

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

    ### Processing Component
    ```php
    #[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"],
            ],
          ],
        ];
      }

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

    ### Tool Component
    ```php
    #[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"],
            ],
          ],
        ];
      }

      public 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
<?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

    ```php
    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:

```yaml
# 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:

```php
public 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](../flowdrop-node-processor.md).
