承接 kavalhub/form-generator 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

kavalhub/form-generator

Composer 安装命令:

composer require kavalhub/form-generator

包简介

Easily create, validate, and display forms.

README 文档

README

PHP-библиотека для программного создания HTML-форм, привязки данных из запроса, валидации и рендеринга с опциональным Bootstrap-декоратором.

Требования

  • PHP ^8.2
  • Composer

Установка

composer require kavalhub/form-generator

Laravel (опционально)

composer require kavalhub/form-generator-laravel

Быстрый старт

use Kavalhub\FormGenerator\Html\Form;
use Kavalhub\FormGenerator\Html\InputSubmit;
use Kavalhub\FormGenerator\Html\InputText;
use Kavalhub\FormGenerator\Request\ElementRequest;
use Kavalhub\FormGenerator\Validator\ElementValidator;
use Kavalhub\FormGenerator\Validator\Interface\ElementValidatorInterface;

$form = (new Form('contact'))
    ->addElement(
        (new InputText('email'))->setRequired()->setPlaceholder('Email')
    )
    ->addElement(
        (new InputSubmit('send'))->setDefaultValue('Отправить')
    );

/** @var ElementValidatorInterface $validator */
$validator = new ElementValidator(new ElementRequest());
$submit = $form->getByName('send');

if ($validator->checkSubmit($submit) && $validator->handle($form)) {
    // данные валидны
}

echo $form->render();

Точки расширения

Библиотека построена на интерфейсах — реализации можно подменять:

Интерфейс Назначение Реализации в пакете
RequestInterface Источник данных формы ElementRequest, ArrayRequest, PostOnlyRequest
ElementValidatorInterface Валидация и bind ElementValidator
DecoratorInterface Рендеринг с темой AbstractDecorator; Bootstrap — пакет form-generator-bootstrap
AjaxRenderStrategyInterface HTML/CSS для AJAX-патчей NullAjaxRenderStrategy; Bootstrap — в bootstrap-пакете
ElementEventDispatcher События элементов (связанные select, фильтры) ElementChangedEvent, слушатели в приложении

Подробнее: docs/element-events.md, docs/custom-templates.md.

flowchart LR
    App[Приложение] --> RequestInterface
    App --> ElementValidatorInterface
    App --> DecoratorInterface
    App --> AjaxRenderStrategyInterface
    RequestInterface --> ElementRequest
    RequestInterface --> PostOnlyRequest
    RequestInterface --> LaravelRequestAdapter
    ElementValidatorInterface --> ElementValidator
    ElementValidatorInterface --> LaravelElementValidator
    DecoratorInterface --> AbstractDecorator
    AjaxRenderStrategyInterface --> NullAjaxRenderStrategy
    DecoratorInterface --> BootstrapPackage[form-generator-bootstrap]
    AjaxRenderStrategyInterface --> BootstrapPackage
Loading

Request: GET, POST и свои адаптеры

ElementRequest — по умолчанию ($_REQUEST)

Читает GET + POST + cookies. Подходит для фильтров и форм, отправляемых GET-запросом (см. demo-проект kavalhub/form-demo, каталог src/).

Demo-приложение

Примеры использования (Kavalhub\Example\) вынесены в отдельный проект и не входят в autoload при composer require kavalhub/form-generator. В репозитории библиотеки каталог example/ доступен только через autoload-dev для PHPUnit.

$request = new ElementRequest();

PostOnlyRequest — только POST

use Kavalhub\FormGenerator\Request\PostOnlyRequest;

$request = new PostOnlyRequest();

ArrayRequest — для тестов и API

use Kavalhub\FormGenerator\Request\ArrayRequest;

$request = new ArrayRequest(['contact_email' => 'a@b.c']);

Свой адаптер

Реализуйте RequestInterface::get(string $name): ?array — метод возвращает массив значений для поля с данным именем (getFormName()).

Validator

Контракт ElementValidatorInterface:

  • checkSubmit(InputSubmit $submit): bool — была ли отправлена форма
  • handle(ElementInterface $element): bool — bind из request, required, callbacks, CSRF
  • isValid(): ?bool — результат последней проверки

Внедряйте интерфейс, а не конкретный класс:

public function __construct(private readonly ElementValidatorInterface $validator) {}

Callback-валидаторы

$input->addCallbackValidator(function (InputText $el): bool {
    if (!str_contains($el->getValue(), '@')) {
        $el->addError(['Некорректный email']);
        return false;
    }
    return true;
});

Laravel-интеграция

Пакет kavalhub/form-generator-laravel — гибридный валидатор:

  1. Core (ElementValidator) — bind, required, callbacks, CSRF
  2. Laravel (illuminate/validation) — правила required|email и т.д.
use Illuminate\Validation\Factory;
use Kavalhub\FormGenerator\Html\Form;
use Kavalhub\FormGenerator\Html\InputText;
use Kavalhub\FormGenerator\Laravel\LaravelElementValidator;
use Kavalhub\FormGenerator\Laravel\LaravelRequestAdapter;

$request = new LaravelRequestAdapter($illuminateRequest);
$validator = new LaravelElementValidator($request, app(Factory::class));
$validator->setRules([
    'contact_email' => 'required|email',
]);

$form = (new Form('contact'))->addElement((new InputText('email'))->setRequired());

if ($validator->handle($form)) {
    // OK
}

Ошибки Laravel автоматически попадают в addError() элементов через ElementDataCollector.

Bootstrap-декоратор

Пакет kavalhub/form-generator-bootstrap (с 3.3 вынесен из core):

composer require kavalhub/form-generator-bootstrap
use Kavalhub\FormGenerator\Bootstrap\BootstrapDecorator;
use Kavalhub\FormGenerator\Decorator\Interface\DecoratorInterface;

/** @var DecoratorInterface $decorator */
$decorator = new BootstrapDecorator($form);
echo $decorator->getHtml();

Кастомные шаблоны для дизайнеров: docs/custom-templates.md.

Blade-декоратор

Пакет kavalhub/form-generator-blade — те же Bootstrap-стили, шаблоны {ClassName}.php в каталоге resources/Blade/:

composer require kavalhub/form-generator-blade
use Kavalhub\FormGenerator\Blade\BladeDecorator;

echo (new BladeDecorator($form))
    ->setTemplate(__DIR__ . '/resources/form-templates')
    ->getHtml();

Для AJAX: BladeAjaxRenderStrategy. Demo поддерживает переключатель HTML / Bootstrap / Blade и per-element шаблон для фасета «Бренд».

CSRF-защита (opt-in)

$form = (new Form('secure'))
    ->enableCsrf()
    ->addElement(/* ... */);

AJAX (3.1+)

Библиотека не навязывает JS-фреймворк. Сервер возвращает JSON с ключом REPLACE — массив патчей DOM. Два режима:

Режим Метод Ответ
field ElementAjaxHandler::handleField() ID, CLASS, ERROR (через AjaxRenderStrategyInterface)
form/block ElementAjaxHandler::handleForm() / handleBlock() ID, HTML (через стратегию, напр. BootstrapAjaxRenderStrategy)

Поиск элемента по DOM-id: ElementDataCollector::findById() или $form->getById().
Короткое имя поля — getByName(); для AJAX используйте getId() / getFormName().

Разметка AJAX на форме и полях

На Form, InputText, InputSubmit и других элементах с HtmlAttributes доступны:

$form->setMethod('get')
    ->setAjax(true)
    ->setUrlState('replaceState'); // 'pushState' | false — не менять URL

$input = (new InputText('name'))->setAjax();

В HTML: data-fg-ajax="true", опционально data-fg-url-state="replaceState".
setAjax() на форме — перехват submit и (в demo) change на полях фильтра; на поле — field mode (action = getId()).

В demo URL state и AJAX POST используют одни и те же ключи, что collectPageData() (getFormName() из DOM): например demoSettings_decoratorFieldset_decorator, fl_gc_cat[], page. Decorator читается только по полному ключу demoSettings_decoratorFieldset_decorator (или из session).

Endpoint (пример)

use Kavalhub\FormGenerator\Ajax\AjaxRequest;
use Kavalhub\FormGenerator\Ajax\ElementAjaxHandler;
use Kavalhub\FormGenerator\Bootstrap\BootstrapAjaxRenderStrategy;
use Kavalhub\FormGenerator\Request\ElementRequest;
use Kavalhub\FormGenerator\Validator\ElementValidator;

header('Content-Type: application/json; charset=utf-8');

if (!AjaxRequest::isXmlHttpRequest()) {
    http_response_code(400);
    exit;
}

$validator = new ElementValidator(new ElementRequest());
$handler = new ElementAjaxHandler($validator, new BootstrapAjaxRenderStrategy());
$form = /* ваша форма */;

if ($targetId = AjaxRequest::readTargetId()) {
    echo $handler->handleField($form, $targetId)->jsonEncode();
    exit;
}

if ($validator->checkSubmit($submit) && $validator->handle($form)) {
    echo $handler->handleBlock($table)->setMessage('Сохранено')->jsonEncode();
}

Параметр action (или target_id) = getId() поля, как в demo.

Клиент (минимальный пример, не входит в пакет)

function collectPageData() {
    const body = new FormData();
    document.querySelectorAll('form').forEach((form) => {
        new FormData(form).forEach((value, key) => body.append(key, value));
    });
    return body;
}

function applyUrlState(form) {
    const mode = form?.dataset?.fgUrlState;
    if (!mode) return;
    const params = new URLSearchParams();
    collectPageData().forEach((value, key) => params.append(key, value));
    const url = `${location.pathname}?${params}`;
    (mode === 'pushState' ? history.pushState : history.replaceState).call(history, null, '', url);
}

document.querySelector('[data-fg-ajax="true"]').addEventListener('input', function () {
    const fd = collectPageData();
    fd.set('action', this.id);
    fd.set(this.name, this.value);
    fetch('/ajax.php', { method: 'POST', body: fd, headers: { 'X-Requested-With': 'XMLHttpRequest' } })
        .then(r => r.json())
        .then(data => {
            data.REPLACE.forEach(patch => {
                const el = document.getElementById(patch.ID);
                el.classList.remove('is-valid', 'is-invalid');
                if (patch.CLASS) el.classList.add(patch.CLASS);
                el.parentElement.querySelectorAll('.invalid-feedback').forEach(n => n.remove());
                if (patch.ERROR) el.insertAdjacentHTML('afterend', patch.ERROR);
                if (patch.HTML) document.getElementById(patch.ID).outerHTML = patch.HTML;
            });
            applyUrlState(this.closest('form[data-fg-url-state]'));
        });
});

Живой пример с переключателем «классика / AJAX», синхронизацией URL (setUrlState) и восстановлением фильтра из GET — demo-проект kavalhub/form-demo: главная демонстрация на ?page=filter (фильтр товаров, чекбоксы/радио на лету), также ?page=facet (добавление фасета).

JSON API (3.2+)

Структурированный обмен без HTML-патчей: валидация и сабмит формы через JSON.

Класс Назначение
Request\JsonElementRequest Источник данных из JSON / массива
Api\FormApiHandler handleField() / handleForm()FormApiResponse
Api\FormJsonSchemaExporter JSON Schema полей формы (интроспекция дерева)
Api\OpenApiDocumentBuilder Сборка OpenAPI 3.0 из списка форм
use Kavalhub\FormGenerator\Api\FormApiHandler;
use Kavalhub\FormGenerator\Request\JsonElementRequest;
use Kavalhub\FormGenerator\Validator\ElementValidator;

$request = JsonElementRequest::fromArray(['contact_email' => 'user@example.com']);
$handler = new FormApiHandler(new ElementValidator($request));
$response = $handler->handleForm($form);
echo $response->jsonEncode(); // {"valid":true,"fields":{...},"data":{...}}

OpenAPI и наполнение БД через JSON — demo: GET /api.php, POST /api.php, Swagger UI на /api-docs.html.

Сбор данных из дерева элементов

use Kavalhub\FormGenerator\Util\ElementDataCollector;

$data = ElementDataCollector::collectByFormName($form);
// ['contact_email' => 'user@example.com', ...]

Поддерживаемые элементы

Класс Описание
Html\Form Контейнер <form>
Html\Group Группа полей с префиксом имени
Html\InputText, Html\InputPassword, Html\InputNumber Текстовые поля
Html\InputCheckbox, Html\InputRadio Переключатели
Html\Select, Html\Option Выпадающий список
Html\Textarea Многострочный ввод
Html\InputHidden, Html\InputSubmit, Html\Button Скрытые и кнопки
Html\Label, Html\Nav, Html\Link Разметка
Html\Table\Table, Html\Table\Tr, Html\Table\Td, Html\Table\Th Таблицы

Миграция 2.x → 3.x

  • Namespace виджетов: Kavalhub\FormGenerator\Form\*Kavalhub\FormGenerator\Html\*
  • Таблицы: Kavalhub\FormGenerator\Table\*Kavalhub\FormGenerator\Html\Table\*
  • Рендеринг элементов: getHtml()render() (декораторы по-прежнему используют getHtml())
  • Element — доменная модель без HTML; HTML-трейты и виджеты в src/Html/
  • HtmlEscaper перенесён в Kavalhub\FormGenerator\Html\Util\HtmlEscaper
  • Базовые HTML-классы: HtmlElement, HtmlElementWithValue, HtmlCompositeElement — содержат tag, ClassList, Path
  • Доменный Element не имеет tag, getTag(), addClass() — только дерево, значения и валидация

Безопасность

  • Значения полей, placeholder, href и сообщения об ошибках экранируются через Html\Util\HtmlEscaper.
  • Label::setAllowHtml() — явное разрешение HTML в подписи.
  • ElementRequest использует $_REQUEST — удобно для GET-фильтров; для POST-only используйте PostOnlyRequest.
  • CSRF включается явно через Form::enableCsrf().

Тесты

composer install
composer test

Лицензия

MIT

kavalhub/form-generator 适用场景与选型建议

kavalhub/form-generator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 24 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 03 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「form」 「Validation form」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 kavalhub/form-generator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 kavalhub/form-generator 我们能提供哪些服务?
定制开发 / 二次开发

基于 kavalhub/form-generator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 24
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-03-29