jazzman / form-html-generator
PHP-HTML 表单管理器
Requires
- php: >=5.4.0
- psr/http-message: ~1.0
README
使用方法
命名空间导入
FormManager 是命名空间化的,但你只需要将单个类导入到你的上下文中
use FormManager\Builder as F;
创建字段
支持所有 HTML5 字段类型。
//Create an input type="text" element $name = F::text(); //Use the jQuery syntax to set/get/remove attributes: $name->attr('name', 'username'); $name->attr([ 'maxlength' => 50, 'required' => true ]); $maxlength = $name->attr('maxlength'); $name->removeAttr('required'); //Get/set values $name->val('MyName'); //Get/set css classes $name->addClass('cool-input'); $name->removeClass('cool-input'); //Get/set/remove data-* attributes $name->data('id', 23); $name->data([ 'name' => 'value', 'foo' => 'bar' ]); $foo = $name->data('foo'); $name->removeData('id'); $name->removeData(); //Remove all data //You can chain various methods: $email = F::email()->addClass('cool-input')->id('my-email')->val('my@email.com'); //And use the __call() magic method to add attributes: $email->required(); //same than $email->attr('required', true); $email->required(false); //same than $email->attr('required', false);
生成 HTML 代码
在将对象转换为字符串时自动创建 HTML 代码
$name = F::text()->class('my-input')->required(); echo $name; //<input type="text" class="my-input" required> //print the input with extra attributes echo $name->addClass('text-input')->placeholder('Your name');
与数据交互
输入可以根据类型和其他验证属性验证数据
$url = F::url(); //Set the input as required $url->required(); //Check if the value is valid if (!$url->validate()) { echo $url->error(); //This value is required } //set an invalid url $url->val('invalid-url'); //check the value and get the error if (!$url->validate()) { echo $url->error(); //This value is not a valid url }
输入可以处理自定义验证器
$name = F::text(); function isDave($input) { if ($input->val() !== 'dave') { throw new FormManager\InvalidValueException('This value must be "dave"'); } } //Add custom validators $name->addValidator('isDave'); $name->val('tom'); if (!$name->validate()) { echo $name->error(); //This value must be "dave" } //Remove the validator $name->removeValidator('isDave');
load()
方法类似于 val()
,但它处理客户端发送的数据
$name = F::text(); //Add a function to sanitize the data $name->sanitize(function($value) { return strip_tags($value); }); //if you use val(), the value remains as is $name->val('<strong>earl</strong>'); echo $name->val(); //<strong>earl</strong> //if you use load(), the value will be sanitized $name->load('<strong>earl</strong>'); echo $name->val(); //earl
标签
你可以使用标签与输入一起使用,只需使用属性 ->label
,它将自动创建。它还可以生成一个带有错误消息的额外标签。
$name = F::text(); //Define a label $name->label('User name'); //And modify the label using the same syntax than inputs: $name->label->class('main-label'); //Print all (label + input) echo $name; //Print label and inputs separately echo $name->label . '<br>' . $name->input; //Use errorLabel to print a secondary label with the validation error: echo $name->label . '<br>' . $name->input . $name->errorLabel;
Datalist
Datalist 同样允许,只需使用 datalist()
方法设置/获取值
$name = F::search(); //Define the datalist values $name->datalist([ 'female' => 'Female', 'male' => 'Male' ]);
自定义渲染
你可以配置每个字段如何渲染。首先,你需要了解每个字段的全部属性
$field->input
输入/选择/textarea 元素$field->label
标签元素$field->errorLabel
带有验证错误的消息标签$field->datalist
可选的 datalist 实例$field->wrapper
包含上述所有内容的 div 元素
$field->render(function ($field) { $html = (string) $field->label; $html .= '<p>'.$field->input.$field->errorLabel.'</p>'; $html .= $field->datalist; return $html; });
特殊字段
除了常规字段(HTML5 的等效项:text、textarea、select、datetime 等)外,还有一些有用的特殊字段,可以创建更复杂的数据方案
组
组是一个简单的字段,用于将其他字段存储在名称下。以下示例显示了包含三个字段的组
$date = F::group([ 'day' => F::number()->min(1)->max(31)->label('Day'), 'month' => F::number()->min(1)->max(12)->label('Month'), 'year' => F::number()->min(1900)->max(2013)->label('Year') ]); //Set values to group $date->val([ 'day' => 21, 'month' => 6, 'year' => 1979 ]); //Get values $values = $date->val(); //Use array syntax to access to the fields by name $year = $date['year']->val(); //Add more fields dinamically $date['hour'] = F::number()->min(0)->max(23)->label('Hour'); //Add other html attributes to the group: $date->addClass('field-day')->attr(['id' => 'date-field']);
选择
此字段存储具有相同名称但不同值的其他字段。对于单选按钮输入或定义各种提交按钮非常有用。
//Create a choose container $colors = F::choose(); //Add some fields. The keys are the values $colors->add([ 'red' => F::radio()->label('Red'), 'blue' => F::radio()->label('Blue'), 'green' => F::radio()->label('Green') ]); //Access to the fields by value $red_radio = $colors['red']; //Add more fields dinamically $colors['yellow'] = F::radio()->label('Yellow'); //Set the value $colors->val('red'); //Get value $color_choosen = $colors->val();
集合
它类似于 组,但存储值集合
//Create a collection container $people = F::collection([ 'name' => F::text()->label('Name'), 'email' => F::email()->label('email'), 'age' => F::number()->label('Age') ]); //Set two values $people->val([ [ 'name' => 'Xaquín', 'email' => 'xaquin@email.com', 'age' => '24' ],[ 'name' => 'Uxío', 'email' => 'uxio@email.com', 'age' => '37' ] ]); //Access to the first group of values: $group = $people[0]; //Access to any field echo $people[0]['name']->val(); //returns 'Xaquín' //Push a new value $people->pushVal([ 'name' => 'Manoela', 'email' => 'manoela@email.com', 'age' => '18' ]); //Returns the group container used as template for each value inserted. //useful to use the html template in javascript $template = $people->getTemplate(); echo '<div class="template">'.$template.'</div>';
集合多个
如果你需要在集合中存储不同类型的值,CollectionMultiple 就是答案
//Create a collectionMultiple container $article = F::collectionMultiple([ 'section' => [ 'title' => F::text()->label('Title'), 'text' => F::textarea()->label('Text') ], 'picture' => [ 'caption' => F::text()->label('Caption'), 'image' => F::file()->label('Image') ], 'quote' => [ 'text' => F::textarea()->label('Text'), 'author' => F::text()->label('Author') ] ]); //Set values. Note that we need a "type" value to know the type of each row $article->val([ [ 'type' => 'section', 'title' => 'This is the section title', 'text' => 'Lorem ipsum...', ],[ 'type' => 'quote', 'text' => 'You have to learn the rules of the game. And then you have to play better than anyone else.', 'author' => 'Albert Einstein' ] ]); // Note that a hidden input will be created for you to store the group type $article[0]['type']->val(); //section $article[0]['type']->attr('type'); //hidden //Push more values $article->pushVal([ 'type' => 'section', 'title' => 'This is another section', 'text' => 'The world of dogs are better than the cats because...' ]); //Add new types $article->add([ 'video' => [ 'title' => F::text()->label('Title'), 'video' => F::url()->label('Youtube url') ] ]); //Returns an array with all templates used $templates = $article->getTemplate(); foreach ($templates as $name => $template) { echo '<div class="template-'.$name.'">'.$template.'</div>'; }
加载器
加载器字段的主要目的是将加载数据的方式与存储和保留已加载数据的方式分开。例如,对于文件输入类型:如果加载了文件,则值是一个与任何 $_FILES 值具有相同结构的数组,但如果没有用户上传任何内容,则值是空的。在这种情况下,应该做什么?删除文件还是保留以前的值?加载器字段有两个字段:一个“加载器”字段和一个“字段”字段。第一个字段响应于加载新值(例如,它可以是一个文件输入类型)并且第二个字段保留以前的值(例如,它可以是一个隐藏输入类型或文本等)。让我们看看一个例子
$fileUpload = F::loader([ 'loader' => F::file()->label('Upload a file here'), 'field' => F::hidden() //this hidden input stores the old value ]); //Set a value $fileUpload->val('my-file.png'); //we have this value echo $fileUpload->val(); //my-file.png //load empty data $fileUpload->load(null); //Nothing was loaded, so we keep the old value echo $fileUpload->val(); //my-file.png //load new value $fileUpload->load($_FILES['file-upload']); //we have the new value echo ($fileUpload->val() === $_FILES['file-upload']); //true
表单
我们需要一个表单来将这些事物放在一起。表单只是一个字段,实际上,它就像一个 组。
$form = F::form(); //Set the form attributes: $form->attr([ 'action' => 'test.php', 'method' => 'post' ]); //Add some fields and containers $form->add([ 'name' => F::text()->maxlength(50)->required()->label('Your name'), 'email' => F::email()->label('Your email'), 'telephone' => F::tel()->label('Telephone number'), 'gender' => F::choose([ 'm' => F::radio()->label('Male'), 'f' => F::radio()->label('Female') ]), 'born' => F::group([ 'day' => F::number()->min(1)->max(31)->label('Day'), 'month' => F::number()->min(1)->max(12)->label('Month'), 'year' => F::number()->min(1900)->max(2013)->label('Year') ]), 'language' => F::select()->options(array( 'gl' => 'Galician', 'es' => 'Spanish', 'en' => 'English' ))->label('Language'), 'friends' => F::collection([ 'name' => F::text()->label('Name'), 'email' => F::email()->label('email'), 'age' => F::number()->label('Age') ]), 'action' => F::choose([ 'save' => F::submit()->html('Save changes'), 'duplicate' => F::submit()->html('Save changes') ]) ]); //You can also add new fields using the array syntax (the key will be the input name): $form['new-input'] = F::range()->min(0)->max(100)->val(50); //Print the form echo $form; //Access to the fields using key names echo $form['website']; //Or fields inside fields echo $form['born']['day']; //Set the values to all fields: $form->val([ 'name' => 'Oscar', 'email' => 'oom@oscarotero.com', 'gender' => 'm', 'born' => [ 'day' => 21, 'month' => 6, 'year' => 1979 ], 'language' => 'gl', 'friends' => [ [ 'name' => 'Friend 1', 'email' => 'friend1@email.com', 'age' => 25, ],[ 'name' => 'Friend 2', 'email' => 'friend2@email.com', 'age' => 30, ],[ 'name' => 'Friend 3', 'email' => 'friend3@email.com', 'age' => 35, ] ], 'action' => 'save' ]); //Get the values $values = $form->val(); //To load the raw values from globals $_GET, $_POST and $_FILES: $form->loadFromGlobals(); //Or specify your own globals $form->loadFromGlobals($_my_GET, $_my_POST, $_my_FILES); //Check the errors if (!$form->validate()) { echo 'there are errors in the form'; }
构建器
Builder
类用于简化字段和容器的创建。例如,而不是这样做
use FormManager\Containers\Form; use FormManager\Inputs\Text; use FormManager\Inputs\Textarea; $form = new Form([ 'name' => new Text(), 'bio' => new Textarea(), ]);
你可以这样做
use FormManager\Builder as F; $form = F::form([ 'name' => F::text(), 'bio' => F::textarea() ]);
FormManager\Builder
类通过使用工厂来处理所有这些类的实例化。默认情况下,它包含 FormManager\Factory
,负责所有字段和容器的实例化。
但你可以添加你自己的工厂,创建实现 FormManager\FactoryInterface
的类。
这对于很多事物都很有用。例如,用于创建自定义字段
use FormManager\Builder as F; use FormManager\FactoryInterface; class CustomFields implements FactoryInterface { /** * Method required by the interface */ public function get($name, array $arguments) { if (method_exists($this, $name)) { return $this->$name(); } } public function Year() { return F::number()->min(1900)->max(date('Y')); } }
在您的应用程序中使用它
use FormManager\Builder as F; F::addFactory(new CustomFields()); $date = F::form([ 'name' => F::text(), 'born-year' => F::year(), 'dead-year' => F::year(), ]);
其他用途是将应用程序的所有形式保存在一个命名空间下
namespace MyApp\Forms; use FormManager\Builder as F; use FormManager\Fields\Form; class EditUserForm extends Form { public function __construct() { $this->add([ 'name' => F::text()->maxlength(200)->label('Name'), 'email' => F::email()->label('Email'), 'password' => F::password()->label('Password'), 'repeat_password' => F::password()->label('Repeat password') ]); //Add a validator to check the password $this->addValidator('password-check', function($form) { $password1 = $form['password']->val(); $password2 = $form['repeat_password']->val(); if ($password1 !== $password2) { throw new FormManager\InvalidValueException('The passwords does not match'); } }); } }
并创建一个工厂
use FormManager\FactoryInterface; class MyForms implements FactoryInterface { public function get($name, array $arguments) { $class = 'MyApp\\Forms\\'.ucfirst($name); if (class_exists($class)) { return new $class(); } } }
使用它
use FormManager\Builder as F; F::addFactory(new MyForms()); $editUser = F::editUserForm();
注意:每次您注册一个新的工厂时,它将被添加到已注册的工厂之前,所以如果您注册了名为“表单”、“文本区域”等字段/容器,它们将替换默认值。这允许您扩展它们。
构建器实例
静态构建器对于大多数情况都很好,但有时您需要将不同的构建器与不同的工厂组合。因此,您可以创建实例
use FormManager\Builder; use FormManager\Factory; //Create a builder instance adding the default FormManager factory: $b1 = new Builder(new Factory()); //Create another builder instance with your custom factory: $b2 = new Builder(); $b2->add(new MyCustomFactory()); //Now, you're ready to combine them: $form = $b1->form([ 'name' => $b1->text(), 'description' => $b2->textarea(), 'email' => Builder::email() ]);