关于Validate层

Validate层,自创的,我读书不多,不知道有什么专业名词能够对应的,有专业人士还请指教。(我又装B了一回……)

 

这两天一直在跟同事讨论分层的问题,大家的思路也基本一致,无外乎拆分出Resource、DAO和Logic。涉及到展现的部分,则丢给MVC中的V和C。

在没分层的项目中,M通常做了DAO的事情,C做了Logic的事情。如果你这样做了的话,在你的项目成长到一定规模的时候会非常让人崩溃——因为Logic无法复用。所以对M进一步分层,主要是为了能够将DAO和Logic有效的复用。我在做设计的时候,又划出一个“抽象/扩展层”,用于定义Logic当中的可扩展点,以便外人按照扩展点向Logic中加入不同的逻辑。这一层个人觉得对于逻辑复杂或者要满足多个系统需求的平台型项目来说挺重要的,不然处理不同系统的需求就免不了各种if……else逻辑。

这段时间在思考技术选型的事情,同时在同事的代码中看到很多用于处理输入参数的逻辑,无外乎是对于参数进行类型和数值范围的校验和转换。在调研框架的时候我注意到了Zend_Form,以对象的方式定义表单,对于复用来说确实非常的方便。其实Zend_Form提供了配置文件、参数定义以及类继承的方式,来帮助你定义你的表单。

对于表单中各个字段的处理,包括输入输出,一般包括:

  • trim:去空格
  • urlencode/urldecode:不解释
  • htmlspecialchars/htmlspecialchars_decode:一般处理输出
  • intval/floatval/strval:转类型
  • iconv:转编码
  • mysql_real_escape_string一类:防SQL注入

而对于各个字段的校验逻辑,一般包括:

  • required:是否必须
  • type:判断数据类型
  • max/min:大小
  • length:长短
  • pattern:满足某种复杂的范式/正则
  • enum:是否在枚举范围内

除了处理和校验外,还会涉及到以下问题:

  • 错误提示:校验失败时给前端的提示语
  • 记日志:偶尔,需要对传入错误参数的行为记录日志
  • 批量输入的定位:对于批量处理请求,返回值中的错误信息定位要明确。例如第几条数据的哪个字段有什么类型的错误。

因为最近太忙我没能抽出时间一一测试Zend_Form的功能,仅仅粗略浏览了一下Zend_Form的文档。Zend_Form中已经提供了比较全的功能来支持上面的需求(性能先另当别论),但是不知道是否支持更细粒度的对于字段的定义,然后在之上重组成为Form。因为在很多场合我们获取到的输入都要用来入库,所以一些字段的定义与表的定义通常是一致的。当我们确定了数据库设计的时候,其实就已经确定了这些字段的类型和范围,那么不论在哪个表单中引用到某个字段,都应当是一致的,因此在“字段”这个粒度上进行复用会比较合适。

我们还是将上述问题分解来看,整个逻辑应该包含这么几个部分:

  • 定义:用一种类似DDL的语言,定义出字段的类型。(有同学说DDL是数据库模式定义语言,我这里取其字面意思,就是:Data Definition Language
  • 校验:按照DDL,对输入进行校验的逻辑。
  • 获得校验结果:校验过后,获得所需要的校验结果,例如errno、errmsg等。
  • 处理:根据不同场合的需要,将输入数据处理成需要的格式。处理必须结合场景,例如要放在URL中就要进行urlencode,要入库则需要mysql_real_escape_string,要打印到HTML页面上则需要htmlspecialchars。

其中,“处理”部分因为要结合不同的场景使用,理应交由不同的场景来解决,例如mysql_real_escape_string交给DAO层来解决,htmlspecialchars交给View层来解决,我们应该尽量在中间过程中尽可能的保持变量原有的状态,我曾见过一些代码反复的进行encode/decode处理,最后把自己搞乱了的情形。这个就不深入讨论了,反正是交给各个层去做了就对了。

“定义”这个工作,需要有一种DDL,因为使用者只想说我这个变量的类型是啥啥啥,而不愿意写代码去if (is_int($x))什么的,并且你的DDL应该尽可能通用,通用意味着不仅仅是PHP要用,可能前端JS也要用,这样能够写一个js库遵照一份DDL去进行前端校验。而通用的DDL就不好找了,schema是基于XML的,处理起来慢,又太笨重,或许XForm到时候可以一统江湖,可是等不了了。除此之外有个json-schema,用来校验json的。公司里有个idl,自用的保密这里就不说了。反正我是没遇到特别好的DDL,也许哪位大牛可以指点一二。总之,DDL是第一位的,DDL不但要能够满足基本需求,还要容易处理,否则花费在解析DDL上的时间开销就大了,啥好东西一旦性能成问题就没人稀饭了。在没有DDL的时候,我们还有一个笨方法,就是跟Zend_Form一样提供个API,外层直接调用API来定义你的数据格式。

如果有了DDL,就容易做上层的工作了。对DDL解析,按照DDL的声明对数据进行校验,返回校验结果。那么这个地方就又扯出一个对errmsg的定义,我们用DDL定义了数据的格式,那么对于每个触犯格式约束的点都要返回相应的errno和errmsg。结合不同的场合,这个errmsg定义可能又不一样,比如在页面上我们可以提示用户“您的密码不得少于6个字符”,而在WebService中我们可能又只返回一个errno=100。和上面处理方法一样,各个场景所用到的不同的方式就交给各个场景去解决。“校验”的工作只需返回一个通用的校验结果,而对于不同场景我们有工具能够根据通用的校验结果产生不同的输出内容就行了。

那么综合来看,这个IOP层所需要的首先是一个基础库的支持,包括:

  • 一个通用DDL
  • 一个解析DDL并且用DDL对输入进行校验,然后返回一个通用校验结果的PHP库,或者JS库、Java库,any……
  • 若干可以读取通用校验结果,并按照规则产生输出内容的工具,可以不放在核心库中,自己实现呗

这是一个比较理想的情况,有了这些,我们就可以只写定义,然后调用工具来执行,就完全没有代码逻辑了。但是我们现在连DDL都没有,说啥都是扯蛋,所以一个可实施的方式就是用API解决DDL的问题(妈的,说了半天说回Zend_Form了)。不管怎么样,有了Validate这一层,可以将对输入的校验独立出来,这样在Action中,或者在WebService的最外层Service封装中,就可以更加的干净一些,不用写太多的if……else之类。

这同样也能解决现在我遇到的一个问题,经常有人来问我:"你们的用户名和密码的字段的规则是什么?",该死的老代码全是if……else,如果有了这一层就方便多了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值