<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>4's symfony blog &#187; embed</title>
	<atom:link href="http://www.foolbirds.com/t/embed/feed" rel="self" type="application/rss+xml" />
	<link>http://www.foolbirds.com</link>
	<description>all about symfony</description>
	<lastBuildDate>Fri, 14 Oct 2011 12:36:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>内嵌表单详解（How to Embed Forms in Symfony 1.2 Admin Generator 中文版）</title>
		<link>http://www.foolbirds.com/how-to-embed-forms-in-symfony-12-admin-generator.html</link>
		<comments>http://www.foolbirds.com/how-to-embed-forms-in-symfony-12-admin-generator.html#comments</comments>
		<pubDate>Thu, 18 Jun 2009 15:31:10 +0000</pubDate>
		<dc:creator>maker</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[关联]]></category>

		<guid isPermaLink="false">http://www.foolbirds.com/?p=862</guid>
		<description><![CDATA[译者：Maker.Wang[at]gmail.com
原文：http://sandbox-ws.com/how-to-embed-forms-in-symfony-12-admin-generator
译者注： Embed form是一个被忽略了的却很实用的技术，可能是由于embed form是新功能的缘故，相关的文档非常少，特别是中文文档，很早以前就听说了embed form，但一直没有机会实际应用， 昨天项目的新需求让我又想起了embed form， 所以又翻出了以前看过的文档， 仔细复习一遍， 同时也翻译出来分享个各位战友们。这是小弟的第一篇译文，难免有错误和遗漏，希望大家多包涵，多提宝贵意见。 &#8211; maker 2009.6.19
第一部分. 一对一关联内嵌表单

Symfony 1.2 添加了很多令人兴奋的新特性，并已经成为了一个很好很强大的PHP开发框架。 其中的一个特性是将一个Form嵌入另一个Form中。那么这意味着什么呢？
第一个模型如下图所示：
 上图是一个公司和联系方式的一对一关系模型。
这是我们的 schema.yml:


propel: 
 _attributes: 
 package: lib.model 
 defaultIdMethod: native 
 company: 
 _attributes: { phpName: Company } 
 id: { type: INTEGER, size: &#8216;11&#8242;, primaryKey: true, autoIncrement: true, required: true } 
 name: { type: VARCHAR, size: &#8216;255&#8242;, required: true } 
 contact_id: { type: INTEGER, size: &#8216;11&#8242;, required: false, foreignTable: contact, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT } 
 _indexes: { company_FI_1: [contact_id] } 
 contact: 
 _attributes: { phpName: Contact } 
 id: { type: INTEGER, size: &#8216;11&#8242;, primaryKey: true, autoIncrement: true, required: true } 
 [...]]]></description>
			<content:encoded><![CDATA[<p>译者：<a title="Maker's Blog" href="http://foolbird.net" target="_blank">Maker.Wang[at]gmail.com</a><br />
原文：<a href="http://sandbox-ws.com/how-to-embed-forms-in-symfony-12-admin-generator">http://sandbox-ws.com/how-to-embed-forms-in-symfony-12-admin-generator</a></p>
<p>译者注： Embed form是一个被忽略了的却很实用的技术，可能是由于embed form是新功能的缘故，相关的文档非常少，特别是中文文档，很早以前就听说了embed form，但一直没有机会实际应用， 昨天项目的新需求让我又想起了embed form， 所以又翻出了以前看过的文档， 仔细复习一遍， 同时也翻译出来分享个各位战友们。这是小弟的第一篇译文，难免有错误和遗漏，希望大家多包涵，多提宝贵意见。 &#8211; maker 2009.6.19</p>
<p><strong>第一部分. 一对一关联内嵌表单<br />
</strong></p>
<p>Symfony 1.2 添加了很多令人兴奋的新特性，并已经成为了一个很好很强大的PHP开发框架。 其中的一个特性是将一个Form嵌入另一个Form中。那么这意味着什么呢？</p>
<p>第一个模型如下图所示：</p>
<p><img class="aligncenter size-full wp-image-889" title="company_contact" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_contact.jpg" alt="company_contact" width="516" height="117" /> 上图是一个公司和联系方式的一对一关系模型。</p>
<p>这是我们的 schema.yml:</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>propel: </span></span></li>
<li><span> _attributes: </span></li>
<li class="alt"><span> package: lib.model </span></li>
<li><span> defaultIdMethod: native </span></li>
<li class="alt"><span> company: </span></li>
<li><span> _attributes: { phpName: Company } </span></li>
<li class="alt"><span> id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, primaryKey: </span><span class="keyword">true</span><span>, autoIncrement: </span><span class="keyword">true</span><span>, required: </span><span class="keyword">true</span><span> } </span></span></li>
<li><span> name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: </span><span class="keyword">true</span><span> } </span></span></li>
<li class="alt"><span> contact_id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, required: </span><span class="keyword">false</span><span>, foreignTable: contact, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT } </span></span></li>
<li><span> _indexes: { company_FI_1: [contact_id] } </span></li>
<li class="alt"><span> contact: </span></li>
<li><span> _attributes: { phpName: Contact } </span></li>
<li class="alt"><span> id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, primaryKey: </span><span class="keyword">true</span><span>, autoIncrement: </span><span class="keyword">true</span><span>, required: </span><span class="keyword">true</span><span> } </span></span></li>
<li><span> first_name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: </span><span class="keyword">true</span><span> } </span></span></li>
<li class="alt"><span> last_name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: </span><span class="keyword">true</span><span> } </span></span></li>
<li><span> company_id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, required: </span><span class="keyword">false</span><span>, foreignTable: company, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT } </span></span></li>
<li class="alt"><span> _indexes: { contact_FI_1: [company_id] } </span></li>
</ol>
</div>
<pre class="c" style="display: none;">propel:
  _attributes:
    package: lib.model
    defaultIdMethod: native
  company:
    _attributes: { phpName: Company }
    id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
    name: { type: VARCHAR, size: '255', required: true }
    contact_id: { type: INTEGER, size: '11', required: false, foreignTable: contact, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT }
    _indexes: { company_FI_1: [contact_id] }
  contact:
    _attributes: { phpName: Contact }
    id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
    first_name: { type: VARCHAR, size: '255', required: true }
    last_name: { type: VARCHAR, size: '255', required: true }
    company_id: { type: INTEGER, size: '11', required: false, foreignTable: company, foreignReference: id, onDelete: SET NULL, onUpdate: RESTRICT }
    _indexes: { contact_FI_1: [company_id] }</pre>
<p>要注意的是这里的两个外键并不是必须存在（required）的，但是必须有了这两个外键我们才能将Contact Form嵌入到Company Form。</p>
<p>现在我们已经有了Schema, 让我们生成sql语句，模型（models）, 表单（forms）, 过滤器（filters）, 并且创建数据表。</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>$ php symfony propel:build-sql </span></span></li>
<li><span>$ php symfony propel:build-model </span></li>
<li class="alt"><span>$ php symfony propel:build-forms </span></li>
<li><span>$ php symfony propel:build-filters </span></li>
<li class="alt"><span>$ php symfony propel:insert-sql &#8211;env=dev<br />
</span></li>
</ol>
<p>译者注：上面这组命令我们也可以简单的使用一个命令来完成</p></div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li><span>$ php symfony propel:build-all</span></li>
</ol>
</div>
<pre class="c" style="display: none;">$ php symfony propel:build-sql
$ php symfony propel:build-model
$ php symfony propel:build-forms
$ php symfony propel:build-filters
$ php symfony propel:insert-sql --env=dev</pre>
<p>现在我们使用symfony中的admin generator来生成一个模块, 来看看如何生成和操作他们之间的关联。</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>$ php symfony propel:generate-admin backend Company </span></span></li>
</ol>
</div>
<pre class="c" style="display: none;">$ php symfony propel:generate-admin backend Company</pre>
<p style="text-align: center;">我们生成了如下图所示的模块：</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-890" title="company_1" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_1.jpg" alt="company_1" width="560" height="150" />现在如果我们点击“New&#8221;链接我们将看到界面如下：</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-891" title="company_2" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_2.jpg" alt="company_2" width="560" height="146" /></p>
<p>注意外键&#8221;contact_id&#8221;被admin generator处理成一个下拉列表，当然这不是我们想要的结果，我们需要在新建Company的同时创建Contact. 感谢symfony 1.2 支持表单内嵌， 这会使我们的工作变得非常简单。</p>
<p>首先打开 &#8220;CompanyForm.class.php&#8221; 并且输入代码如下：</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> configure() { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// get Contact model object</span><span> </span></span></li>
<li><span> <span class="vars">$contact</span><span> = </span><span class="vars">$this</span><span>-&gt;getObject()-&gt;getContact(); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// contact object is null</span><span> </span></span></li>
<li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="func">is_null</span><span>(</span><span class="vars">$contact</span><span>)) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// create a new Contact object</span><span> </span></span></li>
<li><span> <span class="vars">$contact</span><span> = </span><span class="keyword">new</span><span> Contact(); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// set the copmany of the newly created object to the current company</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$contact</span><span>-&gt;setCompany(</span><span class="vars">$this</span><span>-&gt;getObject()); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set the contact of the current company</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;getObject()-&gt;setContact(</span><span class="vars">$contact</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> } </span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// create a new contact form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$contact_form</span><span> = </span><span class="keyword">new</span><span> ContactForm(</span><span class="vars">$contact</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// embed the contact form in the current company form</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;embedForm(</span><span class="string">&#8216;contact&#8217;</span><span>, </span><span class="vars">$contact_form</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// remove the contact_id from the form</span><span> </span></span></li>
<li class="alt"><span> unset(<span class="vars">$this</span><span>[</span><span class="string">'contact_id'</span><span>]); </span></span></li>
<li><span> </span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function configure() {

	// get Contact model object
	$contact = $this-&gt;getObject()-&gt;getContact();

	// contact object is null
	if (is_null($contact)) {

		// create a new Contact object
		$contact = new Contact();

		// set the copmany of the newly created object to the current company
		$contact-&gt;setCompany($this-&gt;getObject());

		// set the contact of the current company
		$this-&gt;getObject()-&gt;setContact($contact);

	}

	// create a new contact form
	$contact_form = new ContactForm($contact);

	// embed the contact form in the current company form
	$this-&gt;embedForm('contact', $contact_form);

	// remove the contact_id from the form
	unset($this['contact_id']);

}</pre>
<p>接下来，打开ContactForm.class.php 并输入代码如下：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="keyword">public</span><span> function configure() { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> unset($<span class="keyword">this</span><span>[</span><span class="string">'company_id'</span><span>]); </span></span></li>
<li><span> </span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="c" style="display: none;">public function configure() {

	unset($this['company_id']);

}</pre>
<p>现在修改模型类Company.php，在删除Contact的同时删除关联的Company</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> </span><span class="func">delete</span><span>(PropelPDO </span><span class="vars">$con</span><span> = null) { </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;getContact()-&gt;</span><span class="func">delete</span><span>(</span><span class="vars">$con</span><span>); </span></span></li>
<li class="alt"><span> parent::<span class="func">delete</span><span>(</span><span class="vars">$con</span><span>); </span></span></li>
<li><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function delete(PropelPDO $con = null) {
	$this-&gt;getContact()-&gt;delete($con);
	parent::delete($con);
}</pre>
<p>最后一点也是很重要的，编辑generator.yml如下（这一步不是必须得） ：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>generator: </span></span></li>
<li><span> <span class="keyword">class</span><span>: sfPropelGenerator </span></span></li>
<li class="alt"><span> param: </span></li>
<li><span> model_class:           Company </span></li>
<li class="alt"><span> theme:                 admin </span></li>
<li><span> non_verbose_templates: <span class="keyword">true</span><span> </span></span></li>
<li class="alt"><span> with_show:             <span class="keyword">false</span><span> </span></span></li>
<li><span> singular:              ~ </span></li>
<li class="alt"><span> plural:                ~ </span></li>
<li><span> route_prefix:          company </span></li>
<li class="alt"><span> with_propel_route:     1 </span></li>
<li><span> </span></li>
<li class="alt"><span> config: </span></li>
<li><span> actions: ~ </span></li>
<li class="alt"><span> fields: </span></li>
<li><span> contact_id: { label: Company Contact } </span></li>
<li class="alt"><span> list: </span></li>
<li><span> display: [=name, contact] </span></li>
<li class="alt"><span> filter:  ~ </span></li>
<li><span> form:    ~ </span></li>
<li class="alt"><span> edit:    ~ </span></li>
<li><span> <span class="keyword">new</span><span>:     ~ </span></span></li>
</ol>
</div>
<pre class="c" style="display: none;">generator:
  class: sfPropelGenerator
  param:
    model_class:           Company
    theme:                 admin
    non_verbose_templates: true
    with_show:             false
    singular:              ~
    plural:                ~
    route_prefix:          company
    with_propel_route:     1

    config:
      actions: ~
      fields:
          contact_id: { label: Company Contact }
      list:
          display: [=name, contact]
      filter:  ~
      form:    ~
      edit:    ~
      new:     ~</pre>
<p style="text-align: center;">现在进入新建&#8221;Company&#8221;页面你会看到如图所示：</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-892" title="company_3" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_3.jpg" alt="company_3" width="560" height="198" />尝试添加，编辑和删除一些记录以便确认一切是正确的。</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-893" title="company_4" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_4.jpg" alt="company_4" width="560" height="183" /></p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-894" title="company_5" src="http://www.foolbirds.com/wp-content/uploads/2009/06/company_5.jpg" alt="company_5" width="560" height="189" /></p>
<p style="text-align: center;">
<p style="text-align: center;">
<p style="text-align: left;"><strong>第二部分. 一对多关联的内嵌</strong><strong>表单</strong></p>
<p>在文章的第一部分我们讲解了如何实一对一关联的表单内嵌。但是我们经常需要在编辑父对象的时候编辑或者添加子对象， 这并不是我们要使用admin generator的原因，总之在这部分文章里我们将要讲解一对多关系的表单内嵌。</p>
<p>在开始之前，我们看到的是最终要实现的CategoryForm。</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-895" title="embed_2" src="http://www.foolbirds.com/wp-content/uploads/2009/06/embed_2.png" alt="embed_2" width="592" height="309" /></p>
<p>本文需要的文件</p>
<ul>
<li><a href="http://www.foolbirds.com/wp-content/uploads/2009/06/sfWidgetFormInputDelete.class.php.zip">sfWidgetFormInputDelete.class.php</a></li>
</ul>
<p>Ok, 我们开始吧，考虑下面这个schema：</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span>category: </span></span></li>
<li><span> _attributes: { phpName: Category } </span></li>
<li class="alt"><span> id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, primaryKey: true, autoIncrement: true, required: true } </span></span></li>
<li><span> name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: true } </span></span></li>
<li class="alt"><span> created_at: { type: TIMESTAMP, required: false } </span></li>
<li><span> updated_at: { type: TIMESTAMP, required: false } </span></li>
<li class="alt"><span>subcategory: </span></li>
<li><span> _attributes: { phpName: Subcategory } </span></li>
<li class="alt"><span> id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, primaryKey: true, autoIncrement: true, required: true } </span></span></li>
<li><span> name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: true } </span></span></li>
<li class="alt"><span> category_id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, required: true, foreignTable: category, foreignReference: id, onDelete: CASCADE, onUpdate: RESTRICT } </span></span></li>
<li><span> created_at: { type: TIMESTAMP, required: false } </span></li>
<li class="alt"><span> updated_at: { type: TIMESTAMP, required: false } </span></li>
</ol>
</div>
<pre class="php" style="display: none;">category:
    _attributes: { phpName: Category }
    id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
    name: { type: VARCHAR, size: '255', required: true }
    created_at: { type: TIMESTAMP, required: false }
    updated_at: { type: TIMESTAMP, required: false }
subcategory:
    _attributes: { phpName: Subcategory }
    id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
    name: { type: VARCHAR, size: '255', required: true }
    category_id: { type: INTEGER, size: '11', required: true, foreignTable: category, foreignReference: id, onDelete: CASCADE, onUpdate: RESTRICT }
    created_at: { type: TIMESTAMP, required: false }
    updated_at: { type: TIMESTAMP, required: false }</pre>
<p>为了实现想要的效果，我们需要需要采取以下步骤</p>
<ol>
<li>修改CategoryForm去包含当前分类所有的子分类的内嵌表单。</li>
<li>修改Widget中的子分类的name</li>
<li>修改CategoryForm添加一个空白的创建新子分类的表单。</li>
<li>重写sfForm类的bind方法，如果name域是空白则跳过保存(saving)和验证(validating)新子分类的表单。</li>
<li>在SubcategoryForm去掉全部的域（fields)</li>
</ol>
<p>为当前分类插入全部子分类的内嵌表单[第1，2，3步]</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="comment">// lib/forms/CategoryForm.class.php</span><span> </span></span></li>
<li><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> configure() { </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// remove timestamps</span><span> </span></span></li>
<li class="alt"><span> unset(<span class="vars">$this</span><span>[</span><span class="string">'created_at'</span><span>], </span><span class="vars">$this</span><span>[</span><span class="string">'updated_at'</span><span>]); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// embed forms only when editing</span><span> </span></span></li>
<li><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>-&gt;isNew()) { </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed all subcategory forms</span><span> </span></span></li>
<li class="alt"><span> <span class="keyword">foreach</span><span> (</span><span class="vars">$this</span><span>-&gt;getObject()-&gt;getSubcategorys() </span><span class="keyword">as</span><span> </span><span class="vars">$subcategory</span><span>) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// create a new subcategory form for the current subcategory model object</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryForm(</span><span class="vars">$subcategory</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed the subcategory form in the main category form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory&#8217;</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getId(), </span><span class="vars">$subcategory_form</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set a custom label for the embedded form</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;widgetSchema[</span><span class="string">'subcategory'</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getId()]-&gt;setLabel(</span><span class="string">&#8216;Subcategory: &#8217;</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getName()); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// change the name widget to sfWidgetFormInputDelete</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;widgetSchema[</span><span class="string">'subcategory'</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getId()][</span><span class="string">'name'</span><span>] = </span><span class="keyword">new</span><span> sfWidgetFormInputDelete(</span><span class="keyword">array</span><span>( </span></span></li>
<li><span> <span class="string">&#8216;url&#8217;</span><span> =&gt; </span><span class="string">&#8216;category/deleteSubcategory&#8217;</span><span>, </span><span class="comment">// required</span><span> </span></span></li>
<li class="alt"><span> <span class="string">&#8216;model_id&#8217;</span><span> =&gt; </span><span class="vars">$subcategory</span><span>-&gt;getId(), </span><span class="comment">// required</span><span> </span></span></li>
<li><span> <span class="string">&#8216;confirm&#8217;</span><span> =&gt; </span><span class="string">&#8216;Sure???&#8217;</span><span>, </span><span class="comment">// optional</span><span> </span></span></li>
<li class="alt"><span> )); </span></li>
<li><span> </span></li>
<li class="alt"><span> } </span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// create a new subcategory form for a new subcategory model object</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryForm(); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed the subcategory form in the main category form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory&#8217;</span><span>, </span><span class="vars">$subcategory_form</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set a custom label for the embedded form</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;widgetSchema[</span><span class="string">'subcategory'</span><span>]-&gt;setLabel(</span><span class="string">&#8216;New Subcategory&#8217;</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> } </span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">// lib/forms/CategoryForm.class.php
public function configure() {

  // remove timestamps
  unset($this['created_at'], $this['updated_at']);

  // embed forms only when editing
  if (!$this-&gt;isNew()) {

    // embed all subcategory forms
    foreach ($this-&gt;getObject()-&gt;getSubcategorys() as $subcategory) {

    // create a new subcategory form for the current subcategory model object
    $subcategory_form = new SubcategoryForm($subcategory);

    // embed the subcategory form in the main category form
    $this-&gt;embedForm('subcategory'.$subcategory-&gt;getId(), $subcategory_form);

    // set a custom label for the embedded form
    $this-&gt;widgetSchema['subcategory'.$subcategory-&gt;getId()]-&gt;setLabel('Subcategory: '.$subcategory-&gt;getName());

    // change the name widget to sfWidgetFormInputDelete
    $this-&gt;widgetSchema['subcategory'.$subcategory-&gt;getId()]['name'] = new sfWidgetFormInputDelete(array(
    'url' =&gt; 'category/deleteSubcategory',      // required
    'model_id' =&gt; $subcategory-&gt;getId(),        // required
    'confirm' =&gt; 'Sure???',                     // optional
    ));

  }

  // create a new subcategory form for a new subcategory model object
  $subcategory_form = new SubcategoryForm();

  // embed the subcategory form in the main category form
  $this-&gt;embedForm('subcategory', $subcategory_form);

  // set a custom label for the embedded form
  $this-&gt;widgetSchema['subcategory']-&gt;setLabel('New Subcategory');

  }
}</pre>
<p>重写bind方法</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> bind(</span><span class="keyword">array</span><span> </span><span class="vars">$taintedValues</span><span> = null, </span><span class="keyword">array</span><span> </span><span class="vars">$taintedFiles</span><span> = null) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// remove the embedded new form if the name field was not provided</span><span> </span></span></li>
<li><span> <span class="keyword">if</span><span> (</span><span class="func">is_null</span><span>(</span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>][</span><span class="string">'name'</span><span>]) || </span><span class="func">strlen</span><span>(</span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>][</span><span class="string">'name'</span><span>]) === 0 ) { </span></span></li>
<li class="alt"><span> </span></li>
<li><span> unset(<span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>], </span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>]); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// pass the new form validations</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;validatorSchema[</span><span class="string">'subcategory'</span><span>] = </span><span class="keyword">new</span><span> sfValidatorPass(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> } <span class="keyword">else</span><span> { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set the category of the new subcategory form object</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>]-&gt;getObject()-&gt;setCategory(</span><span class="vars">$this</span><span>-&gt;getObject()); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> } </span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// call parent bind method</span><span> </span></span></li>
<li class="alt"><span> parent::bind(<span class="vars">$taintedValues</span><span>, </span><span class="vars">$taintedFiles</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function bind(array $taintedValues = null, array $taintedFiles = null) {

	// remove the embedded new form if the name field was not provided
	if (is_null($taintedValues['subcategory']['name']) || strlen($taintedValues['subcategory']['name']) === 0 ) {

		unset($this-&gt;embeddedForms['subcategory'], $taintedValues['subcategory']);

		// pass the new form validations
		$this-&gt;validatorSchema['subcategory'] = new sfValidatorPass();

	} else {

		// set the category of the new subcategory form object
		$this-&gt;embeddedForms['subcategory']-&gt;getObject()-&gt;setCategory($this-&gt;getObject());

	}

	// call parent bind method
	parent::bind($taintedValues, $taintedFiles);

}</pre>
<p>在SubcategoryForm中的域</p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> configure(){ </span></span></li>
<li><span> unset(<span class="vars">$this</span><span>[</span><span class="string">'created_at'</span><span>], </span><span class="vars">$this</span><span>[</span><span class="string">'updated_at'</span><span>], </span><span class="vars">$this</span><span>[</span><span class="string">'category_id'</span><span>]); </span></span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function configure(){
  unset($this['created_at'], $this['updated_at'], $this['category_id']);
}</pre>
<p>现在我们在分类模块下创建deleteSubcategory动作<strong><br />
</strong></p>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="comment">// apps/backend/modules/category/actions/actions.class.php</span><span> </span></span></li>
<li><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> executeDeleteSubcategory(sfWebRequest </span><span class="vars">$request</span><span>) { </span></span></li>
<li class="alt"><span> <span class="vars">$sub_category</span><span> = SubcategoryPeer::retrieveByPk(</span><span class="vars">$request</span><span>-&gt;getParameter(</span><span class="string">&#8216;id&#8217;</span><span>)); </span></span></li>
<li><span> <span class="vars">$sub_category</span><span>-&gt;</span><span class="func">delete</span><span>(); </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;redirect(</span><span class="string">&#8216;@category_edit?id=&#8217;</span><span>.</span><span class="vars">$sub_category</span><span>-&gt;getCategory()-&gt;getId()); </span></span></li>
<li><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">// apps/backend/modules/category/actions/actions.class.php
public function executeDeleteSubcategory(sfWebRequest $request) {
  $sub_category = SubcategoryPeer::retrieveByPk($request-&gt;getParameter('id'));
  $sub_category-&gt;delete();
  $this-&gt;redirect('@category_edit?id='.$sub_category-&gt;getCategory()-&gt;getId());
}</pre>
<p>就是这样了，我希望你会喜欢这篇文章。</p>
<p><strong>第三部分. 内嵌表单的本地化<br />
</strong></p>
<p>在本系列文章的上一部分我们介绍了在父对象中编辑多个子对象的方法。 在本部分钟我们将给子对象添加本地化行为， 为了更清楚的知道我们要做的事先看一下最终的效果。</p>
<p><a href="http://www.foolbirds.com/wp-content/uploads/2009/06/embed_i18n.png"><img class="aligncenter size-full wp-image-897" title="embed_i18n" src="http://www.foolbirds.com/wp-content/uploads/2009/06/embed_i18n.png" alt="embed_i18n" width="540" height="330" /></a></p>
<p>在开始之前，如果你没准备好，我强烈建议你去阅读一下第1，2部分。 OK， 我们开始吧，我们将要修改以下文件：</p>
<ul>
<li><strong>CategoryForm.class.php</strong> 分类模型的表单</li>
<li><strong>SubcategoryI18nForm.class.php</strong> 子分类模型的本地化模型的表单</li>
<li><strong>Subcategory.class.php</strong> 子分类模型</li>
</ul>
<p>本文的附件</p>
<ul>
<li><a href="http://www.foolbirds.com/wp-content/uploads/2009/06/sfWidgetFormInputDelete.class.php.zip">sfWidgetFormInputDelete.class.php</a></li>
</ul>
<h4>Schema.yml</h4>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span>category: </span></span></li>
<li><span> _attributes: { phpName: Category } </span></li>
<li class="alt"><span> id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, primaryKey: true, autoIncrement: true, required: true } </span></span></li>
<li><span> name: { type: VARCHAR, size: <span class="string">&#8216;255&#8242;</span><span>, required: true } </span></span></li>
<li class="alt"><span> created_at: { type: TIMESTAMP, required: false } </span></li>
<li><span> updated_at: { type: TIMESTAMP, required: false } </span></li>
<li class="alt"><span>subcategory: </span></li>
<li><span> _attributes: { phpName: Subcategory, isI18N: true, i18nTable: subcategory_i18n } </span></li>
<li class="alt"><span> id:          { type: integer, required: true, primaryKey: true, autoincrement: true } </span></li>
<li><span> category_id: { type: INTEGER, size: <span class="string">&#8216;11&#8242;</span><span>, required: true, foreignTable: category, foreignReference: id, onDelete: CASCADE} </span></span></li>
<li class="alt"><span> created_at: { type: TIMESTAMP, required: false } </span></li>
<li><span> updated_at: { type: TIMESTAMP, required: false } </span></li>
<li class="alt"><span> </span></li>
<li><span>subcategory_i18n: </span></li>
<li class="alt"><span> _attributes: { phpName: SubcategoryI18n } </span></li>
<li><span> id:          { type: integer, required: true, primaryKey: true, foreignTable: subcategory, foreignReference: id, onDelete: CASCADE } </span></li>
<li class="alt"><span> culture:     { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true } </span></li>
<li><span> name:        { type: varchar, size: 50 } </span></li>
</ol>
</div>
<pre class="php" style="display: none;">  category:
      _attributes: { phpName: Category }
      id: { type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
      name: { type: VARCHAR, size: '255', required: true }
      created_at: { type: TIMESTAMP, required: false }
      updated_at: { type: TIMESTAMP, required: false }
  subcategory:
      _attributes: { phpName: Subcategory, isI18N: true, i18nTable: subcategory_i18n }
      id:          { type: integer, required: true, primaryKey: true, autoincrement: true }
      category_id: { type: INTEGER, size: '11', required: true, foreignTable: category, foreignReference: id, onDelete: CASCADE}
      created_at: { type: TIMESTAMP, required: false }
      updated_at: { type: TIMESTAMP, required: false }

  subcategory_i18n:
    _attributes: { phpName: SubcategoryI18n }
    id:          { type: integer, required: true, primaryKey: true, foreignTable: subcategory, foreignReference: id, onDelete: CASCADE }
    culture:     { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
    name:        { type: varchar, size: 50 }</pre>
<h4>SubcategoryI18nForm.class.php</h4>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> configure() { </span></span></li>
<li><span> unset(<span class="vars">$this</span><span>[</span><span class="string">'culture'</span><span>], </span><span class="vars">$this</span><span>[</span><span class="string">'id'</span><span>]); </span></span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function configure() {
    unset($this['culture'], $this['id']);
}</pre>
<h4>Subcategory.class.php</h4>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> getI18nObject(</span><span class="vars">$culture</span><span> = </span><span class="string">&#8216;en&#8217;</span><span>) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;setCulture(</span><span class="vars">$culture</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="vars">$i18ns</span><span> = </span><span class="vars">$this</span><span>-&gt;getSubcategoryI18ns(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="keyword">if</span><span> (isset(</span><span class="vars">$i18ns</span><span>[0])) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="keyword">return</span><span> </span><span class="vars">$i18ns</span><span>[0]; </span></span></li>
<li><span> </span></li>
<li class="alt"><span> } </span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="keyword">return</span><span> null; </span></span></li>
<li><span> </span></li>
<li class="alt"><span>} </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function getI18nObject($culture = 'en') {

    $this-&gt;setCulture($culture);

    $i18ns = $this-&gt;getSubcategoryI18ns();

    if (isset($i18ns[0])) {

        return $i18ns[0];

    }

    return null;

}</pre>
<h4>CategoryForm.class.php</h4>
<div class="dp-highlighter">
<ol class="dp-c">
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> configure() { </span></span></li>
<li><span> </span></li>
<li class="alt"><span><span class="comment">// remove timestamps</span><span> </span></span></li>
<li><span>unset(<span class="vars">$this</span><span>[</span><span class="string">'created_at'</span><span>], </span><span class="vars">$this</span><span>[</span><span class="string">'updated_at'</span><span>]); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed forms only when editing</span><span> </span></span></li>
<li class="alt"><span> <span class="keyword">if</span><span> (!</span><span class="vars">$this</span><span>-&gt;isNew()) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="vars">$user_culture</span><span> = sfContext::getInstance()-&gt;getUser()-&gt;getCulture(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// embed all subcategory forms</span><span> </span></span></li>
<li><span> <span class="keyword">foreach</span><span> (</span><span class="vars">$this</span><span>-&gt;getObject()-&gt;getSubcategorys() </span><span class="keyword">as</span><span> </span><span class="vars">$subcategory</span><span>) { </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// get the subcategory_i18n model object relative to the current user culture</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_i18n_object</span><span> = </span><span class="vars">$subcategory</span><span>-&gt;getI18nObject(</span><span class="vars">$user_culture</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// create a new subcategory_i18n form for the current subcategory model object</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_i18n_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryI18nForm(</span><span class="vars">$subcategory</span><span>-&gt;getI18nObject(</span><span class="string">&#8216;en&#8217;</span><span>)); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// get widget schema of subcategory_i18n form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_i18n_form_widget_schema</span><span> = </span><span class="vars">$subcategory_i18n_form</span><span>-&gt;getWidgetSchema(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set the input delete widget</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_i18n_form_widget_schema</span><span>[</span><span class="string">'name'</span><span>] = </span><span class="keyword">new</span><span> sfWidgetFormInputDelete(</span><span class="keyword">array</span><span>( </span></span></li>
<li class="alt"><span> <span class="string">&#8216;url&#8217;</span><span> =&gt; </span><span class="string">&#8216;category/deleteSubcategory&#8217;</span><span>, </span><span class="comment">// required</span><span> </span></span></li>
<li><span> <span class="string">&#8216;model_id&#8217;</span><span> =&gt; </span><span class="vars">$subcategory</span><span>-&gt;getId(), </span><span class="comment">// required</span><span> </span></span></li>
<li class="alt"><span> <span class="string">&#8216;confirm&#8217;</span><span> =&gt; </span><span class="string">&#8216;Sure???&#8217;</span><span>, </span><span class="comment">// optional</span><span> </span></span></li>
<li><span> )); </span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// create a new subcategory form for the current subcategory model object</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryForm(</span><span class="vars">$subcategory</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// embed the i18n form</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_form</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory_i18n&#8217;</span><span>.</span><span class="vars">$subcategory_i18n_object</span><span>-&gt;getId(), </span><span class="vars">$subcategory_i18n_form</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// subcategory form widget schema</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_form_widget_schema</span><span> = </span><span class="vars">$subcategory_form</span><span>-&gt;getWidgetSchema(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// disable label</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_form_widget_schema</span><span>[</span><span class="string">'subcategory_i18n'</span><span>.</span><span class="vars">$subcategory_i18n_object</span><span>-&gt;getId()]-&gt;setLabel(false); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed the subcategory form in the main category form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory&#8217;</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getId(), </span><span class="vars">$subcategory_form</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set a custom label for the embedded form</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;widgetSchema[</span><span class="string">'subcategory'</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getId()]-&gt;setLabel(</span><span class="string">&#8216;Subcategory: &#8217;</span><span>.</span><span class="vars">$subcategory</span><span>-&gt;getName()); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> } </span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// create a new subcategory form for a new subcategory model object</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryForm(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// create a new subcategory form for a new subcategory_i18n model object</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_i18n_form</span><span> = </span><span class="keyword">new</span><span> SubcategoryI18nForm(); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// embed the subcategory_i18n form in the parent subcategory form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_form</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory_i18n&#8217;</span><span>, </span><span class="vars">$subcategory_i18n_form</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// subcategory form widget schema</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_form_widget_schema</span><span> = </span><span class="vars">$subcategory_form</span><span>-&gt;getWidgetSchema(); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// disable label</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_form_widget_schema</span><span>[</span><span class="string">'subcategory_i18n'</span><span>]-&gt;setLabel(false); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// embed the subcategory form in the main category form</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;embedForm(</span><span class="string">&#8217;subcategory&#8217;</span><span>, </span><span class="vars">$subcategory_form</span><span>); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// set a custom label for the embedded form</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;widgetSchema[</span><span class="string">'subcategory'</span><span>]-&gt;setLabel(</span><span class="string">&#8216;New Subcategory&#8217;</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> } </span></li>
<li><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">function</span><span> bind(</span><span class="keyword">array</span><span> </span><span class="vars">$taintedValues</span><span> = null, </span><span class="keyword">array</span><span> </span><span class="vars">$taintedFiles</span><span> = null) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="keyword">if</span><span>(!</span><span class="vars">$this</span><span>-&gt;isNew()) { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="vars">$user_culture</span><span> = sfContext::getInstance()-&gt;getUser()-&gt;getCulture(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// remove the embedded new form if the name field was not provided</span><span> </span></span></li>
<li><span> <span class="keyword">if</span><span> (</span><span class="func">is_null</span><span>(</span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>][</span><span class="string">'subcategory_i18n'</span><span>][</span><span class="string">'name'</span><span>]) || </span><span class="func">strlen</span><span>(</span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>][</span><span class="string">'subcategory_i18n'</span><span>][</span><span class="string">'name'</span><span>]) === 0 ) { </span></span></li>
<li class="alt"><span> </span></li>
<li><span> unset(<span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>], </span><span class="vars">$taintedValues</span><span>[</span><span class="string">'subcategory'</span><span>]); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// pass the new form validations</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$this</span><span>-&gt;validatorSchema[</span><span class="string">'subcategory'</span><span>] = </span><span class="keyword">new</span><span> sfValidatorPass(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> } <span class="keyword">else</span><span> { </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set the category of the new subcategory form object</span><span> </span></span></li>
<li><span> <span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>]-&gt;getObject()-&gt;setCategory(</span><span class="vars">$this</span><span>-&gt;getObject()); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// get subcategory embedded forms</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_embedded_forms</span><span> = </span><span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>]-&gt;getEmbeddedForms(); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> <span class="comment">// set subcategory parent of the subcategory_i18n model object</span><span> </span></span></li>
<li><span> <span class="vars">$subcategory_embedded_forms</span><span>[</span><span class="string">'subcategory_i18n'</span><span>]-&gt;getObject()-&gt;setSubcategory(</span><span class="vars">$this</span><span>-&gt;embeddedForms[</span><span class="string">'subcategory'</span><span>]-&gt;getObject()); </span></span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// set the culture of the subcategory_i18n model object</span><span> </span></span></li>
<li class="alt"><span> <span class="vars">$subcategory_embedded_forms</span><span>[</span><span class="string">'subcategory_i18n'</span><span>]-&gt;getObject()-&gt;setCulture(</span><span class="vars">$user_culture</span><span>); </span></span></li>
<li><span> } </span></li>
<li class="alt"><span> </span></li>
<li><span> } </span></li>
<li class="alt"><span> </span></li>
<li><span> <span class="comment">// call parent bind method</span><span> </span></span></li>
<li class="alt"><span> parent::bind(<span class="vars">$taintedValues</span><span>, </span><span class="vars">$taintedFiles</span><span>); </span></span></li>
<li><span> </span></li>
<li class="alt"><span> } </span></li>
</ol>
</div>
<pre class="php" style="display: none;">public function configure() {

// remove timestamps
unset($this['created_at'], $this['updated_at']);

	// embed forms only when editing
	if (!$this-&gt;isNew()) {

		$user_culture = sfContext::getInstance()-&gt;getUser()-&gt;getCulture();

		// embed all subcategory forms
		foreach ($this-&gt;getObject()-&gt;getSubcategorys() as $subcategory) {

			// get the subcategory_i18n model object relative to the current user culture
			$subcategory_i18n_object = $subcategory-&gt;getI18nObject($user_culture);

			// create a new subcategory_i18n form for the current subcategory model object
			$subcategory_i18n_form = new SubcategoryI18nForm($subcategory-&gt;getI18nObject('en'));

			// get widget schema of subcategory_i18n form
			$subcategory_i18n_form_widget_schema = $subcategory_i18n_form-&gt;getWidgetSchema();

			// set the input delete widget
			$subcategory_i18n_form_widget_schema['name'] = new sfWidgetFormInputDelete(array(
			'url' =&gt; 'category/deleteSubcategory',      // required
			'model_id' =&gt; $subcategory-&gt;getId(),        // required
			'confirm' =&gt; 'Sure???',                     // optional
			));

			// create a new subcategory form for the current subcategory model object
			$subcategory_form = new SubcategoryForm($subcategory);

			// embed the i18n form
			$subcategory_form-&gt;embedForm('subcategory_i18n'.$subcategory_i18n_object-&gt;getId(), $subcategory_i18n_form);

			// subcategory form widget schema
			$subcategory_form_widget_schema = $subcategory_form-&gt;getWidgetSchema();

			// disable label
			$subcategory_form_widget_schema['subcategory_i18n'.$subcategory_i18n_object-&gt;getId()]-&gt;setLabel(false);

			// embed the subcategory form in the main category form
			$this-&gt;embedForm('subcategory'.$subcategory-&gt;getId(), $subcategory_form);

			// set a custom label for the embedded form
			$this-&gt;widgetSchema['subcategory'.$subcategory-&gt;getId()]-&gt;setLabel('Subcategory: '.$subcategory-&gt;getName());

		}

		// create a new subcategory form for a new subcategory model object
		$subcategory_form = new SubcategoryForm();

		// create a new subcategory form for a new subcategory_i18n model object
		$subcategory_i18n_form = new SubcategoryI18nForm();

		// embed the subcategory_i18n form in the parent subcategory form
		$subcategory_form-&gt;embedForm('subcategory_i18n', $subcategory_i18n_form);

		// subcategory form widget schema
		$subcategory_form_widget_schema = $subcategory_form-&gt;getWidgetSchema();

		// disable label
		$subcategory_form_widget_schema['subcategory_i18n']-&gt;setLabel(false);

		// embed the subcategory form in the main category form
		$this-&gt;embedForm('subcategory', $subcategory_form);

		// set a custom label for the embedded form
		$this-&gt;widgetSchema['subcategory']-&gt;setLabel('New Subcategory');

	}
}
public function bind(array $taintedValues = null, array $taintedFiles = null) {

		if(!$this-&gt;isNew()) {

			$user_culture = sfContext::getInstance()-&gt;getUser()-&gt;getCulture();

			// remove the embedded new form if the name field was not provided
			if (is_null($taintedValues['subcategory']['subcategory_i18n']['name']) || strlen($taintedValues['subcategory']['subcategory_i18n']['name']) === 0 ) {

				unset($this-&gt;embeddedForms['subcategory'], $taintedValues['subcategory']);

				// pass the new form validations
				$this-&gt;validatorSchema['subcategory'] = new sfValidatorPass();

			} else {

				// set the category of the new subcategory form object
				$this-&gt;embeddedForms['subcategory']-&gt;getObject()-&gt;setCategory($this-&gt;getObject());

				// get subcategory embedded forms
				$subcategory_embedded_forms = $this-&gt;embeddedForms['subcategory']-&gt;getEmbeddedForms();

				// set subcategory parent of the subcategory_i18n model object
				$subcategory_embedded_forms['subcategory_i18n']-&gt;getObject()-&gt;setSubcategory($this-&gt;embeddedForms['subcategory']-&gt;getObject());

				// set the culture of the subcategory_i18n model object
				$subcategory_embedded_forms['subcategory_i18n']-&gt;getObject()-&gt;setCulture($user_culture);
			}

		}

		// call parent bind method
		parent::bind($taintedValues, $taintedFiles);

	}</pre>
<p>正如你所看到的，这是功能需要你复制和粘贴大量的代码，这就是为什么我在使用扩展的Admin Generator,  为了当你生成管理模块的时候有此功能可用。</p>
<ul class="related_post"><li><a href="http://www.foolbirds.com/csrf-and-form.html" title="CSRF使用注意事项和form的标准用法">CSRF使用注意事项和form的标准用法</a></li><li><a href="http://www.foolbirds.com/symfony-references-with-propel.html" title="symfony数据表关联详解(for propel)">symfony数据表关联详解(for propel)</a></li><li><a href="http://www.foolbirds.com/symfony-form-offsetunset.html" title="Symfony中自定义form中offsetUnset的应用">Symfony中自定义form中offsetUnset的应用</a></li><li><a href="http://www.foolbirds.com/use-form.html" title="form使用一例">form使用一例</a></li><li><a href="http://www.foolbirds.com/form-create-and-edit.html" title="Form表单的新建、修改">Form表单的新建、修改</a></li><li><a href="http://www.foolbirds.com/symfony-latlng-widget-with-google-maps.html" title="编写widget一例:支持Google Maps的坐标输入框">编写widget一例:支持Google Maps的坐标输入框</a></li><li><a href="http://www.foolbirds.com/default-values-for-form.html" title="如何给表单项赋初值">如何给表单项赋初值</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.foolbirds.com/how-to-embed-forms-in-symfony-12-admin-generator.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

