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

时间:2009-08-14 13:29:55

标签: php zend-framework zend-form decorator

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

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

然而,我一直在绊倒越来越多关于({3}}引起的(缺乏)灵活性的问题。简单的任务,如为单个输入元素添加额外的按钮,就会变得非常困难。

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

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

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

我正在考虑的一种可能的解决方案是在服务器端和视图中一起编写表单。这将允许我轻松验证我自己的表单,但(在我看来相当大)的缺点是每个表单应该定义两次,这只是感觉完全错误。

有没有指导方针可以做到这一点?你们有没有经历过相同的经历,如果有的话,你们是如何解决这些问题的?

我非常想听听你的观点。

10 个答案:

答案 0 :(得分:21)

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

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

答案 1 :(得分:9)

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

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

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

答案 2 :(得分:4)

这是我用Zend_Form学到的东西:

让它做到这一点,从长远来看,它将为您节省大量的代码。

权衡是你最终写了更多的CSS来让事情以你想要的方式展示。请记住,几乎任何HTML元素都可以设置为任何样式。默认情况下,Zend_Form为您提供了大量的CSS选择器,可以根据您的需要获得特定(或广泛)。我还没有看到一个案例,我无法完成我想要的默认装饰器。

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

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

答案 3 :(得分: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')), );

答案 4 :(得分:2)

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

我现在使用纯HTML表单并在模型中使用Zend_Filter_InputZend_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');
    }
}

答案 5 :(得分:2)

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

  

22.5。 Zend_Filter_Input

     

Zend_Filter_Input提供了一个   关联的声明性接口   适用多个过滤器和验证器   他们收集数据,以及   检索后的输入值   已被过滤器处理   验证。值将返回   默认情况下转义格式为安全   HTML输出。

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

答案 6 :(得分:2)

我认为lo_fye提到了什么。根据我的经验,Zend Forms很笨重而且没有经过深思熟虑。

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

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

在视图脚本中,我按照我喜欢的方式格式化表单,然后输入字段(例如)将只显示该元素:$ this-&gt; element-&gt; form_element_id。并注意我删除错误装饰,只是抓住错误堆栈并显示它我应该如何。

缺点是你会为每个表单创建一个视图脚本,或者自己构建某种可重用的系统,这样就可以进行额外的工作。但最终它更容易设计适合你的布局的表格,imo。

答案 7 :(得分:1)

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

答案 8 :(得分:1)

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

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

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

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

我知道很多人不会同意我的论点,但这只是因为Zend_Fom已经度过了不眠之夜的人的意见。

答案 9 :(得分:0)

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

无法编辑,因为更改字符不足,因为代码不足而无法评论...

$this-element->getAction()

应该是

$this->element->getAction()

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