Zend表格:我如何让自己的意志屈从?
我已经多次阅读手册,我已经search了Google提供的关于这个主题的post,甚至还买了几本和ZF打交道的书。 现在,为什么我还是困惑?
我可以使用Zend_Form创build一个表单来validation和正常工作。 我无法做到这一点的forms,看起来就像我希望看到我想要的错误信息。 我想要自定义button,我想要时髦的布局,我想插入表单中的文本等。
有没有人有一个简单的方法来实现这些东西? 让我感觉像框架的东西是节省我的时间,而不是花费? 我可以放弃Zend Form …制作自己的表单,让它的行为碰到一个页面来validation和处理发布的数据,我可以尽可能快地做到这一点,但我真的想“得到”,并能够使用它,因为它显然是有意的。
有什么build议? 任何简单的“如何”为自定义button,时髦的布局和基本(或更先进,因为有大量的基本教程,跳过了更难的问题)“完成任务”与zendforms?
巴雷特·康拉德的build议是我所build议的。 另外,请记住,您不需要使用表单对象来呈现您的表单。
你可以做的一件事就是在你的视图脚本中创build一个与表单类名称相同的表单。
您的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:
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表单,你的类中的每个元素都有自己的validation器和需求。 回到你的行动中,你可以创build一个你的表单类的实例,并validation你的表单/ 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(); } }
您可以使用此方法在一个组中显示窗体顶部的错误消息。
这是一个基本的例子,但它可以让你完全控制表单的performance,而不用花时间去学习使用装饰器。 在我看来,Zend_Form的大部分优势在于validation和过滤属性。 这给了你这个力量。 这样的解决scheme的主要缺点是,您的视图脚本HTML表单可能会失去与您的表单类同步。
例如,在视图中分别渲染每个元素
<!-- 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视图助手(即在validation失败时显示错误消息并维护表单字段的值)的能力,但是可以给你完全的定制能力。
如果你想进一步,然后closures各个表单元素的默认装饰器,然后附上自己的进一步定制使用什么标签(即错误消息和标签)或根本不使用装饰器比呈现表单元素本身),然后手动编写所有周围的HTML。 在表单级别和视图级别完成自定义function,而不会失去Zend_Form的好处。
Matthew Weier O'Phinney开始了一系列有关Zend_Form装饰器的博客文章:
- 最简单的Zend_Form装饰器
- 从内到外:如何对装饰器进行层次化
- 单独渲染Zend_Form装饰器
- 创build复合元素
目前我们已经有了比旧的组件更加复杂的新的Zend\Form
,而且更加可控,封装和强大。 所以,我下面所说的不适用。 新的组件是恕我直言,一个巨大的改善,因为它…
- …让你完全控制你想要呈现你的表单的方式,你需要写更多的视图代码,但这是值得的
- …最大限度地将数据,逻辑和视图分开
- …使用HTML5表单元素
- …给你很多select你想如何把你的forms,如水合,注释等
关于Zend_Form的旧答案
我可能无法帮助,因为我有完全相同的问题。 我认为Zend_Form装饰器是强大的,但迄今为止,迄今为止我所见过的程序员友好和不直观的ZF片段,而且我在各个项目中使用了ZF的主要部分。
这就是说,我只能从我的经验中得到一些提示:
- filter很容易使用,而不使用窗体
- 大部分(如果不是全部)你想要实现的东西都是在装饰器的帮助下完成的
- 我从小表单开始,一点一点地添加东西,但是我在某些表单中没有得到一些东西,因为结果是基于试错法(主要是装饰器)
- 我从Zend邮件列表中获得了我在networking上无法find的信息
从相关的问题到右边,显然Zend_Form缺乏全面的文档,尤其是在非直观的情况下。 我真的很想看到ZF的工作人员就像我喜欢Zend Framework一样。
所以这个答案可能只是让你知道你不是唯一有这个问题的人。
或者你也可以使用绝地的技巧 !
补充说的是:
不要害怕装饰者,如果你决定坚持使用Zend_Form,你将会使用它们。 一旦你“明白了”就很简单,不幸的是,文档很薄弱,玩这个游戏几乎是唯一的途径。
ViewScript和ViewHelper装饰器给你很多的力量。
不要害怕挖掘存在的不同装饰器的源代码,看看它们是如何做的(我比较了原始的装饰器和dojo的装饰器)。
我认为肖恩所暗示的是,你不需要调用form-> render,你可以在你的viewscript中使用这样的东西。
<someHtmlThingy name="blah" value="<?php echo $this->formInstance->getElement('whatever')->getValue(); ?>" />
我曾经在一个项目(Zend_Form之前)中构build了一组validation器,并使用了标准的观察logging。 这是一个更多的工作(pipe道的错误消息等),但不是过度的Zend_Form创build元素相比。
如果你只是想在你的表单元素之前或之后添加任意标记而不使用ViewScript装饰器,你可以使用我的AnyMarkup装饰器: http ://www.zfsnippets.com/snippets/view/id/62
例如,下面是如何在包装标签中添加一个图像的input字段(需要包括用于自动加载的path才能正确设置):
$ form-> addElement('text','my_field',array( 'label'=>'input信息:', 'decorators'=>数组( “视图助手”, 数组('AnyMarkup',数组 'markup'=>'<span class =“imgwrapper”>'。 '<img src =“info.png”alt =“信息图标”/> </ span>'), 'placement'=>'prepend' ) 'HtmlTag', '标签' ) );
跳过表单装饰器(IE浏览器 – 打印表单的各个元素,而不是仅仅依靠表单的标准视图助手来处理所有事情)是一种重新获得控制权的方法。
另一个select是简单地手动编写你的表单,只使用ZF来处理validation和过滤。
不幸的是,更复杂的问题被忽略,因为没有真正的具体目的或目标,真的很难写一个例子或如何做。 我花了一些时间帮助另一位开发者,他们想要修改隐藏元素的显示方式 ,但是他的案例非常具体,所以更容易深入到具体的细节。
大多数更复杂的任务真的归结为扩展特定字段types的默认助手。 例如,我有一个项目,我希望在提交表单之后将所有types的“错误”应用于所有未通过validation的字段,而不是写出validation错误文本:
<label for="field">Label:</label> <input type="text" name="field" id="field" class="error">
这是一个相当复杂的过程,因为默认情况下,实际的表单元素不可用于视图助手,所以助手不能检查元素是否有validation错误。 所以我去了下面的过程:
- 我不得不为每个字段types创build一个客户视图助手,我想应用“错误”类。 在这里,我
formXXX()
了formXXX()
方法,并添加一个检查来查看元素是否有错误。 此外,我添加了一个setElement()
方法,装饰器可以调用该方法来设置元素的一个实例,以便我的帮手可以检查错误。 - 接下来,我不得不重写默认的
Zend_Form_Decorator_ViewHelper
。 在这个例子中,我访问了视图并实例化了表单元素types的帮助器,并检查了我在视图助手中创build的setElement()
方法的存在性,如果它存在,就设置它。 通过这样做,我可以扩展一些表单元素types而不是其他的而不破坏整个脚本。 - 在我的每个表单的init()函数中,我必须添加一个新的元素前缀path(
addElementPrefixPath('My_Form_Decorator'), 'path/to/decorator')
)指向我的新表单装饰器。 - 最后,我必须添加助手path到我的应用程序,以便Zend框架可以find我已经在第一个项目符号创build的助手:
addHelperPath('/path/to/helpers', 'My_View_Helper');
你可以看到为什么编写复杂的教程真的需要现实世界的问题。 关于build立这些助手或复杂的装饰scheme的重要部分是,所有这一切都让人烦恼,它可以让你很容易地创build很多forms,坚持相同的devisescheme,并修改他们的输出统一非常迅速,如果改变需要制作。 但是另一方面,如果你觉得自己花了大量的时间去思考如何做一件简单的工作,那么为了一种forms的好处,我可以跳过它!
如果您希望获得更具体的帮助,我将非常乐意提供帮助。 只是提出另一个问题(或更新这一个),我会尽我所能帮助。
whycantitbemorethan25c上面提到了它们,但是ViewScripts为渲染表单提供了非常细致的控制。 Zend_Form是快速的,所以它假定像标准装饰器一样的许多默认值,并将它们添加到表单对象中的方式sorting。 使用ViewScript,您可以跳过这一部分,然后将所有元素放在正常的HTML中。
不要完全忽略装饰者的概念。 即使稍后在ViewScript中使用它们,也可以对各个元素进行样式设置。 例如,您可以像其他人所build议的那样将它们用于错误消息。
如果你有非常复杂的forms,有多个数据点类似的行动(想想有一个用户列表的活动/不活跃button和每个删除button),你应该考虑Zend_Form_SubForm 。 子窗体可以像使用正常forms一样使用ViewScript,如果您使用ViewScript将窗体级联到带有子窗体的ViewScript,那么您将得到包含很好的逻辑和演示,而不仅仅是一个简单的窗体。
我写了一些子类到Zend_Form和装饰器,使它在<table>中布局表单。 它甚至有一些特殊的技巧来做一些事情,比如让多个提交button显示在同一行上。
花了整整一天的时间来搞定它的工作。 它是针对Zend 1.5.1编写的,所以不知道它是否可以与当前版本一起工作,但是如果您有兴趣,我可以在某处上传源代码。
这似乎是Zend Forms非常常见的投诉。
(我知道我会被CSS纯粹主义者用表格来布局表格,虽然我同意CSS对大多数情况来说都更好,但是我还没有看到使用CSS的好表单布局就像一个丑陋的混血儿,用表格的forms在我需要的每一个浏览器上都“工作”。
编辑:好的,说到丑陋的克鲁日,我已经把我的代码生成github中的表格zend表单。 去这里看看吧。 (因为gaoshan88问了。)
回答这里。 希望它会帮助你。 我经历了大量的信息,直到find它。
<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>
您现在可能已经解决了这个问题,但我一直在做一些工作,需要一个类似的解决scheme。
形状配合> getSubform( '子窗体'); foreach($ subform as $ key => $ value){ / /一些标记和自定义代码在这里 打印$值; / /一些标记和自定义代码在这里 } ?>
在foreach循环中,可以添加表格标记。 如果您已经适当地为表格行命名了键,则它们应与表单键相匹配。 你甚至可以使用一个通过键来抓取适当的子表单的循环,或者甚至可以使用一个按键的元素。 你可以跳过foreach循环,如果你知道键,只要说print $ subform ['somekey']; 假设你设置主窗体说$ form-> setIsArray(true); (不确定是否最后一部分是绝对必要的,但对于复杂的forms,应该像这样设置。
我删除了默认的装饰器,所以我可以完全控制每个元素内的打印。 Zend_Form应该有一个内置的方法来抓取个别元素更容易一点..但我认为这工作得很好。
希望对某人有帮助!
肖恩McSomething的第一个build议是我的方式去。 我一直认为做<?php echo $this->form ?>
来渲染表单太神奇了。 我会更进一步,并通过$element->renderDecorator()
魔术方法渲染个别装饰器而不是个别元素。 这样,您将不必担心您定义装饰器的顺序。 你只需要他们在那里,你将不必添加这些讨厌的,不直观的HtmlTag
装饰器。 我做了一个关于这个的博客文章 。
我不确定Zend是否已经有了这个function,但是一个快速的解决scheme是扩展这个类,让它接受一个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>