20

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

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

然而,我不断地偶然发现越来越多的关于(缺乏)灵活性引起的问题Zend_Form_Decorator。像向单个输入元素添加额外按钮这样的简单任务变得非常困难。

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

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

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

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

是否有任何指导方针来做到这一点?你们中是否有人遇到过同样的情况,如果有,你们是如何解决这些问题的?

我非常想听听你的观点。

4

10 回答 10

21

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

无论如何,我建议您在表单中使用ViewScripts。请注意,这些与 View 不同——相反,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 验证机制。

于 2009-08-14T16:35:53.387 回答
9

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

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

工具只有在对您有所帮助时才是工具。否则,这只是一个障碍。

于 2009-08-14T14:02:58.663 回答
4

这是我从 Zend_Form 中学到的:

让它做这件事,从长远来看,它将为您节省大量代码行。

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

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

如果您决定走这条路,请提示:确保您使用的是CSS 样式重置脚本

于 2009-08-16T06:31:29.147 回答
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')), );
于 2009-09-06T08:04:39.673 回答
2

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

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

在模型中使用 ZFI 的控制器代码示例片段。错误处理和常见的验证方法在一个子类中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');
    }
}
于 2009-08-14T15:36:09.753 回答
2

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

22.5。Zend_Filter_Input

Zend_Filter_Input提供了一个声明性接口来关联多个过滤器和验证器,将它们应用于数据集合,并在过滤器和验证器处理输入值后检索输入值。默认情况下,值以转义格式返回,以实现安全的 HTML 输出。

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

于 2009-08-14T19:27:47.843 回答
2

我支持 lo_fye 提到的内容。以我的经验,Zend Forms 很笨重而且没有经过深思熟虑。

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

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

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

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

于 2010-02-08T05:44:28.090 回答
1

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

于 2009-08-15T14:44:03.100 回答
1

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

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

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

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

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

于 2012-02-01T03:08:03.930 回答
0

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

由于更改字符不足而无法编辑,由于代表不足而无法发表评论,但是...

$this-element->getAction()

应该

$this->element->getAction()

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

于 2012-07-17T12:49:55.910 回答