42

我已经阅读了很多次手册,我搜索了谷歌提供的关于这个主题的帖子,我什至买了几本关于 ZF 的书。现在,为什么我仍然感到困惑?

我可以使用 Zend_Form 制作一个验证和运行良好的表单。我不能做的就是使表单看起来与我希望它看起来与我希望它具有的错误消息完全一样。我想要自定义按钮,我想要时髦的布局,我想要在表单中间插入文本,等等。

有没有人有一种简单的方法来实现这些事情?让我觉得框架节省了我时间而不是成本的东西?我可以放弃 Zend Form... 制作我自己的表单,让它的动作点击一个页面来验证和处理发布的数据,我可以尽可能快地完成它,但我真的想“得到”这个并且能够按照明显的意图使用它。

有什么建议吗?对于自定义按钮、时髦布局和基本(或者相当高级,因为有大量基本教程跳过了更难的问题)“完成工作”有任何简单的“如何”使用 zend 表单?

4

14 回答 14

26

Barrett Conrad 的建议正是我所建议的。另外,请记住,您不需要使用表单对象来呈现您的表单。

您可以做的一件事是在您的视图脚本中创建一个表单,该表单具有与表单类同名的元素。

您的 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 vars:

$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 表单可能与您的表单类不同步。

于 2009-03-08T00:07:08.690 回答
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 的好处,无论是在表单级别还是在视图级别。

于 2011-03-20T20:12:59.130 回答
9

Matthew Weier O'Phinney 已经开始了一系列关于 Zend_Form 装饰器的博客文章:

  1. 最简单的 Zend_Form 装饰器
  2. 从内到外:如何分层装饰器
  3. 单独渲染 Zend_Form 装饰器
  4. 创建复合元素
于 2009-05-08T15:35:56.987 回答
5

目前我们已经有了新的和闪亮的Zend\Form,它比旧的组件更复杂,但也更可控、封装和强大。所以,我下面说的不适用。恕我直言,新组件是一个巨大的改进,因为它...

  • ...让您完全控制要如何呈现表单,您需要编写更多视图代码,但这是值得的
  • ...最大限度地分离数据、逻辑和视图
  • ...利用 HTML5 表单元素
  • ...为您提供了许多选择如何将表单组合在一起,例如水合作用、注释等。

关于 Zend_Form 的旧答案

我真的帮不上忙,可能是因为我有完全相同的问题。我认为 Zend_Form 装饰器很强大,但到目前为止我见过的 ZF 中对程序员最不友好和不直观的部分,我在各种项目中使用了 ZF 的主要部分。

也就是说,我只能从我的经验中给出一些提示:

  • 过滤器易于使用,无需使用表单
  • 您想要实现的大多数(如果不是全部)事情都是在装饰器的帮助下完成的
  • 我从小表格开始,一点一点地添加东西,但我没有在我的一些表格中得到我正在做的一些东西,因为结果是基于反复试验(主要是装饰器)
  • 我从 zend 邮件列表中获得了我在网上任何地方都找不到的信息

从右侧的相关问题到此,很明显 Zend_Form 缺乏全面的文档,特别是考虑到它的非直观性质。我真的很想看到 ZF 的人为此做点什么,就像我喜欢 Zend Framework 一样。

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


或者你当然可以使用绝地思维技巧

于 2009-02-11T00:19:39.800 回答
4

添加到所说的内容:

不要害怕装饰器,如果你决定坚持使用 Zend_Form,你会大量使用它们。一旦你“得到它”,它就相当简单了,不幸的是,文档很弱,玩它几乎是到达那里的唯一方法。

ViewScript 和 ViewHelper 装饰器为您提供了强大的功能。

不要害怕挖掘存在的不同装饰器的源代码,看看它们是如何做事的(通过比较原始装饰器和 dojo 装饰器,我获得了相当多的见解)。

我认为 Sean 的建议是你不需要调用 form->render,你可以在你的 viewscript 中使用类似的东西。

 <someHtmlThingy name="blah" value="<?php echo $this->formInstance->getElement('whatever')->getValue(); ?>" />

我参与了一个项目(Zend_Form 之前),我们构建了一组验证器并一直使用标准的视图脚本。与使用 Zend_Form 创建元素相比,这需要更多的工作(检查错误消息等),但并不过分。

于 2009-02-11T00:44:58.507 回答
3

如果您只想在表单元素之前或之后添加任意标记而不使用 ViewScript 装饰器,则可以使用我的 AnyMarkup 装饰器:http://www.zfsnippets.com/snippets/view/id/62

例如,以下是您如何在包装器标签内添加带有图像的输入字段(需要包括正确设置自动加载的路径):

$form->addElement('text', 'my_field', array(
  '标签' => '输入信息:',
  '装饰器' => 数组(
    '查看助手',
    数组('AnyMarkup',数组(
      '标记' => '<span class="imgwrapper">'。
        '<img src="info.png" alt="info icon"/></span>'),
      '放置' => '前置'
    ),
    'HTML标签',
    '标签'
  )
);
于 2009-06-28T20:22:01.617 回答
2

跳过表单范围的装饰器(IE - 打印表单的单个元素,而不是仅仅依靠表单的标准 View Helper 来处理所有内容)是获得一堆控制权的一种方法。

另一种选择是简单地手动编码您的表单并仅使用 ZF 处理验证和过滤。

于 2009-02-11T00:30:29.383 回答
2

不幸的是,更复杂的问题被跳过了,因为如果没有真正的特定目的或目标,很难编写示例或操作方法。我花了一些时间在 SO 上帮助另一个想要修改隐藏元素显示方式的开发人员,但他的案例非常具体,因此更容易深入了解细节。

大多数更复杂的任务实际上归结为扩展特定字段类型的默认帮助程序。例如,我有一个项目,我想在提交表单后将“错误”类应用于所有未通过验证的字段,而不是写出验证错误文本:

<label for="field">Label:</label>
<input type="text" name="field" id="field" class="error">

这是一个相当复杂的过程,因为默认情况下视图助手无法使用实际的表单元素,因此助手无法检查元素是否存在验证错误。所以我进行了以下过程:

  1. 我必须为要应用“错误”类的每个字段类型创建一个客户视图助手。在其中,我覆盖了该formXXX()方法,并添加了一个检查以查看元素是否有错误。此外,我添加了一个setElement()方法,装饰器可以调用该方法来设置元素的实例,以便我的助手可以检查错误。
  2. 接下来我必须覆盖默认的Zend_Form_Decorator_ViewHelper. 在其中,我访问了视图并实例化了表单元素类型的帮助器,并检查了setElement()我在视图帮助器中创建的方法是否存在,如果存在则设置它。通过这样做,我可以在不破坏整个脚本的情况下扩展一些表单元素类型而不是其他类型。
  3. 在每个表单的 init() 函数中,我必须添加一个新的元素前缀路径 ( addElementPrefixPath('My_Form_Decorator'), 'path/to/decorator')),它指向我的新表单装饰器。
  4. 最后,我必须将帮助程序路径添加到我的应用程序,以便 Zend Framework 可以找到我在第一个要点中创建的帮助程序:addHelperPath('/path/to/helpers', 'My_View_Helper');

你可以看到为什么编写复杂的教程真的需要现实世界的问题。设置这些帮助器或复杂的装饰器方案的重要之处在于,尽管前面很烦人,但它允许您非常轻松地创建许多遵循相同设计方案的表单,并在更改时非常快速地统一修改它们的输出需要制作。但是另一方面,如果您觉得自己花费大量时间来弄清楚如何做应该是一项简单的任务以使一个表格受益,我会说跳过它!

但是,如果您需要更具体的帮助,我将非常乐意提供帮助。只需提出另一个问题(或更新这个问题),我会尽力提供帮助。

于 2009-02-11T05:19:58.597 回答
2

为什么cantitbemorethan25c 上面提到了它们,但是ViewScripts为您提供了对呈现表单的极细粒度的控制。Zend_Form 旨在快速,因此它假定许多默认值,如标准装饰器,并按照添加到表单对象的方式对元素进行排序。使用 ViewScript,您可以跳过其中的大部分内容并将所有元素放置在普通 HTML 中。

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

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

于 2009-02-11T14:47:28.780 回答
1

我为 Zend_Form 和装饰器编写了一些子类,以使其在 <table> 中布局表单。它甚至有一些特殊的技巧来做一些事情,比如让多个提交按钮显示在同一行。

花了一整天的时间来让它工作。它是针对 Zend 1.5.1 编写的,所以不知道它是否适用于当前版本,但如果您有兴趣,我可能会在某处上传源代码。

这似乎是 Zend Forms 的一个非常常见的抱怨。

(我知道 CSS 纯粹主义者会因为使用表格来布局表单而大吃一惊,虽然我同意 CSS 对大多数事情来说更好,但我还没有看到使用看起来不好看的 CSS 的良好表单布局就像一个丑陋的杂物。有了表格,表格几乎可以在我需要的每个浏览器上“正常工作”。)

编辑:好的,说到丑陋的杂物,我已经将用于生成表格 zend 表单的代码放在 github 中。去这里看看吧。(因为 gaoshan88 要了。)

于 2009-02-11T00:53:13.930 回答
1

在这里回答。希望它会帮助你。我浏览了异常数量的信息,直到找到它。

<table>
    <tr>
        <td>Page name: *</td>
        <td><?php echo $this->pageForm->header_title;?></td>
    </tr>

    <tr>
        <td>H1 tag: *</td>
        <td><?php echo $this->pageForm->h1_tag;?></td>
    </tr>

    <tr>
        <td>Page URL: *</td>
        <td><?php echo $this->pageForm->url;?></td>
    </tr>

    <tr>
        <td>Meta Description: </td>
        <td><?php echo $this->pageForm->meta_description;?></td>
    </tr>

    <tr>
        <td>Meta Keywords: </td>
        <td><?php echo $this->pageForm->meta_keywords;?></td>
    </tr>

    <tr>
        <td>Short Description: *</td>
        <td><?php echo $this->pageForm->short_description;?></td>
    </tr>

    <tr>
        <td colspan="2"><a href="<?php echo $this->websiteUrl;?>backend_template/list?placeValuesBeforeTB_=savedValues&TB_iframe=true&height=200&width=300&modal=true"
                           title="add a caption to title attribute / or leave blank" class="thickbox">Open iFrame Modal</a></td>
         <td>
            <a href="<?php echo $this->websiteUrl;?>backend_template/list?placeValuesBeforeTB_=savedValues&TB_iframe=true&height=200&width=300&modal=true" onclick="javascript:getDataFromAddPage()" title="Select Template For Page" class="thickbox" > TEST FORM  </a>
         </td>
    </tr>

    <tr>
        <td>Featured: </td>
        <td><?php echo $this->pageForm->featured;?></td>
    </tr>

    <tr>
        <td>Mark as 404: </td>
        <td><?php echo $this->pageForm->is_404page;?></td>
    </tr>

    <tr>
        <td>Show in Navigation Menu: </td>
        <td><?php echo $this->pageForm->in_navmain;?></td>
    </tr>

    <tr>
        <td>Show in Static Menu:</td>
        <td><?php echo $this->pageForm->in_navstatic;?></td>
    </tr>

    <tr>
        <td><?php echo $this->pageForm->submit;?></td>
        <td><?php echo $this->pageForm->button_close;?></td>
    </tr>

</table>
于 2009-07-21T16:44:34.110 回答
1

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

form->getSubform('subform');
foreach ($subform as $key => $value) {
//这里有一些标记和自定义代码
    打印$值;
//这里有一些标记和自定义代码

}
?>

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

我删除了默认装饰器,因此我可以完全控制每个元素内的打印。Zend_Form 应该有一个更容易抓取单个元素的内置方法。但我认为这很有效。

希望这对某人有帮助!

于 2009-11-17T23:42:49.377 回答
0

Sean McSomething 的第一个建议是适合我的方法。我一直认为<?php echo $this->form ?>渲染表单太神奇了。不过,我会更进一步,通过$element->renderDecorator()魔术方法渲染单个装饰器而不是单个元素。这样,您就不必担心定义装饰器的顺序。你只需要它们在那里,你就不必添加那些讨厌的、不直观的HtmlTag装饰器。我为此发表了一篇博文

于 2009-02-23T10:58:25.487 回答
-1

我不确定 Zend 是否已经具有该功能,但是一个快速的解决方案是扩展类,使其接受 html 模板。

例如:

<?php
$form = new zend_form_whatever($field_list + $validators + $template);
echo $form;
?>

模板:

<form id="my_custom_form">
    <label>{label.email}</label>
    {input.email}
    <span class="red">{error.email}</span>

    <div>
        {label.password}
        {error.password}
        {input.password}
    </div>

    <div class="purple">{input.submit}<div>
</form>
于 2009-02-11T10:41:37.793 回答