occ2 / form-control
FormControl项目的描述。
Requires
- aleswita/formrenderer: 1.3
- contributte/cache: dev-master
- nette/application: v2.4.12
- nette/di: dev-master
- occ2/control: dev-master
- occ2/flashes: dev-master
This package is not auto-updated.
Last update: 2019-09-01 08:22:06 UTC
README
1. 简介
表单控件是一个创建、设置和使用Nette应用程序中表单的简便方式。表单封装在Bootstrap4卡片中,使用Bootstrap4布局和Font Awesome 5图标。它使用基于注解的表单及其控件设置。
安装
composer require occ2/form-control
表单控件有一些重要的依赖项。
contributte/event-dispatcher - 必需的 contributte/recaptcha - 必需的 kdyby/translation - 可选 aleswita/formrenderer - 必需和整个Nette框架。
所有使用的文本都是未翻译的锚点。如果您不想使用翻译,您可以使用简单的文本。
2. 创建表单
a. 创建您的表单类 - 例如在MyForm.php中
<?php
namespace MyApp\Controls;
use occ2\form-control\FormControl;
/**
* @ajax
* @title app.myForm.title
* @comment app.myForm.comment
* @styles (headerBackground="light",headerText="dark",size="w-100")
*/
final class MyForm extends FormControl{
/**
* @type hidden
*/
public $id;
/**
* @leftAddon app.myForm.username
* @rightIcon user
* @type text
* @cols 20
* @validator (type=':filled',message='user.error.requiredUsername')
* @validator (type=':minLength',message='app.myForm.error.minLengthUsername',value=4)
* @description app.myForm.usernameDescription
*/
public $username;
/**
* @leftAddon app.myForm.password
* @rightIcon key
* @type password
* @cols 20
* @validator (type=':filled',message='user.error.requiredPassword')
* @validator (type=':minLength',message='app.myForm.error.minLengthPassword',value=8)
* @validator (type=':pattern',message='user.error.patternPassword',value='.*(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).*')
* @description app.myForm.passwordDescription
*/
public $password;
/**
* @type recaptcha
*/
public $recaptcha;
/**
* @label app.myForm.submit
* @type submit
*/
public $submit;
}
b. 创建控件工厂接口 - 例如在IMyForm.php中
<?php
namespace MyApp\Controls;
interface IMyForm{
/**
* @return \MyApp\Controls\MyForm
*/
public function create();
}
c. 在您的config.neon中注册表单和渲染器的工厂
services:
formFactory: \app\Base\controls\FormControl\factories\FormFactory(@Nette\Localization\ITranslator)
- \MyApp\Controls\IMyForm
d. 现在,您可以在您的表示者中使用工厂 - 例如在UserPresenter.php中
<?php
namespace MyApp\Presenters;
use Nette\Application\UI\Presenter as NPresenter,
Nette\Application\UI\Form as NForm;
final class UserPresenter extends NPresenter{
/**
* @inject @var \MyApp\Controls\IMyForm
*/
public $myFormFactory;
/**
* @return \MyApp\Controls\MyForm
*/
public function createComponentMyForm{
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
......
if($t->isAjax()){
$t["myForm"]->flashMessage("Success..");
$t["myForm"]->reload();
}
else{
$t->redirect("this");
}
};
return $f;
}
}
e. 将您的表单添加到模板中 - 例如default.latte
{block content}
{control myForm}
3. 设置表单结构
表单的结构由属性设置。一个表单控件 = 一个属性(属性名称 = 控件名称)。所有设置和表单布局都可以通过类注解设置。所有设置和控件的布局都可以通过属性注解设置。请注意,一些属性名称是保留的($name, $parent,$presenter, $params, $snippetMode, $linkCurrent, $template 和所有以 $_ 开头的内容)并且不能用作控件名称。
a. 表单设置和布局
这些通过表单类的注解设置。以下是一些列表。
@ajax - AJAX化表单(设置表单类ajax)
@title - 设置表单卡片标题(在Bootstrap4卡片中) - 可翻译文本
@comment - 设置表单注释(放置在表单控件和标题之间)- 可翻译文本
@footer - 设置表单页脚(放置在表单控件下方)- 可翻译文本
@styles - 表单Bootstrap卡片CSS类数组
@rControl - 控件渲染包装器数组
@rForm - 表单渲染包装器数组
@rError - 错误渲染包装器数组
@rGroup - 组渲染包装器数组
@rControls - 控件渲染包装器数组
@rPair - 对渲染包装器数组
@rLabel - 标签渲染包装器数组
@rHidden - 隐藏渲染包装器数组
@links - 在页脚添加链接(数组包含链接、类和文本)
@onSubmit - 在点击提交按钮时触发的 Symfony 事件
@onError - 在添加错误时触发的 Symfony 事件
@onValidate - 在需要验证时触发的 Symfony 事件
@onSuccess - 在发送有效表单时触发的 Symfony 事件
b. 控件设置和布局
这些由表单属性的注解设置。属性名设置为控件名。以下是注解设置的列表。
@type - 设置控件的类型。可用的类型有:隐藏、文本、电子邮件、数字、密码、文本区域、选择、多选、复选框、复选框列表、单选列表、上传、多上传、提交、reCAPTCHA
@label - 设置控件标签(可翻译)
@cols - 设置控件中的列数 - 仅适用于 TextInput 和 TextArea
@rows - 设置行数 - 仅适用于 TextArea
@description - 设置可翻译的控件描述(位于控件下方的短文本)
@leftAddon - 设置控件中的左附加可翻译文本
@leftIcon - 设置控件中的左附加图标 - 与 leftAddon 冲突
@rightAddon - 设置控件中的右附加可翻译文本
@rightIcon - 设置控件中的右附加图标 - 与 rightAddon 冲突
@placeholder - 设置可翻译的控件占位符
@maxlength - 设置控件文本的最大长度
@caption - 设置复选框的可翻译标题文本
@multiple - 设置多上传
@required - 为 reCAPTCHA 设置必需
@message - 设置 reCAPTCHA 的消息
@validator - 设置控件验证器(类型、消息和值的数组)- 支持多个验证器
- 注意:条件尚未支持。如果您需要,您必须手动添加条件
c. 控件选项和值
Select、Multiselect、CheckboxList 和 Radiolist 控件需要填充选项。最简单的方法是使用回调。FormControl 有 setLoadOptionsCallback 方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->setLoadOptionsCallback('someSelect', function()use($t){
return (array) $t->someModel->findAll()->fetchPairs();
});
...
return $f;
}
...'
5. 表单处理
有两种方法可以处理表单。
a. 使用标准 Nette 表单事件
onSubmit、onSuccess、onError、onValidate 示例 1 - 使用回调
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
$f->onError[] = function (NForm $form) use( $t){
...
};
...
return $f;
}
...'
示例 2 - 使用方法
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = [$this,"processMyForm"];
...
return $f;
}
public function processMyForm(NForm $form){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
}
...'
b. 使用 Symfony 事件
如果您想在表单上使用 Symfony 事件,您有两种方法。第一种是在表单类上添加 @onSuccess(onError、onSubmit、onValidate)注解,其中值是注册在订阅者中的事件名称,数据容器是 FormEventData 类的实例。
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
... // dont use onSuccess, onSubmit etc.
return $f;
}
表单规范 <?php namespace app\Controls\MyControl;
@onSubmit MyForm.submit
@onError MyForm.error
final class MyForm extends FormControl{
}
和订阅者(例如 MyFormSubscriber.php)...
<?php
namespace MyApp\Events;
use Contributte\EventDispatcher\EventSubscriber;
final class MyFormSubscriber implements EventSubscriber{
protected $model;
public static function getSubscribedEvents(){
return [
"MyForm.submit"=>"onSubmit"
"MyForm.error"=>"onError"
...
];
}
public function onSubmit(FormEventData $event){
$values = $event->form->getValues();
// do something with data
$this->model->save($values);
if($event->presenter->isAjax()){
$event->presenter["myForm"]->flashMessage("Saved");
$event->presenter["myForm"]->reload();
}
else{
$event->presenter->redirect("this");
}
}
public function onError(FormEventData $event){
.... // do something else
}
}
第二种方法是使用 setEvent(array $events) 方法,其中 $event 是事件数组的键... public function createComponentMyForm(){ $t = $this; $f = $this->myFormFactory->create(); $f->setEvents([ "success"=>"MyForm.success" ]); ... // 不要使用 onSuccess、onSubmit 等。 return $f; }
6. 设置表单值
有两种方法可以填充表单控件中的值。第一种是使用 setDefaults 方法,第二种是使用预定义的回调
a. 使用 setDefaults()
如果使用 setDefaults($values) 是最简单的方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
$f->onError[] = function (NForm $form) use( $t){
...
};
...
return $f;
}
...
public function handleFillInForm($id){
$data = (array) $this->model->get($id); // data must be array
$this["myForm"]->setDefaults($data);
$this["myForm"]->reload();
return;
}
b. 使用回调 您可以使用加载数据并填充到表单中的回调。在工厂中设置回调并在处理程序中调用示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->setLoadValuesCallback(function($id) use($t){
return (array) $t->model->get($id);
});
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
return $f;
}
...
public function handleFillInForm($id){
$this["myForm"]->laodValues($id));
$this["myForm"]->reload();
return;
}
!! 重要 !! 注意,loadValues() 和 setDefaults() 必须在处理程序或动作方法中调用,而不是在 createComponent 工厂中
7. 小技巧和技巧
a. 如何访问表单容器?
您可以在 FormControl 示例的 form 属性中找到容器。
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$container = $f->form;
$container->addText(...);
...
return $f;
}
b. 如何访问表单控件?
您可以使用 form["controlName"] 或更简单的 getItem("controlName") 方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$control = $f->form["controlName"];
// or
$control = $f->getItem("controleName");
return $f;
}
c. 如何禁用表单注解构建器?
您可以在工厂中使用 disableBuilder() 方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->disableBuilder();
$container = $f->form;
$container->addText(...);
...
return $f;
}
d. 如何在处理程序和操作中覆盖表单文本?
您可以在处理程序和操作中覆盖表单标题、注释和页脚,而无需更改表单类中的注解。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
...
return $f;
}
...
public function handleChangeTexts(){
$this["myForm"]->setTitle("newTitle"));
$this["myForm"]->setComment("newComment"));
$this["myForm"]->setFooter("newFooter"));
$this["myForm"]->reload();
return;
}
e. 如何清除已填写表单的值?
您可以使用 clearValues() 方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->setLoadValuesCallback(function($id) use($t){
return (array) $t->model->get($id);
});
$f->onSuccess[] = function(NForm $form)use($t){
$values = $form->getValues();
$t->model->save($values);
if($t->isAjax(){
$t["myForm]->flashMessage("Saved !!");
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
return $f;
}
...
public function handleFillInForm($id){
$this["myForm"]->laodValues($id));
$this["myForm"]->reload();
return;
}
public function handleResetForm(){
$this["myForm"]->clearValues();
$this["myForm"]->reload();
return;
}
f. 您想使用自己的构建器吗?没问题。
您的构建器必须实现 IFormBuilder 接口
示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->setBuilder(new MyOwnBuilder);
...
return $f;
}
g. 添加错误到控件的方法简单吗?
是的。您可以使用 error() 方法。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->onSuccess[] = function(NForm $form)use($t){
if(..something){
$t["myForm]->error("someControl","Error message");
}
else{
$t["myForm"]->flashMessage("Saved !!");
}
$t["myForm]->flashMessage("Saved !!");
if($t->isAjax(){
$t["myForm]->reload();
}
else{
$t->redirect("this");
}
};
return $f;
}
h. 我可以使用自己的 latte 模板而不是预定义的 bootstrap 模板吗?
是的。您可以使用自己的模板,并通过 setTemplate() 方法覆盖默认设置。示例
...
public function createComponentMyForm(){
$t = $this;
$f = $this->myFormFactory->create();
$f->setTemplate("myTemplate.latte");
...
return $f;
}
并且文件 myTemplate.latte 示例
{snippet form}
{snippetArea flashes}
{include '../../templates/flashes.latte'}
{/snippetArea}
<form n:name=myForm class=form>
<p><label n:name=user>Username: <input n:name=user size=20></label>
<p><label n:name=password>Password: <input n:name=password></label>
<p><input n:name=send class="btn btn-default">
</form>
{/snippet}
i. 我可以使用 Fon Awesome 5 之外的另一个图标集吗?
是的,您可以通过覆盖 _iconPrefix 静态属性来实现。示例
...
public function createComponentMyForm(){
MyForm::$_iconPrefix = "fa fa-";
$t = $this;
$f = $this->myFormFactory->create();
$f->setTemplate("myTemplate.latte");
...
return $f;
}