写模板的时候,开发者大多的时间致力于表单,尽管如此,表单通常难以设计。因为要关心很多的比如:默认值、格式、验证、重新获取以及表单获取等等,一些开发者使者去略过一些重要的处理细节。Symfony可以自动化许多以上需要并能加速表单开发:
l 表单助手提供了在模板中快速写输入表单的方法,特别是对于复杂元素:时间、下拉列别、富文本框等
l 当表单是是编辑对象的属性时,模板可以使用对象表单助手加速。
l YAML验证文件可以简化表单验证与重新获取
验证器对验证输入的代码打包, symfony 对最常用的验证器进行绑定,并且很容易的加入自定义验证器。表单助手
模板中,表单元素的HTML标签经常混合PHP代码。Symfony中的表单助手能帮着简化这种任务。
主表单标签
前面已经说过,必须使用form_tag()助手创建表单,因为他转换用户URL到路由RUL。
<?php echo form_tag('test/save') ?> => <form method="post" action="/path/to/save">
<?php echo form_tag('test/save', 'method=get multipart=true class=simpleForm') ?> => <form method="get" enctype="multipart/form-data" class="simpleForm"action="/path/to/save"> |
因为form_tag没有</form>标签,你最好在HTML代码中加上,虽然这看上去很不好。
标准表单元素
// 文本框 (input) <?php echo input_tag('name', 'default value') ?> => <input type="text" name="name" id="name" value="default value" />
// 所有的表单助手接受额外的参数 // 允许你加入自定义属性 <?php echo input_tag('name', 'default value', 'maxlength=20') ?> => <input type="text" name="name" id="name" value="default value"maxlength="20" />
// (text area) <?php echo textarea_tag('name', 'default content', 'size=10x20') ?> => <textarea name="name" id="name" cols="10" rows="20"> default content </textarea>
// Check box <?php echo checkbox_tag('single', 1, true) ?> <?php echo checkbox_tag('driverslicense', 'B', false) ?> => <input type="checkbox" name="single" id="single" value="1"checked="checked" /> <input type="checkbox" name="driverslicense" id="driverslicense"value="B" />
// Radio button <?php echo radiobutton_tag('status[]', 'value1', true) ?> <?php echo radiobutton_tag('status[]', 'value2', false) ?> => <input type="radio" name="status[]" id="status_value1" value="value1"checked="checked" /> <input type="radio" name="status[]" id="status_value2" value="value2" />
// Dropdown list (select) <?php echo select_tag('payment', '<option selected="selected">Visa</option> <option>Eurocard</option> <option>Mastercard</option>') ?> => <select name="payment" id="payment"> <option selected="selected">Visa</option> <option>Eurocard</option> <option>Mastercard</option> </select>
// List of options for a select tag <?php echo options_for_select(array('Visa', 'Eurocard', 'Mastercard'), 0) ?> => <option value="0" selected="selected">Visa</option> <option value="1">Eurocard</option> <option value="2">Mastercard</option>
// Dropdown helper combined with a list of options <?php echo select_tag('payment', options_for_select(array( 'Visa', 'Eurocard', 'Mastercard' ), 0)) ?> => <select name="payment" id="payment"> <option value="0" selected="selected">Visa</option> <option value="1">Eurocard</option> <option value="2">Mastercard</option> </select>
// To specify option names, use an associative array <?php echo select_tag('name', options_for_select(array( 'Steve' => 'Steve', 'Bob' => 'Bob', 'Albert' => 'Albert', 'Ian' => 'Ian', 'Buck' => 'Buck' ), 'Ian')) ?> => <select name="name" id="name"> <option value="Steve">Steve</option> <option value="Bob">Bob</option> <option value="Albert">Albert</option> <option value="Ian" selected="selected">Ian</option> <option value="Buck">Buck</option> </select>
// Dropdown list with multiple selection (selected values can be an array) <?php echo select_tag('payment', options_for_select( array('Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard'), array('Visa', 'Mastecard'), ), array('multiple' => true))) ?>
=> <select name="payment[]" id="payment" multiple="multiple"> <option value="Visa" selected="selected">Visa</option> <option value="Eurocard">Eurocard</option> <option value="Mastercard">Mastercard</option> </select> // Drop-down list with multiple selection (selected values can be an array) <?php echo select_tag('payment', options_for_select( array('Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard'), array('Visa', 'Mastecard') ), 'multiple=multiple') ?> => <select name="payment" id="payment" multiple="multiple"> <option value="Visa" selected="selected"> <option value="Eurocard">Eurocard</option> <option value="Mastercard" selected="selected">Mastercard</option> </select>
// Upload file field <?php echo input_file_tag('name') ?> => <input type="file" name="name" id="name" value="" />
// Password field <?php echo input_password_tag('name', 'value') ?> => <input type="password" name="name" id="name" value="value" />
// Hidden field <?php echo input_hidden_tag('name', 'value') ?> => <input type="hidden" name="name" id="name" value="value" />
// Submit button (as text) <?php echo submit_tag('Save') ?> => <input type="submit" name="submit" value="Save" />
// Submit button (as image) <?php echo submit_image_tag('submit_img') ?> => <input type="image" name="submit" src="/images/submit_img.png" /> |
处理表单提交 | ||
动作需要使用$this->getRequestParameter($elem)获取提交表单的值。 一个好的方式是使用同一个动作来显示与处理表单,通过请求方法,或者表单被调用或者被处理并且请求被转向其他动作。
要能工作,表单目的地必须与显示的一致
|
时间输入
表单经常被用来获取时间,时间格式错误是表单提交错误中主要的部分。 Input_date_tag 助手能够提供一个交互的 JS 日历,如果设置 rich 属性为 true 则显示如下图:
如果没有设置rich属性或者设置为false,则显示三个<select>标签分别选择年、月和日。也可以使用select_day_tag(), select_month_tag(), and select_year_tag()来实现。时间输入的默认值是当前时间,可以以第二个参数传递过去:
<?php echo input_date_tag('dateofbirth', '
2005-05-03
', 'rich=true') ?>
=>上图格式,只是默认时间不是
// 下面的助手需要DateForm助手组 <?php use_helper('DateForm') ?>
<?php echo select_day_tag('day', 1, 'include_custom=天') ?> => <select name="day" id="day">
<option value="">日</option> <option value="1" selected="selected">01</option>
<option value="2">02</option>
...
<option value="31">31</option>
</select>
<?php echo select_month_tag('month', 1, 'include_custom=月 use_short_month=true') ?> => <select name="month" id="month">
<option value="">月</option> <option value="1" selected="selected">Jan</option>
<option value="2">Feb</option>
...
<option value="12">Dec</option>
</select>
<?php echo select_year_tag('year', 2007, 'include_custom=年 year_end=2010') ?> => <select name="year" id="year">
<option value="">年</option> <option value="2006">2006</option>
<option value="2007" selected="selected">2007</option>
...
</select>
|
Input_date_tag()助手可接受的时间值有PHP的strtotime()方法决定:
// 合法格式 <?php echo input_date_tag('test', '
2006-04-01
', 'rich=true') ?>
<?php echo input_date_tag('test', 1143884373, 'rich=true') ?>
<?php echo input_date_tag('test', 'now', 'rich=true') ?>
<?php echo input_date_tag('test', '23 October 2005', 'rich=true') ?>
<?php echo input_date_tag('test', 'next tuesday', 'rich=true') ?>
<?php echo input_date_tag('test', '1 week 2 days 4 hours 2 seconds', 'rich=true') ?>
// 返回空 <?php echo input_date_tag('test', null, 'rich=true') ?>
<?php echo input_date_tag('test', '', 'rich=true') ?>
// 零 = 01/01/1970 <?php echo input_date_tag('test', 0, 'rich=true') ?>
// 非英语格式不能工作 <?php echo input_date_tag('test', '
01/04/2006
', 'rich=true') ?>
|
文本编辑器
需要手动安装,具体参阅http://tinymce.moxiecode.com。下载文件而后加压缩至web/js目录,然后修改settings.yml文件以激活编辑器
all:
.settings:
rich_text_js_dir: js/tiny_mce
|
然后在模板中的文本区表单中加入rich=true即可。
国家与语言选择器
国家标签助手
<?php echo select_country_tag('country', '
AL
') ?>
=> <select name="country" id="country">
<option value="AF">
Afghanistan
</option>
<option value="
AL
" selected="selected">
Albania
</option>
<option value="DZ">
Algeria
</option>
<option value="AS">
American Samoa
</option>
|
语言标签助手
<?php echo select_language_tag('language', 'en') ?>
=> <select name="language" id="language">
...
<option value="elx">Elamite</option>
<option value="en" selected="selected">English</option>
<option value="enm">English, Middle (1100-1500)</option>
<option value="ang">English, Old (ca.450-1100)</option>
<option value="myv">Erzya</option>
<option value="eo">Esperanto</option>
…… |
对象表单助手
当表单编辑对象属性是,标准助手将变得很麻烦,例如,编译客户对象的电话属性:
<?php echo input_tag('telephone', $customer->getTelephone()) ?>
=> <input type="text" name="telephone" id="telephone" value="0123456789" />
|
Symfony提供了对象表单助手来简化此类操作:
<?php echo object_input_tag($customer, 'getTelephone') ?>
=> <input type="text" name="telephone" id="telephone" value="0123456789" />
|
对象表单助手在使用前必须应用user_helper(“Object”),供提供了下列方法:
<?php echo object_input_tag($object, $method, $options) ?>
<?php echo object_input_date_tag($object, $method, $options) ?>
<?php echo object_input_hidden_tag($object, $method, $options) ?>
<?php echo object_textarea_tag($object, $method, $options) ?>
<?php echo object_checkbox_tag($object, $method, $options) ?>
<?php echo object_select_tag($object, $method, $options) ?>
<?php echo object_select_country_tag($object, $method, $options) ?>
<?php echo object_select_language_tag($object, $method, $options) ?>
|
注意,没有object_password_tag()助手,因为他不需要获取对象的属性值并显示出来。
使用对象生成下拉列表
//使用options_for_select()创建选项列表 <?php echo options_for_select(array(
'1' => 'Steve',
'2' => 'Bob',
'3' => 'Albert',
'4' => 'Ian',
'5' => 'Buck'
), 4) ?>
=> <option value="1">Steve</option>
<option value="2">Bob</option>
<option value="3">Albert</option>
<option value="4" selected="selected">Ian</option>
<option value="5">Buck</option>
|
假定你已经有一个从Propel查询集得到一个Author类对象的数组,要建议基于这个数组的选项列表,你需要循环获取每个对象的id和名称
动作中 |
$options = array();
foreach ($authors as $author)
{
$options[$author->getId()] = $author->getName();
}
$this->options = $options;
|
模板中 |
<?php echo options_for_select($options, 4) ?>
|
这种情况下,symfony提供了一个助手objects_for_select()来自动完成,objects_for_select()助手直接使用对象数组,他需要2个额外的参数:方法名称和<option>标签的名字:
直接在模板中获取 |
<?php echo objects_for_select($authors, 'getId', 'getName', 4) ?>
|
这很智能且快速,但symfony还能做的更好,特别是有外键关联的列上。
基于外键列创建下拉列表
外键值是外键表的主键值,例如,文章表的author_id是author表的外键,这个列可能的值都在author表的id中出现,使用下面的代码创建选项列表:
<?php echo select_tag('author_id', objects_for_select(AuthorPeer::doSelect(new Criteria()),' getId', '__toString', $article->getAuthorId())) ?>
=> <select name="author_id" id="author_id">
<option value="1">Steve</option>
<option value="2">Bob</option>
<option value="3">Albert</option>
<option value="4" selected="selected">Ian</option>
<option value="5">Buck</option>
</select>
|
Object_select_tag助手可以自动完成上面的部分,他会从schema中获取部分信息。
<?php echo object_select_tag($article, 'getAuthorId') ?>
|
Object_select_tag助手根据传递过来的方法名猜测相关的peer类名(根据getAuthorID方法得到AuthorPeer类),你也可以通过第三个参数制定你自己的类作为关联类。<option>的内容文本是对象类的__toString()方法的结果(如果$author->__toString方法不存在则使用主键替代)。另外可以通过Criteria来限定获取的条数。最后可以加入空选项或自定义选项显示在下拉列表的顶部,看下面的例子:
// 基本语法 <?php echo object_select_tag($article, 'getAuthorId') ?>
// 通过方法AuthorPeer::doSelect(new Criteria())
// 修改peer类 <?php echo object_select_tag($article, 'getAuthorId', 'related_class=Foobar') ?>
// 通过方法FoobarPeer::doSelect(new Criteria())
// 修改Peer方法 <?php echo object_select_tag($article, 'getAuthorId','peer_method=getMostFamousAuthors') ?>
// 通过方法AuthorPeer::getMostFamousAuthors(new Criteria())
// 在列表顶部添加 <option value=""> </option> <?php echo object_select_tag($article, 'getAuthorId', 'include_blank=true') ?>
//在列表顶部添加<option value="">Choose an author</option> <?php echo object_select_tag($article, 'getAuthorId', 'include_custom=Choose an author') ?>
|
更新对象
在动作中,很容易地去处理使用对象助手编辑对象属性的表单提交,比如,有一个包含name、age和address属性的Author类对象,表单显示代码可能为:
<?php echo form_tag('author/update') ?>
<?php echo object_input_hidden_tag($author, 'getId') ?>
Name: <?php echo object_input_tag($author, 'getName') ?><br />
Age: <?php echo object_input_tag($author, 'getAge') ?><br />
Address: <br />
<?php echo object_textarea_tag($author, 'getAddress') ?>
</form>
|
表单提交时会调用update动作,调用Proel的fromArray()方法可以很容易的更新对象。
public function executeUpdate ()
{
$author = AuthorPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($author);
$author->fromArray($this->getRequest()->getParameterHolder()->getAll(),AuthorPeer::TYPE_FIELDNAME);
$author->save();
return $this->redirect('/author/show?id='.$author->getId());
|
表单验证
前面提到在动作类中如何使用validateXXX()方法验证请求参数。但是,如果你使用这种方式来验证表单提交,你不得不重复地重写(再三地写)同样的部分。Symfony提供了表单验证技术,只用YAML文件而不是动作类中的PHP代码。
要演示表单验证特性,让我们考虑下面的表单(经典联系人表单,有name、email、age和message字段)例子:modules/contact/templates/indexSuccess.php
<?php echo form_tag('contact/send') ?>
Name: <?php echo input_tag('name') ?><br />
Email: <?php echo input_tag('email') ?><br />
Age: <?php echo input_tag('age') ?><br />
Message: <?php echo textarea_tag('message') ?><br />
<?php echo submit_tag() ?>
</form> //这是一种好习惯,虽然看起来不好 |
规则是:如果用户输入了非法数据并提交了表单,下一页会显示错误信息,让我们定义验证的具体内容:
l Name必须,长度2到100
l Email必须,长度2到100,必须是合法邮件地址
l Age必须,大小在1到120
l Message必须
表单验证可以在服务端 和/或 客户端,服务端验证是必须的,可以防止数据库错误数据的写入,客户端是可选的,但却可以大大提升用户体验,客户端验证使用JS。
验证器
有些验证规则被频繁的使用,symfony就将他们打包做成验证器。验证器是一个提供execute()方法的简单类,方法需要一个字段值作为参数,并返回真或假。
现在让我们来看看sfStringValidator,他验证输入是否是字符串,并且长度是否在两个数字之间,这就是必须的验证器:modules/contact/action/actions.class.php
public function validateSend()
{
$name = $this->getRequestParameter('name');
// name必须 if (!$name)
{
$this->getRequest()->setError('name', 'name不能为空');
return false;
}
// name必须且长度在2到100之间 $myValidator = new sfStringValidator();
$myValidator->initialize($this->getContext(), array(
'min' => 2,
'min_error' => 'name太短,至少2个字符', 'max' => 100,
'max_error' => ' name太长,最多100个字符', ));
if (!$myValidator->execute($name))
{
return false;
}
return true;
}
|
如果用户发送表单是name不符合规定,则sfStringValidator返回false,validateSend()方法将失败,handleErrorSend()方法将替代executeSend()方法被调用
sfRequest的setError()方法传递信息给模板以显示错误信息。验证器在内部设置错误信息,可以根据不同的错误设置不同的信息。
将描述转换为代码:
l
name
: sfStringValidator
(min=2
, max=100
)
l
email
: sfStringValidator
(min=2
, max=100
) 和 sfEmailValidator
l
age
: sfNumberValidator
(min=0
, max=120
)
事实上,验证器不能处理表单非空验证。
验证文件
你可以简单的使用validateSend()方法来实施表单的验证,但这很不好,每个验证都要重复许多的代码。Symfony提供了两外的方式来定义表单验证规则,包含在YAML中。
例如:modules/contact/validate/send.yml
fields:
name:
required: //必须 msg: name不能为空 sfStringValidator:
min: 2 //最小长度 min_error: name太短,至少2个字符 max: 100
max_error: name太长,最多100个字符 |
验证器在某项验证失败后不会停止,他会测试所有的验证,即使验证失败了,symfony也仍然去查找validateXXX()方法并执行,所以两个验证是相互补充的。这样做的好处是,一个表单提交可能包含多个错误,可以把所有的错误信息全部显示出来。
验证文件放在模块的validate目录下,并且以要验证的动作命名。
重新显示表单
默认情况,symfony在验证失败后查找handleErrorSend()方法,方法不存在则显示sendError.php模板。但一般是验证失败后重新显示表单并列出错误信息,要这么做,你需要覆盖handleErrorSend()方法并且以转向表单显示结束:modules/contact/actions/actions.class.php
class ContactActions extends sfActions
{
public function executeIndex()
{
// 显示表单 }
public function handleErrorSend()
{
$this->forward('contact', 'index');
}
public function executeSend()
{
// 验证表单提交 }
}
|
如果选择使用同样的动作显示表单并处理表单提交,可以使handleErrorSend()方法简单的返回sfView::SUCCESS去通过sendSuccess.php显示表单:modules/contact/actions/actions.class.php
class ContactActions extends sfActions
{
public function executeSend()
{
if ($this->getRequest()->getMethod() != sfRequest::POST)
{
// 为模板准备数据
// 显示表单 return sfView::SUCCESS;
}
else
{
// 处理表单提交 ...
$this->redirect('mymodule/anotheraction');
}
}
public function handleErrorSend()
{
// 为模板准备数据
// 显示表单 return sfView::SUCCESS;
}
}
|
这时,当用户输入了非法的name,表单将再次显示,但输入的数据没了,错误信息也不显示,你需要去修改显示表单的模板,在出错的地方插入错误信息。
在表单中显示错误信息
错误信息在表单验证失败后被作为参数加入到了请求中(你也可以手动方式加入错误信息,通过setError()方法)。sfRequest对象提供了连个游泳的方法来获取错误信息:hasError和getError,每个方法都要求将field名字作为参数传送。另外,还要在表单的上部显示一个警告来显示所有错误的集合:templates/indexSuccess.php
<?php if ($sf_request->hasErrors()): ?>
<p>The data you entered seems to be incorrect.
Please correct the following errors and resubmit:</p>
<ul>
<?php foreach($sf_request->getErrors() as $name => $error): ?>
<li><?php echo $name ?>: <?php echo $error ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
|
在每个有错误的表单附近显示单独的错误:templates/indexSuccess.php
<?php echo form_tag('contact/send') ?>
<?php if ($sf_request->hasError('name')): ?>
<?php echo $sf_request->getError('name') ?> <br />
<?php endif; ?>
Name: <?php echo input_tag('name') ?><br />
...
<?php echo submit_tag() ?>
</form>
|
使用getError()方法看起来有些长,symfony提供了一个form_error()助手来代替:
<?php use_helper('Validation') ?>
<?php echo form_tag('contact/send') ?>
<?php echo form_error('name') ?><br />
Name: <?php echo input_tag('name') ?><br />
...
<?php echo submit_tag() ?>
</form>
|
Form_error()助手在错误信息的前后添加了特殊的字符来更容易的查看错误,默认字符使用下箭头($darr;),可以在settings.yml文件中修改:
all:
.settings:
validation_error_prefix: ' ↓ '
validation_error_suffix: ' ↓'
|
上面解决了错误信息显示的问题,但用户输入的内容没了,下一步来解决。
重新注入表单
当错误被捕获,原始请求信息仍然可以访问,用户输入的信息还在请求参数中。因此可以通过为每个field加入默认值的方式重新将数据注入表单:templates/indexSuccess.php
<?php use_helper('Validation') ?>
<?php echo form_tag('contact/send') ?>
<?php echo form_error('name') ?><br />
Name: <?php echo input_tag('name', $sf_params->get('name')) ?><br />
<?php echo form_error('email') ?><br />
Email: <?php echo input_tag('email', $sf_params->get('email')) ?><br />
<?php echo form_error('age') ?><br />
Age: <?php echo input_tag('age', $sf_params->get('age')) ?><br />
<?php echo form_error('message') ?><br />
Message: <?php echo textarea_tag('message', $sf_params->get('message')) ?><br />
<?php echo submit_tag() ?>
</form>
|
同样,这种方式相当乏味,symfony提供了另一种方式来解决问题,也是直接在YAML验证文件,只要激活表单的fillin:特性:validate/send.yml
fillin:
enabled: true # 激活表单重注入特性 param:
name: test # 表单名,如果页面中只有一个表单则不是必须的 skip_fields: [email] # 不注入的field exclude_types: [hidden, password] # 不注入的field类型 check_types: [text, checkbox, radio, password, hidden] # 检查类型
//转换内容 converters: # 实施转换 htmlentities: [first_name, comments]
htmlspecialchars: [comments]
|
重注入默认对text inputs、check boxex、radio buttons、text areas以及select 组件 (simple and multiple)起作用,而对password或hidden标签不起作用。
标准symfony验证器
Symfony
中包含的标准验证器有:
l sfStringValidator
l sfNumberValidator
l sfEmailValidator
l sfUrlValidator
l sfRegexValidator
l sfCompareValidator
l sfPropelUniqueValidator
l sfFileValidator
l sfCall
l backValidator
每个验证器都有默认的一组参数和错误信息,你可以通过覆盖initialize()来修改或者在YAML文件中。
String Validator
sfStringValidator
对字符串相关约束进行验证:
sfStringValidator:
values: [foo, bar]
values_error: The only accepted values are foo and bar
insensitive: false # 如果设置为真则比较的时候区分大小写 min: 2
min_error: 至少2个字符 max: 100
max_error: 最多100个字符 |
Number Validator
sfNumberValidator
检验数字约束
sfNumberValidator:
nan_error: 请输入数字 min: 0
min_error: 不得小于0 max: 100
max_error: 不得大于100 |
E-Mail Validator
sfEmailValidator
检验是否有内容且符合格式合法
sfEmailValidator:
strict: true
email_error: 邮件格式不合法 |
合法的邮件格式是由RFC822定义的,然而,他却比验证器规定的宽松的多,比如:me@localhost在RFC822中是合法的邮件格式,但却不能被验证器验证通过,把strict设置为false则使用RFC822的标准。
URL Validator
sfUrlValidator
检验URL约束
sfUrlValidator:
url_error: URL地址错误 |
Regular Expression Validator
sfRegexValidator
使用perl兼容的正则表达式来验证约束
sfRegexValidator:
match: No
match_error: 提交中包含多个URL时被认为是垃圾地址 pattern: /http.*http/si
|
Compare Validator
sfCompareValidator
检测两个请求参数是否相等,对于密码检测很有用
fields:
password1:
required:
msg: 请输入密码 password2:
required:
msg: 请再次输入密码 sfCompareValidator:
check: password1
compare_error: 两次输入的密码不一致 |
Propel Unique Validator
sfPropelUniqueValidator
验证数据在数据库是否已经存在,对于唯一字段非常好用。
fields:
nickname:
sfPropelUniqueValidator:
class: User
column: login
unique_error: 此用户已经存在,请换一个 |
File Validator
sfFileValidator
验证文件上传的信息
fields:
image:
required:
msg: 请选择上传文件 file: True
sfFileValidator:
mime_types:
- 'image/jpeg'
- 'image/png'
- 'image/x-png'
- 'image/pjpeg'
mime_types_error: 只能上传PNG和JPEG文件 max_size: 512000
max_size_error: 最大上传512K |
Callback Validator
sfCallbackValidator
代理第三方验证,第三方必须返回真或假。
fields:
account_number:
sfCallbackValidator:
callback: is_integer
invalid_error: 请输入一个数字 credit_card_number:
sfCallbackValidator:
callback: [myTools, validateCreditCard]
invalid_error: 请输入合法的信用卡号 |
Named Validators
不多说了,看代码吧:validate/send.yml
validators:
myStringValidator:
class: sfStringValidator
param:
min: 2
min_error: This field is too short (2 characters minimum)
max: 100
max_error: This field is too long (100 characters maximum)
fields:
name:
required:
msg: The name field cannot be left blank
myStringValidator:
email:
required:
msg: The email field cannot be left blank
myStringValidator:
sfEmailValidator:
email_error: This email address is invalid
|
限制验证的方法(POST GET)
默认情况下,动作被POST方法调用的时候验证器运行,你可以修改默认的设置:
methods: [post] # 默认设置
fields:
name:
required:
msg: The name field cannot be left blank
myStringValidator:
email:
methods: [post, get] # 覆盖全局的设置 required:
msg: The email field cannot be left blank
myStringValidator:
sfEmailValidator:
email_error: This email address is invalid
|
完整验证文件示例
fillin:
enabled: true
validators:
myStringValidator:
class: sfStringValidator
param:
min: 2
min_error: 最少2个字符 max: 100
max_error: 最多两个字符
fields:
name:
required:
msg: name不能为空 myStringValidator:
email:
required:
msg: email必须填写 myStringValidator:
sfEmailValidator:
email_error: email不合法 age:
sfNumberValidator
nan_error: Please enter an integer
min: 0
min_error: "还没出生呢!!怎么发送消息?" max: 120
max_error: "嘿,老爷爷,您还能上网呢??" message:
required:
msg: message字段不能为空 |
复杂验证
创建自定义验证器
每个验证器都是继承自sfValidator的类,如果symfony提供的验证器忙组不了你的需求,你可以在任何lib目录下自创一个。语法很简单:在initialize()方法中定义默认设置,在execute()方法中写验证信息。
Execute()方法获取第一个参数作为验证对象,第二个参数作为错误信息,所有传递都是引用传递,所以可以在方法内部修改错误信息。
Initialize()方法接受单例模式的上下文和YAML文件中的参数数组,它必须先调用父类sfValidator的initialize()方法,然后设定默认值。
每个验证器都有一个参数仓库:$this->getParameterHolder()
举例:建立一个sfSpamValidator来验证一个字符串不是spam(散发者,比如在URL中包含另一个URL,在用户不知不觉中引入到别的地方),他检测$value是否包含比max_url次多的“http”字符串。在任意的lib目录下建立sfSpamValidator.class.php文件:
class sfSpamValidator extends sfValidator
{
public function execute (&$value, &$error)
{
// 如果max_url=2, 正则表达式为 /http.*http/is $re = '/'.implode('.*', array_fill(0, $this->getParameter('max_url') + 1, 'http')).'/is';
if (preg_match($re, $value))
{
$error = $this->getParameter('spam_error');
return false;
}
return true;
}
public function initialize ($context, $parameters = null)
{
// 调用父类initialize() parent::initialize($context);
// 设置默认参数值 $this->setParameter('max_url', 2);
$this->setParameter('spam_error', 'This is spam');
// 设置参数 $this->getParameterHolder()->add($parameters);
return true;
}
}
|
使用方式如下:validate/send.yml
fields:
message:
required:
msg: message不能为空 sfSpamValidator:
max_url: 3
spam_error: 快离开这个站点,他是spammer |
在表单中使用数组
PHP允许在表单中使用数组语法,示例代码:
<label for="story[title]">Title:</label>
<input type="text" name="story[title]" id="story[title]" value="default value" size="45" />
|
这时,若直接把带有[]的字段放入验证文件将会出现解析错误,解决方式是使用{}代替[]:
fields:
story{title}:
required: Yes
|
在空字段上执行验证
对于非必填字段也可能需要验证,例如用户修改密码:
fields:
password1:
password2:
sfCompareValidator:
check: password1
compare_error: 两次输入的密码不符 |
验证过程如下:
l 如果password1 == null 并且 password2 == null:
n 必需验证通过(不是必需字段)
n 验证器不运行
n 提交表单有效
l 如果password2 == null 而password1 不是null:
n 必需验证通过(不是必需字段)
n 验证器不运行
n 提交表单有效
但希望在password1非空的时候验证password2,幸运的是,symfony验证器能处理这种情况——使用分组参数。分组中的字段在非空或者一个非空的时候会被验证。所以修改验证代码如下:
fields:
password1:
group: password_group
password2:
group: password_group
sfCompareValidator:
check: password1
compare_error: 两次输入的密码不符 |
验证过程如下:
l
如果password1 == null 并且 password2 == null:
n
必需验证通过
n
验证器不运行
n
提交表单有效
l
Password1 == null
并且 password2 == “foo”:
n
必须验证通过
n
Password2
非空,验证器执行并验证失败
n
错误信息抛给password2
l
Password1 ==
“foo” 并且 password2 == null:
n
必须验证通过
n
Password1
非空,password2的验证器被执行且验证失败
n
错误信息抛给password2
l
Password1 ==
“foo” 并且 password2 == “foo”:
n
必须验证通过
n
Password2
非空,验证器执行并验证通过
n
提交表单有效