Zend_Validate-WritingValidators.xml 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <sect1 id="zend.validate.writing_validators">
  2. <title>编写校验器</title>
  3. <para>
  4. 尽管提供了一组通用的校验器,但不可避免地,开发者还将为他们特定的需求来编写定制的校验器。编写定制的校验器的任务将在本节描述。
  5. </para>
  6. <para>
  7. <code>Zend_Validate_Interface</code> 定义了三个方法,<code>isValid()</code>,<code>getMessages()</code> 和 <code>getErrors()</code>, 为了创建校验对象,它们可以在用户的类里被实现。实现<code>Zend_Validate_Interface</code>接口的对象可以用<code>Zend_Validate::addValidator()</code> 添加到校验链里。这样的对象也可以和<link linkend="zend.filter.input"><code>Zend_Filter_Input</code></link>一起使用。
  8. </para>
  9. <para>
  10. 也许你已经从上面关于 的描述中推断出,不论一个值是否被校验成功,校验类为Zend Framework返回一个布尔值。它们也提供关于<emphasis role="bold">why</emphasis>一个值校验失败的信息。校验失败原因的有效性对于不同用途的应用程序可能很有价值,象为可用性分析提供的统计量。
  11. </para>
  12. <para>
  13. 基本校验失败消息的功能在<code>Zend_Validate_Abstract</code>中实现。当创建一个校验类,简单地扩展<code>Zend_Validate_Abstract</code>来包括这个功能。在扩展类里你将实现<code>isValid()</code> 方法逻辑和定义消息变量和消息模板,它和可能发生的校验失败类型相对应。如果校验测试一个值失败,<code>isValid()</code> 应该返回 <code>false</code>。如果这个值通过校验测试,<code>isValid()</code> 应该返回 <code>true</code>。
  14. </para>
  15. <para>
  16. 一般地,<code>isValid()</code>方法不应该抛出任何异常,除了不可能决定输入值是否有效。一些抛出异常的合情合理的例子可能是如果文件不能被打开,LDAP服务器不能被联系,或者数据库连接无效,并且有些事情必须由校验成功或失败来决定。
  17. </para>
  18. <example id="zend.validate.writing_validators.example.simple">
  19. <title>创建简单校验类</title>
  20. <para>
  21. 下面的例子演示如何编写一个非常简单的定制的校验器。在这个例子中,校验规则简单,输入值必须是浮点数值。
  22. <programlisting role="php"><![CDATA[
  23. class MyValid_Float extends Zend_Validate_Abstract
  24. {
  25. const FLOAT = 'float';
  26. protected $_messageTemplates = array(
  27. self::FLOAT => "'%value%' is not a floating point value"
  28. );
  29. public function isValid($value)
  30. {
  31. $this->_setValue($value);
  32. if (!is_float($value)) {
  33. $this->_error();
  34. return false;
  35. }
  36. return true;
  37. }
  38. }
  39. ]]>
  40. </programlisting>
  41. 这个类为它的单个校验失败消息定义了一个模板,它包括内置的魔术参数,<code>%value%</code>。如果校验失败,对<code>_setValue()</code>的调用准备了自动插入被测试的值到失败消息的对象。对<code>_error()</code>的调用跟踪校验失败的原因。因为这个类只定义了一个失败消息,没有必要为<code>_error()</code>提供带有失败消息名字的模板。
  42. </para>
  43. </example>
  44. <example id="zend.validate.writing_validators.example.conditions.dependent">
  45. <title>编写有独立条件的校验类</title>
  46. <para>
  47. 下面的例子演示一组稍微复杂的校验规则,要求输入值是数字并有最小值和最大值的范围。由于下面确切的原因之一,输入值校验失败:
  48. <itemizedlist>
  49. <listitem>
  50. <para>输入值不是数字。</para>
  51. </listitem>
  52. <listitem>
  53. <para>输入值小于允许的最小值。</para>
  54. </listitem>
  55. <listitem>
  56. <para>输入值大于允许的最大值。</para>
  57. </listitem>
  58. </itemizedlist>
  59. </para>
  60. <para>
  61. 这些校验失败的原因被翻译为在类中的定义:
  62. <programlisting role="php"><![CDATA[
  63. class MyValid_NumericBetween extends Zend_Validate_Abstract
  64. {
  65. const MSG_NUMERIC = 'msgNumeric';
  66. const MSG_MINIMUM = 'msgMinimum';
  67. const MSG_MAXIMUM = 'msgMaximum';
  68. public $minimum = 0;
  69. public $maximum = 100;
  70. protected $_messageVariables = array(
  71. 'min' => 'minimum',
  72. 'max' => 'maximum'
  73. );
  74. protected $_messageTemplates = array(
  75. self::MSG_NUMERIC => "'%value%' is not numeric",
  76. self::MSG_MINIMUM => "'%value%' must be at least '%min%'",
  77. self::MSG_MAXIMUM => "'%value%' must be no more than '%max%'"
  78. );
  79. public function isValid($value)
  80. {
  81. $this->_setValue($value);
  82. if (!is_numeric($value)) {
  83. $this->_error(self::MSG_NUMERIC);
  84. return false;
  85. }
  86. if ($value < $this->minimum) {
  87. $this->_error(self::MSG_MINIMUM);
  88. return false;
  89. }
  90. if ($value > $this->maximum) {
  91. $this->_error(self::MSG_MAXIMUM);
  92. return false;
  93. }
  94. return true;
  95. }
  96. }
  97. ]]>
  98. </programlisting>
  99. Public 属性<code>$minimum</code> 和 <code>$maximum</code> 分别为成功校验一个值被建立用来提供最小和最大值边界。这个类也定义了两个消息变量和public属性相对应并允许<code>min</code> 和 <code>max</code> 与 <code>value</code> 一起被用在作为魔术参数的消息模板,
  100. </para>
  101. <para>
  102. 注意如果任何在<code>isValid()</code>中的校验检查失败,一个恰当的失败消息被准备,并且方法立即返回<code>false</code>。这些校验规则因此继续独立。换句话说,如果一个测试失败,不需要测试任何后来的校验规则。然而这本来不是个案例。下面的例子示例如何编写带有独立校验规则的类,校验对象返回什么校验企图失败的。
  103. </para>
  104. </example>
  105. <example id="zend.validate.writing_validators.example.conditions.independent">
  106. <title>带有独立条件、多重失败原因的校验</title>
  107. <para>
  108. 考虑编写一个为密码加强强度的校验类-当用户被要求为帮助使用户账户安全而选择符合一定条件的密码。让我们假设口令安全条件加强那个密码:
  109. <itemizedlist>
  110. <listitem>
  111. <para>至少8个字符长,</para>
  112. </listitem>
  113. <listitem>
  114. <para>包括至少一个大写字母,</para>
  115. </listitem>
  116. <listitem>
  117. <para>包括至少一个小写字母,</para>
  118. </listitem>
  119. <listitem>
  120. <para>并至少包括一个数字字符。</para>
  121. </listitem>
  122. </itemizedlist>
  123. </para>
  124. <para>
  125. 下面的类实现这些校验条件:
  126. <programlisting role="php"><![CDATA[
  127. class MyValid_PasswordStrength extends Zend_Validate_Abstract
  128. {
  129. const LENGTH = 'length';
  130. const UPPER = 'upper';
  131. const LOWER = 'lower';
  132. const DIGIT = 'digit';
  133. protected $_messageTemplates = array(
  134. self::LENGTH => "'%value%' must be at least 8 characters in length",
  135. self::UPPER => "'%value%' must contain at least one uppercase letter",
  136. self::LOWER => "'%value%' must contain at least one lowercase letter",
  137. self::DIGIT => "'%value%' must contain at least one digit character"
  138. );
  139. public function isValid($value)
  140. {
  141. $this->_setValue($value);
  142. $isValid = true;
  143. if (strlen($value) < 8) {
  144. $this->_error(self::LENGTH);
  145. $isValid = false;
  146. }
  147. if (!preg_match('/[A-Z]/', $value)) {
  148. $this->_error(self::UPPER);
  149. $isValid = false;
  150. }
  151. if (!preg_match('/[a-z]/', $value)) {
  152. $this->_error(self::LOWER);
  153. $isValid = false;
  154. }
  155. if (!preg_match('/\d/', $value)) {
  156. $this->_error(self::DIGIT);
  157. $isValid = false;
  158. }
  159. return $isValid;
  160. }
  161. }
  162. ]]>
  163. </programlisting>
  164. 注意在<code>isValid()</code>中的四个条件测试不立即返回<code>false</code>。这允许校验类提供<emphasis role="bold">所有的</emphasis>输入的密码不符合要求的原因。如果例如一个用户打算输入"<code>#$%</code>"字符串作为密码,<code>isValid()</code>将导致所有四个校验失败消息被后来的<code>getMessages()</code>调用返回。
  165. </para>
  166. </example>
  167. </sect1>
  168. <!--
  169. vim:se ts=4 sw=4 et:
  170. -->