Zend Framework 表单、装饰器和验证:我应该回到纯 HTML 吗?

Posted

技术标签:

【中文标题】Zend Framework 表单、装饰器和验证:我应该回到纯 HTML 吗?【英文标题】:Zend Framework forms, decorators and validation: should I go back to plain HTML? 【发布时间】:2010-11-19 15:43:58 【问题描述】:

我目前正在开发一个包含大量表单的相当大的应用程序。

到目前为止,我一直在手动编写表单并编写自己的验证逻辑,但我决定是时候开始使用 Zend_Form 了,它是内置的验证例程。

但是,我不断发现越来越多的问题与Zend_Form_Decorator 导致的(缺乏)灵活性有关。向单个输入元素添加额外按钮等简单任务变得异常困难。

我现在已经到了一个地步,我正在认真考虑完全放弃 Zend_Form_Element + Zend_Form_Decorator 方法,但我不想失去出色的验证选项。

基本上,我想要两全其美:

以最终用户看到的方式编写表单:html 轻松将服务器端验证添加到表单字段,而不会破坏太多 ZF 标准行为

我正在考虑的一个可能的解决方案是在服务器端编写表单,就像在视图中一样。这可以让我轻松验证自己的表单,但(在我看来相当大的)缺点是每个表单都应该定义两次,这感觉很明显是错误的。

是否有任何指导方针可以做到这一点?你们中的任何人都有过同样的经历吗?如果有,你们是如何解决这些问题的?

我非常想听听您的观点。

【问题讨论】:

【参考方案1】:

我也发现默认装饰器是一个巨大的痛苦。我理解为什么它们是这样的,但我认为“不便因素”被严重低估了。

无论如何,我建议您在表单中使用ViewScripts。请注意,这些与视图不同——相反,ViewScript 在您的 Form 类中被显式引用,充当各种“子视图”并允许您控制每个元素的布局。过去很难找到如何使用 ViewScripts 的示例,但我会尝试提供一些有用的东西。

首先,覆盖表单类中的 loadDefaultDecorators:

public function loadDefaultDecorators() 
     $this->setDecorators(
         array(
             array('ViewScript', 
                 array('viewScript' => 'foo/bar.phtml')
             )
          )
      );        
 

这将引用位于 /views/scripts/foo 中名为 bar.phtml 的 ViewScript。请注意上面“ViewScript”和“viewScript”中区分大小写的区别。

接下来,您必须调整应用于每个元素的装饰器,以确保它可以显示,但没有烦人的 dt/dd 包装器。例如:

$baz = new Zend_Form_Element_Text('bazInput');
$baz->setDecorators(array('ViewHelper','Errors')); 

最后,您需要构建您的 ViewScript,例如:

<form method="post" action="<?php echo $this-element->getAction() ?>">
    <table>
        <tr>
            <td><label for="bazInput">Baz:</label></td>
            <td><?php echo $this->element->bazInput ?></td>
        </tr>
    </table>
    <input type="submit" value="Submit Form" />
</form>

显然这是一个非常简单的示例,但它说明了如何引用表单元素和表单操作。

然后在您的视图中,像往常一样简单地引用和输出您的表单。通过这种方式,您可以更好地控制表单布局——包括轻松添加 javascript

我相信这种方法可以解决您的两个要求:您可以用纯 HTML 构建表单,并且仍然可以利用 Zend Form 验证机制。

【讨论】:

感谢您的回答;虽然我已经了解 viewScripts,但这似乎是满足我所有需求的最佳解决方案。【参考方案2】:

在过去的 10 个月里,我在一个大型项目中使用了尽可能多的 Zend 组件,而 Zend_Form 一直是 *** 中最大的痛苦。这些表格渲染速度很慢,而且很难制作漂亮。甚至不要让我开始使用子表单。我看到了一篇名为“scaling zend_form”的有趣文章,但它似乎对渲染速度没有太大帮助:(

我正在考虑在视图中使用直接 HTML 来制作我的所有表单,并且只使用 Zend_Form 来进行验证和过滤(而不是渲染)。要么,要么我只使用 Zend_Validate 和 Zend_Filter,根本不使用 Form 方面。

只有对你有帮助的工具才是工具。否则,这只是一个障碍。

【讨论】:

这正是我的经验。感谢您确认这可能不仅仅是我的愚蠢让这工作变得痛苦:) ~距离那个答案已经过去了 3 年,你还有这个想法吗?因为如果是这样,我和你有同样的想法。 是的,我仍然有这种感觉。我听说 ZF 2.0(即将推出)将重构 Forms,所以我期待着尝试。同时,我按原样使用 Zend_Form 并尝试仅使用 css 对其进行样式设置,或者我仅将 Zend_Form 用于验证,但我实际上是手动构建 html。 同意,我完全讨厌 Zend Framework。它很臃肿,并试图做所有事情。就我而言,它是 PHP 框架的 Drupal。由一家公司而不是由一群热情的个人组成。 Kohana,目前是我的最爱。【参考方案3】:

这是我从 Zend_Form 中学到的:

让它做它的事情,从长远来看,它会为你节省大量的代码行。

权衡是您最终要编写更多的 CSS 来让内容以您想要的方式显示。请记住,几乎任何 HTML 元素都可以被设置为看起来像任何东西。默认情况下,Zend_Form 为您提供了大量的 CSS 选择器,让您可以根据需要获得尽可能具体(或广泛)的选择。我还没有看到我无法将默认装饰器完全按照我想要的方式工作的情况。

当然,我有一个又大又丑的 CSS 文件,但根据我的经验,它最终可能还是一个又大又丑的 CSS 文件。我不担心应用程序特定的表单编码/验证/过滤/处理/等,而是处理 CSS 文件中一些特定样式的元素。

如果您决定走这条路,请提示:确保您使用的是CSS style reset script

【讨论】:

【参考方案4】:

以下是我在使用 Zend Form 的项目中使用的一些装饰器。这些,我相信,很容易理解。

$stdRowDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'width' => '200')), array('Label', array('escape' => false, 'class' => 'zfFormLabel', 'tag' => 'td')), array(array('row'=>'HtmlTag'), array('tag'=>'tr')));
$startRowDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td')), array('Label', array('escape' => false, 'tag' => 'td', 'class' => 'zfFormLabel')), array(array('row'=>'HtmlTag'), array('tag'=>'tr', 'openOnly'=>true)));
$startRowOpenOnlyDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'openOnly'=>true)), array('Label', array('escape' => false, 'class' => 'zfFormLabel', 'tag' => 'td')), array(array('row'=>'HtmlTag'), array('tag'=>'tr', 'openOnly'=>true)));
$midRowDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td')),array('Label', array('escape' => false, 'class' => 'zfFormLabel', 'tag' => 'td')));
$midRowCloseOnlyDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'closeOnly'=>'true')),array('Label', array('escape' => false, 'class' => 'zfFormLabel', 'tag' => 'td')));
$midRowCloseOnlyNoLabelDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'closeOnly'=>'true')));
$endRowDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td')), array('Label', array('escape' => false, 'class' => 'zfFormLabel', 'tag' => 'td')), array(array('row'=>'HtmlTag'), array('tag'=>'tr', 'closeOnly'=>'true')));
$endRowCloseOnlyNoLabelDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'closeOnly'=>'true')), array(array('row'=>'HtmlTag'), array('tag'=>'tr', 'closeOnly' => 'true')));
$buttonEndRowDec = array('ViewHelper', 'Description', 'Errors', array(array('data'=>'HtmlTag'), array('tag' => 'td', 'colspan'=>'2', 'align'=>'center')), array(array('row'=>'HtmlTag'), array('tag'=>'tr', 'closeOnly'=>'true')));
$buttonDecorators = array('ViewHelper', array(array('data' => 'HtmlTag'), array('tag' => 'td', 'class' => 'element')), array(array('label' => 'HtmlTag'), array('tag' => 'td', 'placement' => 'prepend')), array(array('row' => 'HtmlTag'), array('tag' => 'tr')), );

【讨论】:

【参考方案5】:

如果您想要没有表单的验证器和过滤器:Zend_Filter_Input

22.5。 Zend_Filter_Input

Zend_Filter_Input 提供了一个 关联的声明性接口 多个过滤器和验证器,应用 他们收集数据,并 在输入值之后检索它们 由过滤器处理和 验证器。值返回 为了安全起见,默认转义格式 HTML 输出。

虽然 - 我个人的建议是学习制作自定义装饰器和视图助手。 Zend_Form 非常强大,我在尝试定位/装饰东西时从来没有遇到过问题。即使在使用 jQuery 构建复杂的权限表并自动生成列和行时,我也发现 Zend_Form 接口可以节省时间。如果您有关于如何处理装饰的具体问题,我很乐意提供帮助。打开一个新问题并在此处发表评论或其他内容....

【讨论】:

【参考方案6】:

我已经使用 Zend Framework 大约一年了,我只在我的一个项目(第一个项目)中使用了Zend_Form。在我花了 15 分钟试图定位我的“或取消”链接后,我放弃了Zend_Form。 不过,我确实喜欢这种集成。

我现在使用纯 HTML 表单并在模型中使用 Zend_Filter_Input(大多数情况下是 Zend_Db_Table,但我必须在上一个项目中添加一个服务层)。

在模型中使用 ZFI 的控制器代码示例 sn-p。错误处理和常用验证方法在 Zend_Db_Table 的子类中,我的类扩展了它。

视图助手格式化错误消息数组。

if ($this->_request->isPost()) 
    $data = $this->_request->getPost();
    $event = new Default_Model_DbTable_Event();         
    $event->createRow($data)->save();

    if ($event->hasErrors()) 
        $this->view->errors = $event->getErrorMessages();
        $this->view->event = $data;
     else 
        $this->_redirect('events');
    

【讨论】:

感谢您的回答。您能否详细说明您如何验证表单并向客户显示错误消息? 我在模型中创建了一个 ZFI 实例,并且如果验证失败,还有一个属性来保存错误。我将在下面发布控制器代码的 sn-p。 我已经合并了我的两个帖子,所以我的代码 sn-p 在上面。将删除重复的条目。【参考方案7】:

我赞同 lo_fye 提到的内容。根据我的经验,Zend Forms 很笨重,而且没有经过深思熟虑。

我发现最简单和最灵活的解决方案是创建两个表单文件,1. 初始化表单元素的表单类,然后是显示表单元素的视图脚本。在我的表单类中,我关闭了所有装饰器,减去了实际的表单元素。例如。: ->removeDecorator('HtmlTag') ->removeDecorator('DtDdWrapper') ->removeDecorator('标签') ->removeDecorator('Errors');

然后在初始化表单元素的构造函数的最后,传递视图脚本: $this->setDecorators(array(array('ViewScript', array('viewScript' => 'path/to/script_form.phtml '))));

在视图脚本中,我完全按照自己喜欢的方式格式化表单,然后输入字段(例如)将在哪里显示该元素:$this->element->form_element_id。请注意,我删除了错误装饰,只是抓取了错误堆栈并按我认为应该的方式显示它。

缺点是您将为每个表单创建一个视图脚本或自己构建某种可重用的系统,因此需要额外的工作。但最终设计表单以适应您的布局要容易得多,imo。

【讨论】:

【参考方案8】:

您可以使用 Zend Form 并自己生成 HTML :) 您只需要跟踪更改并在 HTML 和 ZF 中使用相同的表单元素 :)

【讨论】:

在两个地方跟踪这些变化是 Zend Forms 试图根除的!值得学习曲线(希望我仍在努力) 完全同意!我只是在回答问题! :)【参考方案9】:

简短回答:仅将 Zend_Form 用于验证和过滤,并使用普通的旧视图脚本以您想要的方式呈现表单。

长答案:我得出的结论是,使用 Zend_Form 生成表单的 HTML 是不值得的。至少在我工作的公司里。但是为什么呢?

这很简单,我不想创建一个类(或使用 hack)只是为了“平静地”在我的表单内的 div 中添加一个链接。我不想创建多个装饰器只是为了添加可以使用简单 HTML 轻松添加的功能,最重要的是,与我们合作的设计师不想编辑一个(或两个或更多)类 [es] 只是为了做好他们的工作。

我们继续使用 Zend_Form,但只是为了验证和过滤我们的表单。而不是生成它们。

我知道很多人不会同意我的论点,但这只是一些因 Zend_Fom 而失眠的人的意见。

【讨论】:

JCM,我认为在这种情况下,有人可以使用 Zend_Filter_Input 定义验证/过滤器。我认为只有当表单元素只能来自 html 时,才使用 zend_form 进行验证。【参考方案10】:

编辑/评论@Cal Jacobson 的最佳答案。

由于更改字符不足无法编辑,由于rep不足无法评论但是...

$this-element->getAction()

应该是

$this->element->getAction()

我确定 OP 知道这一点,但在尝试直接使用答案中的代码时,更正会避免错误。

【讨论】:

以上是关于Zend Framework 表单、装饰器和验证:我应该回到纯 HTML 吗?的主要内容,如果未能解决你的问题,请参考以下文章

文件上传表单的 Zend 验证器大小 - Zend Framework 2.3

文件上传表单的 Zend 验证器大小 - Zend Framework 2.3

你能在 Zend 子表单中添加错误装饰器吗?

PHP 自定义Zend_Form:更改了装饰器和添加的方法

Zend Framework 2 CSRF 验证

Zend 表单装饰问题