Form library

1.0.0 2025-08-27 19:50 UTC

This package is not auto-updated.

Last update: 2025-08-28 15:14:27 UTC


README

A powerful, flexible PHP form library for PocketMine-MP servers with strict typing and modern PHP 8.3+ features.

Installation

composer require celestifyx/form

Quick Start

use pocketmine\player\Player;

use nerve\form\FormBuilder;
use nerve\form\forms\ModalForm;
use nerve\form\forms\MenuForm;
use nerve\form\forms\CustomForm;
use nerve\form\elements\Button;
use nerve\form\elements\Input;
use nerve\form\elements\Toggle;
use nerve\form\enums\ImageType;
use nerve\form\response\CustomFormResponse;

// Simple confirmation
$form = FormBuilder::confirm("Delete Item", "Are you sure?", function (Player $player): void {
    $player->sendMessage("Item deleted!");
});

// Menu with buttons
$form = FormBuilder::menu("Main Menu", "Choose an option:")
    ->append("Settings", "Help", "Exit")
    ->onSubmit(function (Player $player, Button $button): void {
        $player->sendMessage("Selected: " . $button->getText());
    });

$player->sendForm($form);

Form Types

Modal Form

Binary choice forms (Yes/No, OK/Cancel).

$form = FormBuilder::modal(
    "Confirmation",
    "Do you want to proceed?",

    function (Player $player, bool $response): void {
        match ($response) {
            true  => $player->sendMessage("Confirmed!"),
            false => $player->sendMessage("Cancelled!")
        };
    },

    "Yes",
    "No"
);

// Or use shorthand for confirmations
$form = FormBuilder::confirm("Delete", "Are you sure?", function (Player $player): void {
    // Handle confirmation
});

Menu Form

List of buttons for navigation.

$form = FormBuilder::menu("Game Menu", "Select an option:")
    ->append(
        FormBuilder::button("Play", FormBuilder::image("textures/ui/play.png", ImageType::PATH)),
        FormBuilder::button("Settings"),
        "Exit" // String buttons are auto-converted
    )
    ->onSubmit(function (Player $player, Button $button): void {
        match ($button->getText()) {
            "Play"     => $this->startGame($player),
            "Settings" => $this->openSettings($player),
            "Exit"     => $player->quit()
        };
    });

Custom Form

Complex forms with multiple input elements.

$form = FormBuilder::custom("Player Settings", [
    FormBuilder::label("Personal Information"),
    FormBuilder::input("Username", "Enter username", $player->getName()),
    FormBuilder::dropdown("Rank", ["Member", "VIP", "Admin"], 0),
    FormBuilder::toggle("Receive notifications", true),
    FormBuilder::slider("Volume", 0, 100, 1, 50),
    FormBuilder::stepSlider("Difficulty", ["Easy", "Normal", "Hard"], 1)
], function (Player $player, CustomFormResponse $response): void {
    $username = $response->getInput()->getValue();
    $rank = $response->getDropdown()->getSelectedOption();
    $notifications = $response->getToggle()->getValue();
    $volume = $response->getSlider()->getValue();
    $difficulty = $response->getStepSlider()->getSelectedOption();

    // Process form data
});

Server Settings Form

Special form type with icon support.

$form = FormBuilder::serverSettings(
    "Server Configuration",

    [
        FormBuilder::input("Server Name", "Enter name", "My Server"),
        FormBuilder::toggle("PvP Enabled", false)
    ],

    FormBuilder::image("textures/ui/server_icon.png", ImageType::PATH),

    function (Player $player, CustomFormResponse $response): void {
        // Handle server settings
    }
);

Direct Form Creation (Without FormBuilder)

You can create forms directly without using FormBuilder:

use nerve\form\forms\{ModalForm, MenuForm, CustomForm};
use nerve\form\elements\{Button, Input, Toggle};
use pocketmine\player\Player;
use nerve\form\response\CustomFormResponse;

// Direct modal form creation
$modal = new ModalForm(
    "Confirmation",
    "Are you sure?",

    function (Player $player, bool $response): void {
        match ($response) {
            true  => $player->sendMessage("Yes!"),
            false => $player->sendMessage("No!")
        };
    }
);

// Direct menu form creation
$menu = new MenuForm(
    "Main Menu",
    "Choose option:",

    [
        new Button("Play"),
        new Button("Exit")
    ],

    function (Player $player, Button $button): void {
        $player->sendMessage("Selected: " . $button->getText());
    }
);

// Direct custom form creation
$custom = new CustomForm(
    "Settings",

    [
        new Input("Name", "Enter name"),
        new Toggle("Notifications", true)
    ],

    function (Player $player, CustomFormResponse $response): void {
        $name = $response->getInput()->getValue();
        $notify = $response->getToggle()->getValue();
    }
);

Elements

Input

Text input field.

FormBuilder::input("Name", "Enter your name", "Default value")

Label

Display-only text.

FormBuilder::label("Section Header")

Toggle

Boolean switch.

FormBuilder::toggle("Enable feature", true) // default: true

Slider

Numeric range selector.

FormBuilder::slider("Volume", 0, 100, 5, 50) // min, max, step, default

Dropdown

Single selection from list.

FormBuilder::dropdown("Choose option", ["Option 1", "Option 2"], 0) // default index: 0

Step Slider

Discrete value selector.

FormBuilder::stepSlider("Difficulty", ["Easy", "Normal", "Hard"], 1)

Button

Menu form button with optional image.

FormBuilder::button("Click me", FormBuilder::image("icon.png"))

Image

Icon for buttons or server settings.

FormBuilder::image("https://example.com/icon.png") // URL (default)
FormBuilder::image("textures/ui/icon.png", ImageType::PATH) // Resource pack path

Advanced Usage

Form Chaining

$mainMenu = FormBuilder::menu("Main Menu", "Choose:")
    ->append("Settings", "About")
    ->onSubmit(function (Player $player, Button $button): void {
        match ($button->getText()) {
            "Settings" => $this->openSettings($player),
            "About"    => $this->showAbout($player)
        };
    });

private function openSettings(Player $player): void {
    FormBuilder::custom("Settings", [
        FormBuilder::toggle("Sound", true),
        FormBuilder::slider("FOV", 30, 120, 1, 90)
    ], function (Player $player, CustomFormResponse $response): void {
        // Save settings and return to main menu
        $this->saveSettings($player, $response);
        $this->openMainMenu($player);
    })->sendTo($player);
}

Response Handling

$form = FormBuilder::custom("Registration", [
    FormBuilder::input("Email", "user@example.com"),
    FormBuilder::input("Password", "Password", ""),
    FormBuilder::dropdown("Country", ["USA", "UK", "Canada"]),
    FormBuilder::toggle("Subscribe to newsletter")
], function (Player $player, CustomFormResponse $response): void {
    // Get values in order
    $email = $response->getInput()->getValue();
    $password = $response->getInput()->getValue();
    $country = $response->getDropdown()->getSelectedOption();
    $subscribe = $response->getToggle()->getValue();

    // Or get all values as array
    $values = $response->getValues(); // ["email", "password", "USA", true]

    // Validate and process
    match (filter_var($email, FILTER_VALIDATE_EMAIL)) {
        false   => $player->sendMessage("Invalid email!"),
        default => $this->registerUser($player, $email, $password, $country, $subscribe)
    };
});

Close Handling

$form = FormBuilder::menu("Important Choice", "This is important!")
    ->append("Accept", "Decline")
    ->onSubmit(function (Player $player, Button $button): void {
        // Handle selection
    })
    ->onClose(function (Player $player): void {
        $player->sendMessage("You must make a choice!");
        // Reopen form or take action
    });

Dynamic Forms

class ShopForm {
    function create(Player $player, string $category): MenuForm {
        $items = $this->getItemsByCategory($category)

        $buttons = array_map(fn ($item) => 
            FormBuilder::button($item->getName(), $item->getIcon()), 
            $items
        );

        return FormBuilder::menu("Shop - " . $category, "Select item:")
            ->append(...$buttons)
            ->onSubmit(function (Player $player, Button $button) use ($items): void {
                $selectedItem = $items[$button->getValue()];
                $this->purchaseItem($player, $selectedItem);
            });
    }
}

Error Handling

use InvalidArgumentException;

use pocketmine\form\FormValidationException;

try {
    $form = FormBuilder::custom("Test", [
        FormBuilder::slider("Invalid", 100, 0) // min > max
    ], function (Player $player, CustomFormResponse $response): void {});
} catch (InvalidArgumentException $e) {
    $player->sendMessage("Form error: " . $e->getMessage());
}

The library automatically validates form responses and throws FormValidationException for invalid data.

Features

  • Strict Typing: Full type safety with PHP 8.3+ features
  • Modern PHP: Uses match expressions, constructor promotion, readonly properties
  • Flexible API: Use FormBuilder or create forms directly
  • Method Chaining: Fluent interface for clean code
  • Automatic Validation: Built-in response validation
  • Error Handling: Comprehensive exception handling
  • Clean Code: No if/else chains, uses modern PHP patterns