任何数据库驱动的应用程序(Couch 恰好是其中之一)基本上只包含四个基本操作 -
创建、读取、更新和删除(众所周知的 CRUD)。
而目前位置,只公开了一个 pages标签,读取。
向前端开放CRUD可以干很多事情,
- 允许访问者提交文章或职位发布等内容。
- 允许访问者提交他们的评论和评级。
-允许一组注册用户创建/管理他们自己的页面。
Couch通过简单的方法把创建/更新/删除功能带到前端使用,强大的力量伴随着巨大的责任,Couch 还为您提供所有必要的安全工具,以安全地实现这种新发现的力量的潜力。
真实案例操作
警告:接下来的讨论假设您已经熟悉 Couch 的表单和可编辑区域概念。
如果您是 Couch 的新手,请花一些时间先学习一下,因为这里讨论的所有新功能都建立在它们之上。
在我们开始我们的小教程之前,需要先完成一个小准备步骤。
由于并非所有部署 Couch 的站点都需要数据绑定表单功能,尽管 Couch 附带该模块,但默认情况下不启用它。
要启用此模块,请编辑“couch/addons”文件夹中的“kfunctions.php”文件并取消注释(如果从旧版本升级,则添加)以下行
require_once( K_COUCH_DIR.'addons/data-bound-form/data-bound-form.php' );
我们教程中的代码还将利用cms:set_flash标签来设置表示表单提交成功的 flash 消息。这将需要启用“会话”模块,因此也取消注释以下行(如果尚未如此)
require_once( K_COUCH_DIR.'addons/cart/session.php' );
启用所需的模块后,我们终于可以开始了。
假设我有一个留言板,标题,内容,电话三个字段,把留言提交到后台我们需要两个东西:
- 前端提交表单。
- 可以接收留言的后端数据库。
如果我们暂时忽略对提交的前端数据进行保存的目的,我们可以看到 Couch 已经可以用于独立实现这两个部分中的每一个。
- cms:form和cms:input标签来实现前端表单。
- 带有cms:editable标签的可克隆模板,用于保存数据。
但是很明显的问题,这两个没有联系。
Couch数据绑定表单功能可以很简单的解决此问题,下面见识一下“绑定”二字的真正威力。
一个极简的留言表单如下:
<form method="post"><input type='text' name='title' /> <input type='text' name='tel' /> <input type='textatea' name='content' /> </form>
再创建和注册一个后台的可编辑的克隆模板,假设命名为:feedback.php,和前端数据对应的主要结构代码应该如下:
<cms:template title='留言板' clonable='1'> <cms:editable name='title' desc='标题' required='1' type='text' /><cms:editable name='tel' desc='电话' required='1' type='text' /> <cms:editable name='content' desc='留言内容' required='1' type='textarea' /></cms:template>
我们把前端表单使用couch语义转换过来,这是及其简单的工作:
<cms:set submit_success="<cms:get_flash 'submit_success' />" /> <cms:if submit_success > <h4>Success: Your application has been submitted.</h4> </cms:if> <cms:form method='post' anchor='0'> <cms:if k_success > <cms:set_flash name='submit_success' value='1' /> <cms:redirect k_page_link /> </cms:if> <cms:if k_error > <div class="error"> <cms:each k_error > <br><cms:show item /> </cms:each> </div> </cms:if> <cms:input name="title" type="text" /> <cms:input name="tel" type="text" /> <cms:input name="content" type="text" /> <cms:if "<cms:not submit_success />" > <button type="submit">Submit Application</button> </cms:if> </cms:form>
注意到最后一个content字段了吗,原来是textarea,转化后是text,这同行适用于select, radio, checkbox等,这是故意为之,稍后将看到这背后的逻辑所在。
绑定
修改form标签
前:
<cms:form method='post' anchor='0'>
后:
<cms:form masterpage=k_template_name mode='create' enctype='multipart/form-data' method='post' anchor='0'>
加了一堆标签和值,用于表单提交。
这里的关键变化是“masterpage”参数。通过指定此参数,我们让表单知道它不再是常规表单,而是“数据绑定”表单(绑定到指定为母版页的模板)。
另一个感兴趣的参数是“mode”。它可以采用两个可能的值,“edit”和“create”。但是,对于我们的本教程,我们将其硬编码为“create”,因为我们只会使用我们的表单来创建新的克隆页面,而不会用于编辑现有页面。
字段值的绑定改造:
前:
<cms:input name="title" type="text" /> <cms:input name="tel" type="text" /> <cms:input name="content" type="text" />
后:
<cms:input name="title" type="bound" /> <cms:input name="tel" type="bound" /> <cms:input name="content" type="bound" />
前端字段全部变成了bound类型,刷新前端后发现尽管前端全部为bound类型,但是textarea呈现的样式依旧是textarea,它调取到了后端的“可编辑区域”的类型,一一对应,同样适用于select,radio,checkbox。
每个渲染都与它在管理面板中所做的完全一样,这就是“数据绑定”中的“绑定”。您会发现,尽管我们将所有输入框的类型都声明为相同的 `bound`,但在前端,每个输入框的渲染方式却各不相同——例如,“position”输入框渲染成下拉列表,“resume”输入框渲染成文件输入框等等。实际上,每个输入框的渲染方式都与后台管理面板中的完全一致。这就是 `data-bound` 中“bound”的含义。
请仔细阅读以下说明—— 为了在前端渲染绑定的 cms:input 元素,Couch 实际上使用了表单绑定的模板中同名“可编辑区域”的定义。 明白了吗?关键在于绑定的 cms:input 元素要使用与已定义可编辑区域相同的“名称”。
所以,实际上我们在前端表单上看到的,正是我们在后端看到的那些可编辑区域。这就像我们在表单上切开了一道缝隙,管理面板中的可编辑区域从这些缝隙里露了出来一样(至少我是这么觉得的)。
测试一下表单。我们为可编辑区域定义的所有验证、要求等也将在前端强制执行(这并不奇怪,因为这些实际上就是可编辑区域)。
当所有输入框都填写了正确的数据后,表单提交成功,` <cms:if k_success> ` 代码块执行。但是,我们还没有在那里放置任何内容。让我们在最终修改中添加它。
表单提交成功后,保留已提交的值
修改前:
<cms:if k_success > <cms:set_flash name='submit_success' value='1' /> <cms:redirect k_page_link /> </cms:if>
修改后:
<cms:if k_success > <cms:db_persist_form _invalidate_cache='0' _auto_title='1' /> <cms:set_flash name='submit_success' value='1' /> <cms:redirect k_page_link /> </cms:if>
'db_persist_form' 标签是解决此问题的最后一块拼图。
不带任何参数使用此标签时,它会直接获取提交的值(来自“绑定”的输入框),并将其保存到表单绑定的模板中。由于在本例中,表单的绑定“模式”为“创建”,因此保存操作会创建一个新的模板克隆页面。
尝试从前端提交一些已填写的表单。返回管理面板后,您应该会看到一个列表,其中包含了所有成功提交表单后创建的克隆页面。

尝试编辑任何此类页面,您应该可以看到所有已提交的数据。

这就是我们目前的表单内容:
<cms:set submit_success="<cms:get_flash 'submit_success' />" /> <cms:if submit_success > <h4>Success: Your application has been submitted.</h4> </cms:if> <cms:form masterpage=k_template_name mode='create' enctype='multipart/form-data' method='post' anchor='0' > <cms:if k_success > <cms:db_persist_form _invalidate_cache='0' _auto_title='1' /> <cms:set_flash name='submit_success' value='1' /> <cms:redirect k_page_link /> </cms:if> <cms:if k_error > <div class="error"> <cms:each k_error > <br><cms:show item /> </cms:each> </div> </cms:if> <label>Title</label> <cms:input name="title" type="bound" /> <br /> <label>Tel</label> <cms:input name="tel" type="bound" /> <br /> <label>Content</label> <cms:input name="content" type="bound" /> <br /> <cms:if "<cms:not submit_success />" > <button type="submit">Submit Application</button> </cms:if> </cms:form>
cms:db_persist_form标签的 '_auto_title' 参数值得探讨。查看后台任何克隆页面的编辑界面,你会发现它有两个默认字段:名称 (name) 和标题 (title)。其中,只有名称是必填项。名称是系统内部识别克隆页面的唯一 ID。但是,只要填写了标题,名称就可以留空。这是因为,如果未提供名称,Couch 会自动根据标题生成名称。但是,如果连标题也留空,则会导致错误。
在本教程中,如果我们只是简单地使用
<cms:db_persist_form />
这将导致错误提示,指出“名称”不能为空。上面的解释应该可以说明这一点。
解决方案 一:我们可以复制管理面板中使用的方法(即提供姓名和职称的显式输入框)。这可以通过使用绑定到系统字段的 cms:input 字段来实现,例如:
<cms:input type="bound" name="k_page_name" />
<cms:input type="bound" name="k_page_title" />
如果省略绑定到“k_page_name”的输入,则会使用绑定到“title”的字段的值(即 k_page_title)自动生成名称。
2. 我们可以间接地为名称/标题提供值,作为 cms:db_persist_form 标签的参数,例如:
<cms:db_persist_form
k_page_name='my-page-name'
k_page_title='My Page Name'/>
与之前一样,如果省略“k_page_name”,则会使用“k_page_title”的值自动生成页面名称。当然,在实际应用中,与其硬编码这些值,不如使用一些代码或算法来提供唯一的值。
就我们教程中讨论的情况而言,第一种方案(显式输入框)对访问者的要求过高。第二种方案要么要求每次提交都提供唯一的名称,要么提供一个固定的“标题”,然后依靠系统从中生成唯一的“名称”。由于“标题”是固定的,生成的名称总是会带有一个唯一的后缀(1、2 等)。如果提交数量达到数千,这样做会造成资源浪费。
总之,仔细想想,“名称”只是系统的一个要求,它本身并不会对我们正在采集的数据(即应用程序)产生任何影响。因此,提供所需名称的最有效方法是让表单自行生成一个。这就是“_auto_title”参数的作用。
<cms:db_persist_form
_auto_title='1'/>