occ2/form-control

此包已被废弃,不再维护。未建议替代包。
关于此包的最新版本(v1.0.0alpha1)没有可用的许可证信息。

FormControl项目的描述。

v1.0.0alpha1 2018-09-05 23:00 UTC

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;
}