-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial.Form Generation and Validation II.zh_cn
- 添加其他类型的表单
3.1 创建注册页
接下来两节,我将以注册页面为例介绍下如何添加其他类型的表单、添加自定义表单以及自定义表单验证。
在Form目录下创建RegisterForm.php文件,并添加如下代码:
路径:usr/module/member/src/Form/RegisterForm.php
Code 3.3.1
<?php
namespace Module\Member\Form;
use Pi\Form\Form as BaseForm;
class RegisterForm extends BaseForm
{
public function init()
{
$this->add(array(
'name' => 'username',
'options' => array(
'label' => __('Username'),
),
'attributes' => array(
'type' => 'text',
),
));
$this->add(array(
'name' => 'password',
'options' => array(
'label' => __('Password'),
),
'attributes' => array(
'type' => 'password',
),
));
$this->add(array(
'name' => 'repeat-password',
'options' => array(
'label' => __('Repeat Password'),
),
'attributes' => array(
'type' => 'password',
),
));
$this->add(array(
'name' => 'gender',
'options' => array(
'label' => __('Gender'),
),
'attributes' => array(
'value' => 'm',
'options' => array(
'm' => __('Male'),
'f' => __('Female'),
),
),
'type' => 'radio',
));
$this->add(array(
'name' => 'country',
'options' => array(
'label' => __('Country'),
),
'attributes' => array(
'type' => 'select',
'value' => 'chn',
'options' => array(
'chn' => __('China'),
'usa' => __('United States'),
),
),
));
$this->add(array(
'name' => 'feedback',
'options' => array(
'label' => __('Do you want to contact us?'),
),
'attributes' => array(
'value' => 0,
),
'type' => 'checkbox',
));
$this->add(array(
'name' => 'introduction',
'options' => array(
'label' => __('Introduction'),
),
'attributes' => array(
'type' => 'textarea',
'cols' => 50,
'rows' => 5,
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'value' => __('Create'),
),
'type' => 'submit',
));
}
}
在这段代码里,我们创建几种类型的表单,包括text, password, radio, select, checkbox, textarea和submit。像radio, select和checkbox/multiCheckbox这几类可能会生成多个表单的的表单,需要在attributes字段里增加options字段来标识不同的表单,这些表单都在同一个组里,而value值就是默认被选中的表单,其值也就是options里的键值。需要注意的是,radio和checkbox的type字段不能写在attributes数组里,否则会报错。另外attributes里还可以添加其他参数,如'class' => 'btn'将会生成class="btn",这样开发者也可以自定义表单标签里的内容。
在src/Controller/Front目录下创建RegisterController.php并添加如下代码:
路径:usr/module/member/src/Controller/Front/RegisterController.php
Code 3.3.2
<?php
namespace Module\Member\Controller\Front;
use Pi\Mvc\Controller\ActionController;
use Module\Member\Form\RegisterForm;
class RegisterController extends ActionController
{
protected function renderForm()
{
$form = new RegisterForm('register');
$form->setAttribute('action', $this->url('', array('action' => 'index')));
return $form;
}
public function indexAction()
{
$form = $this->renderForm();
$this->view()->assign('form', $form);
$this->view()->assign('title', __('Register member'));
}
}
在template/front目录下创建register-index.phtml并添加如下代码:
路径:usr/module/member/template/register-index.phtml
Code 3.3.3
<h2><?php echo $title; ?></h2>
<?php if (isset($error)) {
echo $error;
} ?>
<?php echo $this->form()->openTag($form) ?>
<div id="member-register-username">
<?php $element = $form->get('username'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-password">
<?php $element = $form->get('password'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-repeat-password">
<?php $element = $form->get('repeat-password'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-gender">
<?php $element = $form->get('gender'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-country">
<?php $element = $form->get('country'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-feedback">
<?php $element = $form->get('feedback'); ?>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="member-register-introduction">
<?php $element = $form->get('introduction'); ?>
<div><?php echo $this->formLabel($element) ?></div>
<div><?php
echo $this->formElement($element);
echo $this->formElementErrors($element); ?>
</div>
</div>
<div id="login-login-submit">
<?php $element = $form->get('submit'); ?>
<div><?php echo $this->formElement($element) ?></div>
</div>
<?php echo $this->form()->closeTag() ?>
在浏览器访问localhost/course/www/member/register将会看下如下页面:
图3-5 member模块注册页
3.2 扩展表单
上述例子中,我们只是将所有的配置参数通过add()方法传递给Form类,对于country我们只是写了两条记录,但实际上这一项会有一两百条记录,如果都只是通过这种方式添加,会使代码难以阅读,并且工作量也很大,一般这种数据可以保存在数据库或文件里,因此我们可以创建一个类继承自Select类,动态生成表单。在此以select表单为例介绍下如何动态创建表单。
首先需要修改RegisterForm类里country表单的类型:
路径:usr/module/member/src/Form/RegisterForm.php
Code 3.3.4
...
$this->add(array(
'name' => 'country',
'options' => array(
'label' => __('Country'),
),
'type' => 'Module\Member\Form\Element\CountrySelect',
));
....
在代码里,我们把type的类型修改为一个命名空间的形式,CountrySelect就是我们要创建的类。需要注意的是,type字段此时不能放在attributes数组里,否则会报错。根据这个命名规则,我们需要在Form目录下创建Element目录,并在Element里创建CountrySelect.php文件。
member
|- src
|- Form
|- Element
|- CountrySelect.php
路径:usr/module/member/src/Form/Element/CountrySelect.php
Code 3.3.5
<?php
namespace Module\Member\Form\Element;
use Zend\Form\Element\Select;
class CountrySelect extends Select
{
protected $countries = array(
'chn' => 'China',
'usa' => 'United States',
'jpn' => 'Japan',
'uk' => 'United Kindom',
);
public function getValueOptions()
{
if (empty($this->valueOptions)) {
foreach ($this->countries as $key => $country) {
$options[$key] = __($country);
}
$this->valueOptions = $options;
}
return $this->valueOptions;
}
}
在这段代码里,我们首先定义了命名空间,同时引用了CountrySelect类要继承的类-- Zend\Form\Element\Select,这个就是之前在RegisterForm里指定的select类型对应的类。
在类里,由于暂时还没介绍数据库操作,我们这里手动添加了一些国家的信息,同时创建getValueOptions()方法来覆盖基类的这个方法,在getValueOptions()里,我们把coutries里的值都添加翻译,然后赋给valueOptions变量,这样select里的值就被更改了。
图3-6 表单扩展
开发者可以运用同样的方法来扩展其他表单,实现自定义功能。