tobento/service-form

轻松构建HTML表单。

1.0.2 2024-03-15 18:45 UTC

This package is auto-updated.

Last update: 2024-09-15 19:46:28 UTC


README

构建HTML表单。

目录

入门

使用以下命令添加运行此项目的html服务项目的最新版本。

composer require tobento/service-form

要求

  • PHP 8.0或更高版本

亮点

  • 框架无关,适用于任何项目
  • 解耦设计

文档

创建表单

use Tobento\Service\Form\Form;
use Tobento\Service\Form\InputInterface;
use Tobento\Service\Form\TokenizerInterface;
use Tobento\Service\Form\ActiveElementsInterface;
use Tobento\Service\Message\MessagesInterface;

$form = new Form(
    input: null, // null|InputInterface
    tokenizer: null, // null|TokenizerInterface
    activeElements: null, // null|ActiveElementsInterface
    messages: null // null|MessagesInterface
);

参数说明

表单工厂

您可以使用表单工厂创建表单类。

ResponserFormFactory

首先,请确保您已安装了responser服务

composer require tobento/service-responser

查看Responser服务以了解更多信息。

use Tobento\Service\Form\FormFactoryInterface;
use Tobento\Service\Form\ResponserFormFactory;
use Tobento\Service\Form\ActiveElementsInterface;
use Tobento\Service\Form\Form;
use Tobento\Service\Responser\ResponserInterface;

$formFactory = new ResponserFormFactory(
    responser: $responser, // ResponserInterface
    tokenizer: null, // null|TokenizerInterface
    activeElements: null, // null|ActiveElementsInterface
);

var_dump($formFactory instanceof FormFactoryInterface);
// bool(true)


$form = $formFactory->createForm();

var_dump($form instanceof Form);
// bool(true)

表单元素

表单

<?= $form->form() ?>
// <form method="POST">

<?= $form->close() ?>
// </form>

表单属性

<?= $form->form(attributes: ['method' => 'GET']) ?>
// <form method="GET">

输入

<?= $form->input(
    name: 'name',
    type: 'text',
    value: 'value',
    attributes: [],
    selected: null,
    withInput: true,
) ?>
// <input name="name" id="name" type="text" value="value">

参数说明

复选框类型

<?= $form->input(
    name: 'colors[]',
    type: 'checkbox',
    value: 'red',
    attributes: ['id' => 'colors_red'],
    selected: ['red'], // or 'red'
) ?>
// <input id="colors_red" name="colors[]" type="checkbox" value="red" checked>

复选框

您可以使用复选框方法创建带有其标签的多个复选框输入元素。

<?= $form->checkboxes(
    name: 'colors',
    items: ['red' => 'Red', 'blue' => 'Blue'],
    selected: ['blue'],
    attributes: [],
    labelAttributes: [],
    withInput: true,
    wrapClass: 'form-wrap-checkbox'
) ?>
/*
<span class="form-wrap-checkbox">
    <input id="colors_1" name="colors[]" type="checkbox" value="red">
    <label for="colors_1">Red</label>
</span>
<span class="form-wrap-checkbox">
    <input id="colors_2" name="colors[]" type="checkbox" value="blue" checked>
    <label for="colors_2">Blue</label>
</span>
*/

参数说明

带有每个的复选框

如果您有一个对象数组或只想对复选框的值、标签和名称的数组键有更多控制,您可以使用each方法。

$items = ['red' => 'Red', 'blue' => 'Blue'];

<?= $form->checkboxes(
    name: 'colors',
    items: $form->each(items: $items, callback: function($item, $key): array {
        // value:string, label:string|null, array-key:string|null
        return [$key, strtoupper($item), $key];
    }),
    selected: ['blue'],
) ?>
/*
<span class="form-wrap-checkbox">
    <input id="colors_red" name="colors[red]" type="checkbox" value="red">
    <label for="colors_red">RED</label>
</span>
<span class="form-wrap-checkbox">
    <input id="colors_blue" name="colors[blue]" type="checkbox" value="blue" checked>
    <label for="colors_blue">BLUE</label>
</span>
*/

单选框类型

<?= $form->input(
    name: 'colors',
    type: 'radio',
    value: 'red',
    attributes: ['id' => 'colors_red'],
    selected: 'red',
) ?>
// <input id="colors_red" name="colors" type="radio" value="red" checked>

单选框

您可以使用单选框方法创建带有其标签的多个单选框输入元素。

<?= $form->radios(
    name: 'colors',
    items: ['red' => 'Red', 'blue' => 'Blue'],
    selected: 'blue',
    attributes: [],
    labelAttributes: [],
    withInput: true,
    wrapClass: 'form-wrap-radio'
) ?>
/*
<span class="form-wrap-radio">
    <input id="colors_1" name="colors[]" type="radio" value="red">
    <label for="colors_1">Red</label>
</span>
<span class="form-wrap-radio">
    <input id="colors_2" name="colors[]" type="radio" value="blue" checked>
    <label for="colors_2">Blue</label>
</span>
*/

参数说明

带有每个的单选框

如果您有一个对象数组或只想对值和标签有更多控制,您可以使用each方法。

$items = ['red' => 'Red', 'blue' => 'Blue'];

<?= $form->radios(
    name: 'colors',
    items: $form->each(items: $items, callback: function($item, $key): array {
        // value:string, label:string|null
        return [$key, strtoupper($item)];
    }),
    selected: 'blue',
) ?>
/*
<span class="form-wrap-radio">
    <input id="colors_red" name="colors" type="radio" value="red">
    <label for="colors_red">RED</label>
</span>
<span class="form-wrap-radio">
    <input id="colors_blue" name="colors" type="radio" value="blue" checked>
    <label for="colors_blue">BLUE</label>
</span>
*/

标签

<?= $form->label(
    text: 'Text',
    for: 'colors',
    attributes: [],
    requiredText: '',
    optionalText: '',
) ?>
// <label for="colors">Text</label>

参数说明

带有必填文本

<?= $form->label(
    text: 'Text',
    requiredText: 'required',
) ?>
// <label>Text<span class="required">required</span></label>

带有可选文本

<?= $form->label(
    text: 'Text',
    optionalText: 'optional',
) ?>
// <label>Text<span class="optional">optional</span></label>

选择

<?= $form->select(
    name: 'colors[]',
    items: ['red' => 'Red', 'blue' => 'Blue'],
    selected: ['blue'],
    selectAttributes: ['multiple'],
    optionAttributes: [],
    optgroupAttributes: [],
    emptyOption: null,
    withInput: true,
) ?>
/*
<select multiple name="colors" id="colors">
    <option value="red">Red</option>
    <option value="blue" selected>Blue</option>
</select>
*/

参数说明

带有optgroup元素

<?= $form->select(
    name: 'roles',
    items: [
        'Frontend' => [
            'guest' => 'Guest',
            'registered' => 'Registered',
        ],
        'Backend' => [
            'editor' => 'Editor',
            'administrator' => 'Aministrator',
        ],        
    ],
) ?>
/*
<select name="roles" id="roles">
    <optgroup label="Frontend">
        <option value="guest">Guest</option>
        <option value="registered">Registered</option>
    </optgroup>
    <optgroup label="Backend">
        <option value="editor">Editor</option>
        <option value="administrator">Aministrator</option>
    </optgroup>
</select>
*/

使用每个方法

如果您有一个对象数组或只想对值、标签和单选框名称的数组键有更多控制,您可以使用each方法。

$items = ['red' => 'Red', 'blue' => 'Blue'];

<?= $form->select(
    name: 'colors',
    items: $form->each(items: $items, callback: function($item, $key): array {
        // value:string, label:string|null
        return [$key, strtoupper($item)];
    }),
    selected: 'blue',
) ?>
/*
<select name="colors" id="colors">
    <option value="red">RED</option>
    <option value="blue" selected>BLUE</option>
</select>
*/

带有空选项

<?= $form->select(
    name: 'colors',
    items: ['red' => 'Red', 'blue' => 'Blue'],
    emptyOption: ['none', '---'],
) ?>
/*
<select name="colors" id="colors">
    <option value="none">---</option>
    <option value="red">Red</option>
    <option value="blue">Blue</option>
</select>
*/

文本区域

<?= $form->textarea(
    name: 'description',
    value: 'Lorem ipsum',
    attributes: [],
    withInput: true,
) ?>
// <textarea name="description" id="description">Lorem ipsum</textarea>

参数说明

按钮

<?= $form->button(
    text: 'Submit Text',
    attributes: [],
    escText: true,
) ?>
// <button type="submit">Submit Text</button>

参数说明

字段集和说明

<?= $form->fieldset(
    legend: 'Legend',
    attributes: [],
    legendAttributes: [],
) ?>
// <fieldset><legend>Legend</legend>

<?= $form->fieldsetClose() ?>
// </fieldset>

参数说明

数据列表

<?= $form->datalist(
    name: 'colors',
    items: ['red', 'blue'],
    attributes: [],
) ?>
/*
<datalist id="colors">
    <option value="red"></option>
    <option value="blue"></option>
</datalist>
*/

参数说明

使用每个方法

如果您有一个对象数组或只想对值有更多控制,您可以使用each方法。

$items = ['red' => 'Red', 'blue' => 'Blue'];

<?= $form->datalist(
    name: 'colors',
    items: $form->each(items: $items, callback: function($item, $key): array {
        // value:string
        return [strtoupper($item)];
    })
) ?>
/*
<datalist id="colors">
    <option value="RED"></option>
    <option value="BLUE"></option>
</datalist>
*/

选项

<?= $form->option(
    value: 'red',
    text: 'Red',
    attributes: [],
    selected: ['red'], // or 'red'
) ?>
// <option value="red" selected>Red</option>

参数说明

输入数据

输入数据用于重新填充表单元素的值。

创建输入

use Tobento\Service\Form\InputInterface;
use Tobento\Service\Form\Input;

$input = new Input(array_merge(
    $_GET ?? [],
    $_POST ?? [],
));

var_dump($input instanceof InputInterface);
// bool(true)

现在,如果存在指定元素的输入数据,表单元素的值将自动重新填充。

表单输入方法

您可以使用以下方法访问表单类上的输入数据。

getInput

use Tobento\Service\Form\Form;
use Tobento\Service\Form\Input;

$form = new Form(
    input: new Input(['color' => 'red']),
);

$value = $form->getInput(
    name: 'color',
    default: 'blue',
    withInput: true, // default
);

var_dump($value);
// string(3) "red"

$value = $form->getInput(
    name: 'color',
    default: 'blue',
    withInput: false,
);

var_dump($value);
// string(4) "blue"

hasInput

use Tobento\Service\Form\Form;
use Tobento\Service\Form\Input;

$form = new Form(
    input: new Input(['color' => 'red']),
);

var_dump($form->hasInput('color'));
// bool(true)

withInput

返回具有指定输入的新表单实例。

use Tobento\Service\Form\Form;
use Tobento\Service\Form\Input;
use Tobento\Service\Form\InputInterface;

$form = new Form(
    input: new Input(['color' => 'red']),
);

$form = $form->withInput(
    input: null, // null|InputInterface
);

标记器

标记器用于生成和验证令牌,以保护您的应用程序免受跨站请求伪造攻击。

会话标记器

首先,请确保您已安装会话服务

composer require tobento/service-session

查看会话服务以了解更多信息。

use Tobento\Service\Form\TokenizerInterface;
use Tobento\Service\Form\SessionTokenizer;
use Tobento\Service\Session\SessionInterface;
use Tobento\Service\Session\Session;

$session = new Session(name: 'sess');

$tokenizer = new SessionTokenizer(
    session: $session, // SessionInterface
    tokenName: 'csrf', // default
    tokenInputName: '_token' // default
);

var_dump($tokenizer instanceof TokenizerInterface);
// bool(true)

标记器方法

setTokenName

$tokenizer->setTokenName('csrf');

getTokenName

var_dump($tokenizer->getTokenName());
// string(4) "csrf"

setTokenInputName

$tokenizer->setTokenInputName('_token');

getTokenInputName

var_dump($tokenizer->getTokenInputName());
// string(6) "_token"

get

返回指定名称的令牌。

var_dump($tokenizer->get('csrf'));
// Null or string

generate

生成并返回指定名称的新令牌。

var_dump($tokenizer->generate('csrf'));
// string(40) "token-string..."

delete

删除指定名称的令牌。

$tokenizer->delete('csrf');

verifyToken

$isValid = $tokenizer->verifyToken(
    inputToken: 'input token string', // string
    name: 'csrf', // null|string The name of the token to verify.
);

// or set a token.
$isValid = $tokenizer->verifyToken(
    inputToken: 'input token string', // string
    token: 'token string' // null|string
);

标记器PSR-15中间件

您还可以使用VerifyCsrfToken::class中间件验证表单令牌。
如果令牌无效,将抛出InvalidTokenException异常。

use Tobento\Service\Form\Middleware\VerifyCsrfToken;
use Tobento\Service\Form\InvalidTokenException;

$middleware = new VerifyCsrfToken(
    tokenizer: $tokenizer, // TokenizerInterface
    name: 'csrf', // default
    inputName: '_token', // default
    headerTokenName: 'X-Csrf-Token', // default. Null if not to use at all.
    onetimeToken: false, // default
);

您可能希望排除一组URI从CSRF保护

$request = $request->withAttribute(
    VerifyCsrfToken::EXCLUDE_URIS_KEY,
    [
        'http://example.com/foo/bar',
    ]
);

表单标记器方法

标记器

use Tobento\Service\Form\Form;
use Tobento\Service\Form\TokenizerInterface;

$form = new Form(
    tokenizer: $tokenizer,
);

var_dump($form->tokenizer() instanceof TokenizerInterface);
// bool(true)

generateToken

use Tobento\Service\Form\Form;

$form = new Form(
    tokenizer: $tokenizer,
);

var_dump($form->generateToken());
// string(40) "token string..."

generateTokenInput

use Tobento\Service\Form\Form;

$form = new Form(
    tokenizer: $tokenizer,
);

echo $form->generateTokenInput();
// <input name="_token" type="hidden" value="token string...">

消息

消息用于在表单元素上显示任何类型的消息。

查看消息服务以了解更多相关信息。

use Tobento\Service\Message\MessagesInterface;
use Tobento\Service\Message\Messages;

$messages = new Messages();

var_dump($messages instanceof MessagesInterface);
// bool(true)

表单消息方法

messages

use Tobento\Service\Form\Form;
use Tobento\Service\Message\MessagesInterface;

$form = new Form();

var_dump($form->messages() instanceof MessagesInterface);
// bool(true)

withMessages

返回一个带有指定消息的新实例。

use Tobento\Service\Form\Form;
use Tobento\Service\Message\MessagesInterface;

$form = new Form();

$form = $form->withMessages(
    input: null, // null|MessagesInterface
);

getMessage

返回指定键的消息。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->getMessage('key'));
// string(0) ""

getRenderedMessageKeys

返回已渲染的消息键。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->getRenderedMessageKeys());
// array(0) { }

添加消息

如何为特定表单元素添加消息的示例。

use Tobento\Service\Form\Form;

$form = new Form();

$form->messages()->add(
    level: 'error',
    message: 'Please accept our terms.',
    key: 'terms',
);

<?= $form->input('terms', 'checkbox', 'terms') ?>
// <span class="form-message error">Please accept our terms.</span>
// <input name="terms" id="terms" type="checkbox">

您可以通过查看验证服务来验证表单并将验证器消息传递到表单。

CSRF保护

如果您在表单类中指定了分词器,表单方法将自动添加一个带有标记的隐藏输入元素。

<?= $form->form() ?>
// <form method="POST">
// <input name="_token" type="hidden" value="generated-token-string">

方法欺骗

如果您将PUT、PATCH或DELETE设置为方法,将自动添加一个名为_method的隐藏输入元素以进行欺骗。

<?= $form->form(['method' => 'PUT']) ?>
// <form method="POST">
// <input name="_method" type="hidden" value="PUT">

活动表单元素

getActiveElements

返回活动元素。

use Tobento\Service\Form\Form;
use Tobento\Service\Form\ActiveElements;
use Tobento\Service\Form\ActiveElementsInterface;

$form = new Form(
    activeElements: new ActiveElements(),
);

var_dump($form->getActiveElements() instanceof ActiveElementsInterface);
// bool(true)

isActive

如果元素是活动的。

use Tobento\Service\Form\Form;

$form = new Form();

$isActive = $form->isActive(
    name: 'colors',
    value: 'red', // the value to be active.
    default: null,
);

表单辅助方法

nameToArray

如果名称包含表示法语法,则将指定的名称生成到数组字符串。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->nameToArray('user.firstname'));
// string(15) "user[firstname]"

nameToNotation

将指定的名称从数组字符串生成到基于表示法的名称。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->nameToNotation('user[firstname]'));
// string(14) "user.firstname"

nameToId

将指定的名称生成到一个有效的id。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->nameToId('user[firstname]'));
// string(14) "user_firstname"

hasArrayNotation

检查指定的名称是否包含表示法。

use Tobento\Service\Form\Form;

$form = new Form();

var_dump($form->hasArrayNotation('user.firstname'));
// bool(true)

致谢