Zend表单:如何让它顺从于我的意愿?

42

我已经多次阅读了手册,搜索了谷歌关于这个主题的帖子,甚至买了几本涉及ZF的书。但是,为什么我仍然感到困惑呢?

使用Zend_Form,我可以创建一个验证和功能良好的表单。但是,我无法创建一个外观完全符合我要求并具有我想要的错误消息的表单。我想要自定义按钮、时髦的布局、在表单中插入文本等。

有人有简单的方法来实现这些吗?有什么东西可以让我感觉框架节省了我的时间而不是浪费了我的时间吗?我可以放弃Zend Form...制作自己的表单,使其动作命中一个页面以验证和处理提交的数据,并且我可以像打字一样快速完成,但是我真的想“get”它并能够按照明显的意图使用它。

任何建议?有关自定义按钮、时髦的布局以及基本(或更高级的,因为有很多基本教程跳过了更难的问题)使用zend form的“如何做”简单指南吗?


那个蛋怎么了?c_O - Nick Rolando
2
@Shredder - 请阅读Zend Framework指南,了解如何使用Zend表单。 - rg88
14个回答

26

巴雷特·康拉德的建议是我会建议的。此外,请记住,您不需要使用表单对象来呈现表单。

您可以在视图脚本中创建一个具有与表单类相同名称的元素的表单。

您的HTML表单:

<form action="/login/" method="post">
<fieldset>
    <label for="username">Username:</label>
    <input type="text" size="10" name="username" />
    <label for="password">Password:</label>
    <input type="password" size="10" name="password" />
    <input type="submit" />
</fieldset>
</form>

你的类:

class LoginForm extends Zend_Form
{
    public function init()
    {
        $username = $this->createElement('text','username');
        $username->setRequired(true);
        $this->addElement($username);

        $password = $this->createElement('password','password');
        $password->setRequired(true);
        $this->addElement($password);        
    }
}

你的表单类反映了你的HTML表单,类中的每个元素都有自己的验证器和要求。在你的操作中,你可以创建一个你的表单类的实例,并根据该表单验证你的post/get变量:

$form = new LoginForm();
if ($this->_request->isPost()) {
    if ($form->isValid($this->_request->getParams())) {
        // do whatever you need to do
    } else {
        $this->view->errors = $form->getMessages();
    }
}

您可以使用此方法将错误消息作为一组显示在表单顶部。

这是一个基本示例,但它允许您完全控制表单的呈现方式,而无需花费时间学习如何使用装饰器。在我看来,Zend_Form 的很多优势在于其验证和过滤属性。这使您具备了这种优势。这种解决方案的主要缺点是,视图脚本 HTML 表单可能会与表单类不同步。


你能否更新你的示例并添加以下代码:1)当用户名未填写时,将类“error”添加到输入元素,并在上方显示一些错误消息 2)对于用户名进行特殊验证,例如唯一性检查加符号检查 - se_pavel
6
这并不是一个理想的解决方案。您会失去视图助手的所有功能,例如显示错误消息、在显示错误消息时维护字段值等。最好的做法是从表单对象中在视图中逐个呈现每个表单元素。 - mjh_ca

11

在您的视图中单独渲染每个元素 - 例如:

<!-- view script here -->
<form method="POST">
Name: <?php echo $this->myForm->getElement('name')->render(); ?>
some other text between the fields
Birthdate: <?php echo $this->myForm->getElement('birthdate')->render(); ?>
<input type="submit" />
</form>

这样做可以保持使用Zend_Form视图助手的能力(例如在验证失败时显示错误消息和维护表单字段的值),但同时还可以完全自定义。如果您想更进一步,可以关闭单个表单元素的默认修饰符,然后附加自己的修饰符来进一步自定义要使用的标记(例如用于错误消息和标签),或者根本不使用修饰符(除了呈现表单元素本身),然后手动编写所有周围的HTML。 在表单级别和视图级别都能够实现完全的自定义能力,而不失去Zend_Form的优点。


9

5
目前我们有了新的、闪亮的Zend\Form,它比旧组件更加复杂,但也更加可控、封装和强大。因此,我下面说的话不适用于新组件。新组件在我看来是一个巨大的改进,因为它...
  • ...让您完全掌控如何渲染表单,您需要编写更多的视图代码,但这是值得的。
  • ...将数据、逻辑和视图尽可能地分离。
  • ...利用了HTML5表单元素。
  • ...为您提供了许多选项,例如hydration、注释等,让您可以自由组合您的表单。

关于Zend_Form的旧回答

我可能真的帮不上忙,因为我也有同样的问题。我认为Zend_Form装饰器很强大,但迄今为止是ZF中最不友好和不直观的部分,我在各种项目中使用了ZF的主要部分。

话虽如此,根据我的经验,我只能给出一些提示:

  • 过滤器易于在没有使用表单的情况下使用
  • 你想实现的大多数甚至全部都是通过装饰器完成的
  • 我从小表单开始,逐步添加东西,但我不明白我在一些表单中做的一些事情,因为结果是基于试错的(主要是与装饰器有关)
  • 我从zend邮件列表中获得了信息,在任何地方都找不到

从右侧的相关问题中可以看出,Zend_Form缺乏全面的文档,特别是考虑到它的非直观性。我真的希望看到ZF的人们对此采取行动,就像我喜欢Zend Framework一样。

所以这个答案可能只是让你知道你不是唯一一个遇到这个问题的人。


或者您也可以使用绝地心理战,当然!


4
补充一下之前说的话:
不要害怕装饰器,如果你决定使用Zend_Form,你会经常使用它们。一旦你理解了,它就相当简单,不幸的是文档很薄弱,几乎只有通过实践才能掌握。
ViewScript和ViewHelper装饰器给你很多的力量。
不要害怕查看源代码中存在的不同装饰器,并查看它们如何做事情(比较原始装饰器与dojo装饰器,我获得了相当多的见解)。
我认为Sean所建议的是你不需要调用form->render,你可以在你的视图脚本中使用像这样的东西。
 <someHtmlThingy name="blah" value="<?php echo $this->formInstance->getElement('whatever')->getValue(); ?>" />

我曾经参与过一个项目(在 Zend_Form 出现之前),我们构建了一组验证器,并一直使用标准的视图脚本。相比于使用 Zend_Form 创建元素,这需要做更多的工作(例如处理错误信息等),但并不过分。


3
如果您想在不使用ViewScript装饰器的情况下在表单元素之前或之后添加任意标记,可以使用我的AnyMarkup装饰器:http://www.zfsnippets.com/snippets/view/id/62 例如,以下是如何在包装标记内使用图像在输入字段之前添加标记(需要正确设置自动加载的包含路径): $form->addElement('text', 'my_field', array( 'label' => 'Enter Info:', 'decorators' => array( 'ViewHelper', array('AnyMarkup', array( 'markup' => ''. 'info icon'), 'placement' => 'prepend' ), 'HtmlTag', 'Label' ) );

2

跳过表单整体装饰器(例如,打印表单的各个元素而不仅仅依赖于表单的标准视图助手来处理一切)是获得更多控制权的一种方式。

另一种选择是手动编写表单,只使用ZF来处理验证和过滤。


如果输入无效,您如何将验证消息传递回页面? - Evan
1
Zend_Form有一些访问器函数:$form->isValid(),$form->getErrors(),$form->getValue()等类似函数。 - Sean McSomething
你也可以使用flashMessenger来处理错误信息。我过去曾经使用过它。 - rg88

2

为什么不能超过25c,我之前提到过,但ViewScripts可以让您对表单的呈现进行极细粒度的控制。Zend_Form旨在快速执行,因此它假设许多默认值,如标准修饰符,并按照它们添加到表单对象中的方式排列元素。使用ViewScript,您可以跳过其中大部分内容,并将所有元素放置在正常HTML中的任何位置。

但不要完全跳过装饰器的概念。即使以后在ViewScript中使用它们,它们也会为单个元素设置样式。例如,您可以将其用于错误消息,就像其他人建议的那样。

如果您有非常复杂的表单,其中包含具有相似操作的多个数据点(考虑具有活动/非活动按钮和每个按钮的删除按钮的用户列表),则应考虑Zend_Form_SubForm。子表单可以像普通表单一样利用ViewScripts,如果您将一个带有ViewScript的表单级联到具有自己的ViewScript的子表单,则最终得到的逻辑和呈现将更加强大,比直接表单更好。


2
不幸的是,更复杂的问题被跳过了,因为如果没有真正具体的目的或目标,编写示例或操作指南就非常困难。我花了一些时间在这里帮助另一个开发人员,他想要修改隐藏元素的显示方式,但他的情况非常特殊,所以更容易深入具体细节。
大多数更复杂的任务实际上归结为针对特定字段类型扩展默认助手。例如,我有一个项目,我想在表单提交后将类“error”应用于所有未通过验证的字段,而不是编写验证错误文本:
<label for="field">Label:</label>
<input type="text" name="field" id="field" class="error">

这是一个相当复杂的过程,因为实际的表单元素默认情况下不可用于视图助手,所以助手无法检查元素是否具有验证错误。因此,我进行了以下过程:
我必须为每个字段类型创建一个客户视图辅助程序,以便将“error”类应用于它们。在其中,我重写了formXXX()方法,并添加了一个检查以查看元素是否有错误。此外,我添加了一个setElement()方法,装饰器可以调用该方法来设置元素的实例,以便我的辅助程序可以检查错误。
接下来,我必须覆盖默认的Zend_Form_Decorator_ViewHelper。在其中,我访问视图并实例化表单元素类型的辅助程序,并检查我在视图辅助程序中创建的setElement()方法是否存在,如果存在则进行设置。通过这样做,我可以扩展一些表单元素类型而不破坏整个脚本。
在每个表单的init()函数中,我必须添加一个新的元素前缀路径(addElementPrefixPath('My_Form_Decorator'), 'path/to/decorator'),它指向我的新表单装饰器。
最后,我必须将帮助程序路径添加到我的应用程序中,以便Zend Framework可以找到我在第一个项目中创建的帮助程序:addHelperPath('/path/to/helpers', 'My_View_Helper'); 你可以看到为什么编写复杂的教程确实需要真实世界的问题。设置这些类型的辅助程序或复杂的装饰器方案的好处是,虽然一开始可能很烦人,但如果需要进行更改,它允许您非常轻松地创建许多遵循相同设计方案的表单,并快速统一修改其输出。但另一方面,如果你觉得你花了很多时间来解决一个应该是简单任务的问题,那我会建议你跳过它!
然而,如果你需要更具体的帮助,我将非常乐意提供帮助。只需提出另一个问题(或更新此问题),我会尽力帮助你。

我正在查看您针对元素错误类问题的解决方案答案,但后来意识到也可以使用非常简单的装饰器来完成。我创建了一个装饰器,应该在“ViewHelper”装饰器之前添加。它调用getElement(),检查其上的hasErrors(),然后,如果必要,使用setAttrib('class','error')向其中添加一个类。(当然还要检查之前存在的类。) - Decent Dabbler

1

你可能已经解决了这个问题,但我一直在做一些工作,需要一个类似的解决方案。

form->getSubform('subform'); 
foreach ($subform as $key => $value) {
//在此处添加一些标记和自定义代码
    print $value;
//在此处添加一些标记和自定义代码
} ?>

在foreach循环中,您可以添加表格标记。如果您为表格行命名了键,它们应该与表单键匹配。您甚至可以使用按键获取适当子表单的循环,或者甚至是按键获取元素。如果您知道键,则可以跳过foreach循环,并简单地说print $subform ['somekey']; 假设您通过说$ form-&gt; setIsArray(true); 设置了主表格(不确定最后一部分是否严格必要,但对于复杂的表格,应该像那样设置。

我删除了默认装饰器,以便完全控制每个元素内的打印。Zend_Form应该有一个内置方法更轻松地获取单个元素..但我认为这个方法非常有效。

希望对某人有所帮助!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接