<?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>Ezzatron &#187; forms</title>
	<atom:link href="http://ezzatron.com/tag/forms/feed/" rel="self" type="application/rss+xml" />
	<link>http://ezzatron.com</link>
	<description>Bringing together the fine arts of programming and death metal.</description>
	<lastBuildDate>Sat, 07 Aug 2010 04:41:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Expanding forms with symfony 1.2 and Doctrine</title>
		<link>http://ezzatron.com/2009/12/03/expanding-forms-with-symfony-1-2-and-doctrine/</link>
		<comments>http://ezzatron.com/2009/12/03/expanding-forms-with-symfony-1-2-and-doctrine/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 04:19:32 +0000</pubDate>
		<dc:creator>Erin</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[band]]></category>
		<category><![CDATA[degradation]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[dynamic]]></category>
		<category><![CDATA[enhancement]]></category>
		<category><![CDATA[expanding]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[graceful]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[many]]></category>
		<category><![CDATA[member]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[one]]></category>
		<category><![CDATA[oriented]]></category>
		<category><![CDATA[progressive]]></category>
		<category><![CDATA[to]]></category>
		<category><![CDATA[validation]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://ezzatron.com/?p=177</guid>
		<description><![CDATA[I recently started learning how to use the forms system in symfony 1.2 and for the most part I was impressed with its simplicity and flexibility. Unfortunately I was thrown in the deep end somewhat when a project I was working on had a requirement for an &#8220;expanding&#8221; form &#8211; that is, one where a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.symfony-project.org/"><img class="alignnone" title="symfony" src="http://www.symfony-project.org/downloads/logos/symfony.gif" alt="" width="448" height="122" /></a></p>
<p>I recently started learning how to use the <a title="symfony Forms in Action" href="http://www.symfony-project.org/forms/1_2/en/">forms system</a> in <a title="symfony" href="http://www.symfony-project.org/">symfony</a> 1.2 and for the most part I was impressed with its simplicity and flexibility. Unfortunately I was thrown in the deep end somewhat when a project I was working on had a requirement for an &#8220;expanding&#8221; form &#8211; that is, one where a certain section of a form should be able to be repeated as many times as necessary to accommodate the user&#8217;s needs.</p>
<p>In the case of the project in question, the specific situation was an application form where the user could fill out any number of team members involved in their project. Each team member consisted of a name and a role, both free-form text fields. Team members were to be stored in the database, linked to the application in a one to many relationship.</p>
<p>Circumstances conspired that this must be achieved in a single form, so full of confidence in symfony&#8217;s design decisions regarding the forms system, a bit of light Googling revealed the answer &#8211; symfony&#8217;s <a title="Call the expert: Nested forms - A real implementation" href="http://www.symfony-project.org/blog/2008/11/10/call-the-expert-nested-forms-a-real-implementation">embedded forms</a> system. Great, so you just plonk in a few embedded forms and away you go, right? Wrong.</p>
<p>The good news is, I managed to find a solution that satisfied the requirements, <em>eventually</em>. The bad news is that it is not easy, elegant, or particularly reusable.</p>
<p>What follows is a loose guide to implementing such a system. Being a relative newcomer to symfony I cannot guarantee that this is the best way to do things, so tread with caution, and if you think of a better way to achieve the same outcome, please please let me know! Read on if you dare&#8230;<span id="more-177"></span></p>
<h2>Introduction</h2>
<p>I&#8217;m going to assume the following in this guide:</p>
<ul>
<li>You have a solid working knowledge of <a title="symfony" href="http://www.symfony-project.org/">symfony</a>, <a title="PHP: Hypertext Preprocessor" href="http://php.net/">PHP</a> and <a title="Doctrine - PHP Object Relational Mapper" href="http://www.doctrine-project.org/">Doctrine</a>.</li>
<li>You have a blank symfony 1.2 project, set up to use Doctrine rather than Propel (although I&#8217;m sure the same could be achieved with Propel with a bit of tweaking).</li>
<li>You have the symfony executable in your system path or in the root of your project.</li>
<li>You are using a relational database such as MySQL to store your data.</li>
<li>You have entered your database connection details into your <strong>config/databases.yml</strong> file and set up all the appropriate database permissions.</li>
<li>You have completed any web server setup as required to access the project.</li>
<li>You are aware that you need to clear the symfony cache (by running <code class="codecolorer text vibrant"><span class="text">symfony cc</span></code>) when new classes are created and when configuration changes are made.</li>
</ul>
<p>I&#8217;m also going to move fairly quickly as there is a lot to cover, so please feel free to ask for any clarification in the comments and I will update as necessary.</p>
<p>For help with installing and setting up symfony 1.2, check out <a title="Getting Started with symfony" href="http://www.symfony-project.org/getting-started/1_2/en/">Getting started with symfony</a>. I chose to use Doctrine 1.1 for this tutorial, however the version that comes with symfony should also be fine. For instructions on upgrading to Doctrine 1.1 see <a title="Using Doctrine 1.1 with Symfony 1.2" href="http://www.brandonturner.net/blog/2009/05/doctrine11-with-symfony12/">Using Doctrine 1.1 with Symfony 1.2</a>.</p>
<p>You can also see a live demo and get an idea of what we are trying to achieve by visiting <a href="http://expandingform.sf.ezzatron.com/">http://expandingform.sf.ezzatron.com/</a>.</p>
<h2>Step 1: Setting up</h2>
<p>Here is the Doctrine schema we will be using. I went for something a bit more cheery than the above situation, namely bands and band members:</p>
<div class="codecolorer-container text vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Band:<br />
&nbsp; columns:<br />
&nbsp; &nbsp; name:<br />
&nbsp; &nbsp; &nbsp; type: string(200)<br />
&nbsp; &nbsp; &nbsp; notnull: true<br />
&nbsp; &nbsp; &nbsp; notblank: true<br />
&nbsp; &nbsp; formed: date<br />
<br />
BandMember:<br />
&nbsp; columns:<br />
&nbsp; &nbsp; band_id:<br />
&nbsp; &nbsp; &nbsp; type: integer<br />
&nbsp; &nbsp; &nbsp; notnull: true<br />
&nbsp; &nbsp; name:<br />
&nbsp; &nbsp; &nbsp; type: string(200)<br />
&nbsp; &nbsp; &nbsp; notnull: true<br />
&nbsp; &nbsp; &nbsp; notblank: true<br />
&nbsp; &nbsp; role: string(200)<br />
&nbsp; relations:<br />
&nbsp; &nbsp; Band:<br />
&nbsp; &nbsp; &nbsp; foreignAlias: Members<br />
&nbsp; &nbsp; &nbsp; onUpdate: cascade<br />
&nbsp; &nbsp; &nbsp; onDelete: cascade</div></div>
<p>Place this in your <strong>config/doctrine/schema.yml</strong> file, and then create a data fixture so we have some test data to work with:</p>
<div class="codecolorer-container text vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Band:<br />
&nbsp; hnd:<br />
&nbsp; &nbsp; name: Hesitate &amp; Die<br />
&nbsp; &nbsp; formed: '2006-06-06'<br />
<br />
BandMember:<br />
&nbsp; andrew:<br />
&nbsp; &nbsp; name: Andrew<br />
&nbsp; &nbsp; role: Guitar<br />
&nbsp; &nbsp; Band: hnd<br />
&nbsp; erin:<br />
&nbsp; &nbsp; name: Erin<br />
&nbsp; &nbsp; role: Bass<br />
&nbsp; &nbsp; Band: hnd<br />
&nbsp; richie:<br />
&nbsp; &nbsp; name: Richie<br />
&nbsp; &nbsp; role: Vocals<br />
&nbsp; &nbsp; Band: hnd<br />
&nbsp; rowan:<br />
&nbsp; &nbsp; name: Rowan<br />
&nbsp; &nbsp; role: Drums<br />
&nbsp; &nbsp; Band: hnd</div></div>
<p>Place the above in <strong>data/fixtures/fixtures.yml</strong> and run:</p>
<div class="codecolorer-container text vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ symfony doctrine:build-all-reload --no-confirmation</div></div>
<p>This will generate all the model classes and forms we will need, create the database, and populate it with some test data for us. Next we need to create an application, and we&#8217;ll use the standard symfony app name &#8220;frontend&#8221;:</p>
<div class="codecolorer-container text vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ symfony generate:app --escaping-strategy=on --csrf-secret=randomstring frontend</div></div>
<p>Replacing &#8220;randomstring&#8221; with whatever you like. Now let&#8217;s generate a module from our model classes as a base to start from:</p>
<div class="codecolorer-container text vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ symfony doctrine:generate-module --non-verbose-templates frontend band Band</div></div>
<p>Now if you visit <strong>http://&lt;project url&gt;/frontend_dev.php/band/edit/id/1</strong> you should be presented with the following:</p>
<p><img class="alignnone size-full wp-image-190" title="Generated band form" src="http://ezzatron.com/wp-content/uploads/2009/12/end_step_1.png" alt="Generated band form" width="450" height="170" /></p>
<p>We now have a basic form for entering band details. Thus concludes step 1. Moving on to&#8230;</p>
<h2>Step 2: Building the form</h2>
<p>OK let&#8217;s dive right in. We are going to embed forms for editing band members inside of the band form itself. To add a single member form you would simply add:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'members'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> BandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>to our <strong>lib/form/doctrine/BandForm.class.php</strong>&#8216;s <strong>configure()</strong> method. But what we want is to structure the form in such a way that the form data, when posted to the update action, will contain an array of band members. The way to do so in the symfony forms system is to wrap the embedded forms in another form, then embed this wrapper form itself into the main form. Confused? Don&#8217;t worry, everything will become clearer once we actually create the forms.</p>
<p>Firstly, we need to make a small modification to the band member form to allow it to slot into our band form better. The generated form includes a field for the related band ID, which we will not need as all band members will relate to the band represented in the parent band form.</p>
<p>We could modify the <strong>BandMemberForm</strong> class itself, but it&#8217;s possible we may want to use the form outside of a band context, so let&#8217;s harness the power of the forms system and extend the form instead. Create a file at <strong>lib/form/doctrine/EmbeddedBandMemberForm.class.php</strong> with the following class definition (PHP opening tag excluded for brevity):</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> EmbeddedBandMemberForm <span style="color: #000000; font-weight: bold;">extends</span> BandMemberForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span><span style="color: #004000;">configure</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'band_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Next, let&#8217;s create the &#8220;container&#8221; form. Create a file at <strong>lib/form/doctrine/BandMembersForm.class.php</strong> containing the following class:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandMembersForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>This creates three blank forms for inputting band members. Now to actually embed the container form into our main band form, it&#8217;s actually very simple. Simply edit <strong>lib/form/doctrine/BandForm.class.php</strong> so that it looks like the following:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'members'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> BandMembersForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now when we reload our band form (did you remember to clear your cache?), we will see the following:</p>
<p><img class="alignnone size-full wp-image-195" title="Band form with 3 empty member forms" src="http://ezzatron.com/wp-content/uploads/2009/12/band_with_blank_members.png" alt="Band form with 3 empty member forms" width="450" height="348" /></p>
<p>Looks promising, and that wasn&#8217;t <em>too</em> painful so far, right?</p>
<p>There next obvious step would be displaying the existing band members. We want to be able to see and edit the existing band members and still have the option of inputting new members also. To do this we need to pass the <strong>Band</strong> object to our container form so that it can access the existing members. Let&#8217;s update the container form so that it looks like:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandMembersForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$band</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>Band <span style="color: #000088;">$band</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">band</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$band</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">band</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Members</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$member</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$member</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$i</span> <span style="color: #339933;">++;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$j</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$i</span><span style="color: #339933;">;</span> <span style="color: #000088;">$j</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">;</span> <span style="color: #000088;">$j</span> <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$j</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now we have to change the main form so that we pass the Band object when we instantiate the container form:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'members'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> BandMembersForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Reloading the form should now show the existing members:</p>
<p><img class="alignnone size-full wp-image-198" title="Band form with existing members" src="http://ezzatron.com/wp-content/uploads/2009/12/band_with_existing_members.png" alt="Band form with existing members" width="450" height="581" /></p>
<p>So now we have a form that can display the band with all of its members and still provide room for new ones. Time for the next step.</p>
<h2>Step 3: Getting the form to save</h2>
<p>Try saving the form without making any changes to the data. You should get validation errors because the band member name is a required field:</p>
<p><img class="alignnone size-full wp-image-202" title="Member names incorrectly required" src="http://ezzatron.com/wp-content/uploads/2009/12/member_name_required.png" alt="Member names incorrectly required" width="433" height="379" /></p>
<p>This won&#8217;t do at all because we want to be able to leave a band member blank and have the system ignore it. We also want to be able to delete an existing member by clearing their name and role. So let&#8217;s remove the requirement for now, and we&#8217;ll add it back in later. Edit your <strong>EmbeddedBandMemberForm</strong> class so that it looks like this:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> EmbeddedBandMemberForm <span style="color: #000000; font-weight: bold;">extends</span> BandMemberForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span><span style="color: #004000;">configure</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'band_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setOption</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now when we try to save the form again, we get an exception thrown:</p>
<p><img class="alignnone size-full wp-image-249" title="Database constraint violated" src="http://ezzatron.com/wp-content/uploads/2009/12/constraint_violated.png" alt="Database constraint violated" width="433" height="262" /></p>
<p>As you can see, Doctrine is not happy with us, but why? The answer is that symfony is trying to create new band members from the blank band member forms, but it has no idea which band the new members should belong to. We&#8217;ll deal with this issue shortly, but in the meantime let&#8217;s start by making symfony ignore any band member forms which are left blank.</p>
<p>Firstly, how do we decide if a band member form is &#8220;blank&#8221;? Let&#8217;s write a couple of custom methods in our form classes. Some of this functionality is reusable, so we&#8217;ll place the main body of the code in <strong>lib/form/doctrine/BaseFormDoctrine.class.php</strong> which is the base class for all of our generated forms:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">abstract <span style="color: #000000; font-weight: bold;">class</span> BaseFormDoctrine <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> _formValuesAreBlank<span style="color: #009900;">&#40;</span><a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #000088;">$fieldNames</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$fieldNames</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$fieldName</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fieldName</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #339933;">!</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">formValueIsBlank</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$fieldName</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> formValueIsBlank<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$subValue</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">formValueIsBlank</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$subValue</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$value</span> ? <span style="color: #009900; font-weight: bold;">false</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>These two methods essentially traverse an array recursively looking for any non-blank values, and returns false as soon as one is found. The method needs to be recursive because some fields like dates are passed as an array. Now we can write a simple method in our <strong>EmbeddedBandMemberForm</strong> class to check whether the fields that constitute a band member have been filled out:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> EmbeddedBandMemberForm <span style="color: #000000; font-weight: bold;">extends</span> BandMemberForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> formValuesAreBlank<span style="color: #009900;">&#40;</span><a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$fieldNames</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/array_diff"><span style="color: #990000;">array_diff</span></a><span style="color: #009900;">&#40;</span>Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BandMember'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getFieldNames</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'band_id'</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span>_formValuesAreBlank<span style="color: #009900;">&#40;</span><span style="color: #000088;">$fieldNames</span><span style="color: #339933;">,</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>We are simply grabbing the field names directly from our model class, and excluding the ones we don&#8217;t care about. This is more robust that explicitly specifying <em>name</em> and <em>role</em> as the important fields, as it allows for further fields to be added to the band member form as requirements change.</p>
<p>Now we need to actually change the way the form is processed by overriding some methods in our main band form:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> updateObjectEmbeddedForms<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span> instanceof EmbeddedBandMemberForm<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$formValues</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>EmbeddedBandMemberForm<span style="color: #339933;">::</span><span style="color: #004000;">formValuesAreBlank</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$formValues</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">updateObjectEmbeddedForms</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> saveEmbeddedForms<span style="color: #009900;">&#40;</span><span style="color: #000088;">$con</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span> instanceof EmbeddedBandMemberForm<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isModified</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">saveEmbeddedForms</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$con</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>These methods doubtless require some explanation. Firstly let&#8217;s look at <strong>updateObjectEmbeddedForms()</strong>. This method uses the custom method we wrote to check whether the band members passed to the form for processing are blank. If a blank band member is encountered, the related form is removed from the forms array to prevent symfony from attempting to update the related band member object.</p>
<p>The next method, <strong>saveEmbeddedForms()</strong> works in tandem with the above. It runs through each of the forms and checks whether the related object has been modified. If an unmodified object is encountered, the related form is once again removed from the forms array to prevent symfony from attempting to save an unmodified object.</p>
<p>OK so now we should be able to save our form without any validation warnings or exceptions cropping up. If you can&#8217;t, it&#8217;s probably time to double check everything, and perhaps clear your cache. On to the next step&#8230;</p>
<h2>Step 4: Adding and deleting members</h2>
<p>Our form now saves without errors, but what does it actually <em>do</em>? Not much at the moment. Let&#8217;s try adding another band member. Ladies and gentlemen, may I present Steven on second guitar!:</p>
<p><img class="alignnone size-full wp-image-210" title="Attempting to add a member" src="http://ezzatron.com/wp-content/uploads/2009/12/adding_a_member_fail.png" alt="Attempting to add a member" width="433" height="301" /></p>
<p>What happens when we save the form? Ah, it seems we have the same issue we encountered before:</p>
<p><img class="alignnone size-full wp-image-249" title="Database constraint violated" src="http://ezzatron.com/wp-content/uploads/2009/12/constraint_violated.png" alt="Database constraint violated" width="433" height="262" /></p>
<p>As we found out in the previous step, this is caused by symfony not knowing to link our new band member to the band we are editing. We can fix this by making a simple change to our <strong>BandForm</strong> class, in the <strong>saveEmbeddedForms()</strong> method:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> saveEmbeddedForms<span style="color: #009900;">&#40;</span><span style="color: #000088;">$con</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span> instanceof EmbeddedBandMemberForm<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isModified</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Band</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">saveEmbeddedForms</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$con</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now when we try again, the new member is saved correctly and appears in the list of band members as expected:</p>
<p><img class="alignnone size-full wp-image-212" title="New member successfully saved" src="http://ezzatron.com/wp-content/uploads/2009/12/new_member_saved.png" alt="New member successfully saved" width="450" height="638" /></p>
<p>Awesome! We now have 2 guitarists and all the glory that comes with duelling guitar solos. But wait; oh no! Steven has decided to get married and move to Norway! Well, it&#8217;s time to remove him from the band I guess, so let&#8217;s try setting his name and role to blank and see what happens when we save&#8230;</p>
<p>Oh dear, it seems Steven is not keen on leaving without a fight. He still appears in the list of band members. So what&#8217;s happening here? In short, we simply haven&#8217;t told Doctrine to dispose of the unwanted band member yet! Let&#8217;s go ahead and do that now by modifying the <strong>BandForm</strong> class&#8217; <strong>updateObjectEmbeddedForms()</strong> method:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> updateObjectEmbeddedForms<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span> instanceof EmbeddedBandMemberForm<span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$formValues</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>EmbeddedBandMemberForm<span style="color: #339933;">::</span><span style="color: #004000;">formValuesAreBlank</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$formValues</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">unlink</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Members'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$id</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$forms</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">updateObjectEmbeddedForms</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #339933;">,</span> <span style="color: #000088;">$forms</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Now we can try again to delete Steven, and it seems to have worked:</p>
<p><img class="alignnone size-full wp-image-224" title="Member successfully deleted" src="http://ezzatron.com/wp-content/uploads/2009/12/member_delete_success.png" alt="Member successfully deleted" width="450" height="580" /></p>
<p>So now we have a fully functional form, which is great! But there are some important things we still need to consider, which leads us to the next step&#8230;</p>
<h2>Step 5: Validation</h2>
<p>That&#8217;s right, you forgot, didn&#8217;t you? Back in step 3 we disabled important validation for the band member form, which means, for example, if you try to enter a band member with a role but no name, you get this nasty validation exception:</p>
<p><img class="alignnone size-full wp-image-225" title="Validation error when saving a band member with only a role" src="http://ezzatron.com/wp-content/uploads/2009/12/validation_error.png" alt="Validation error when saving a band member with only a role" width="433" height="219" /></p>
<p><strong>NOTE:</strong> You may find that you do not encounter this exception, there seems to be a bug somewhere where the &#8220;notblank&#8221; validator we specified in the schema is being ignored. Nevertheless, we still need to prevent blank names from being entered.</p>
<p>We can&#8217;t leave things as they stand, so let&#8217;s create a custom wrapper for the validator schema that we can use to validate band members that have not been left blank. Create a file at <strong>lib/validator/EmbeddedBandMemberValidatorSchema.class.php</strong> and enter this class definition:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> EmbeddedBandMemberValidatorSchema <span style="color: #000000; font-weight: bold;">extends</span> sfValidatorSchema<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$validatorSchema</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfValidatorSchema <span style="color: #000088;">$validatorSchema</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$validatorSchema</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> doClean<span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>EmbeddedBandMemberForm<span style="color: #339933;">::</span><span style="color: #004000;">formValuesAreBlank</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">doClean</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> <span style="color: #000088;">$values</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>All this class does is check whether the passed values are considered &#8220;blank&#8221; before applying the existing validation rules. This increases robustness by allowing us to keep all of the validation rules defined in the <strong>BandMemberForm</strong> class, and freeing us from having to duplicate their logic in the <strong>EmbeddedBandMemberForm</strong> class.</p>
<p>Now it&#8217;s simply a matter of making a small change to the <strong>EmbeddedBandMemberForm</strong> class&#8217; <strong>configure()</strong> method to allow us to take advantage of our new wrapper class:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> EmbeddedBandMemberForm <span style="color: #000000; font-weight: bold;">extends</span> BandMemberForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span><span style="color: #004000;">configure</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <a href="http://www.php.net/unset"><span style="color: #990000;">unset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'band_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberValidatorSchema<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">validatorSchema</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>With those changes made, we can try again to save a band member with only a role and this time we are presented with the appropriate form errors:</p>
<p><img class="alignnone size-full wp-image-226" title="Form validation working correctly" src="http://ezzatron.com/wp-content/uploads/2009/12/form_errors_working.png" alt="Form validation working correctly" width="433" height="236" /></p>
<p>OK, that&#8217;s validation taken care of, let&#8217;s make some usability improvements.</p>
<h2>Step 6: Usability</h2>
<p>We&#8217;re going to add extra functionality to our form for users with JavaScript support, namely the ability to add additional spaces for band members without the need to save the form. What&#8217;s more we&#8217;re going to do it without preventing non-JavaScript enabled users from using the form. This is known as <em>progressive enhancement</em> and is generally considered a best-practice in web development.</p>
<p>The first thing we need to do is set up an action to render the additional band member forms so that we can fetch them via an AJAX call. Open up your <strong>apps/frontend/modules/band/actions/actions.class.php</strong> file and add the following method:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> bandActions <span style="color: #000000; font-weight: bold;">extends</span> sfActions<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeMemberForm<span style="color: #009900;">&#40;</span>sfWebRequest <span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">forward404Unless</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isXmlHttpRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$count</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'count'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BandForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNumMembers</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$count</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">member</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'members'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$count</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLayout</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>The template for this action is very simple. Create a file at <strong>apps/frontend/modules/band/templates/memberFormSuccess.php</strong> with the following contents:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$sf_data</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRaw</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'member'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderRow</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p>You may have noticed the call to <strong>BandForm::setNumMembers()</strong> in the above action. We still need to add this method, so let&#8217;s do that now. Edit your <strong>BandForm</strong> class and add the following method definition:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setNumMembers<span style="color: #009900;">&#40;</span><span style="color: #000088;">$numMembers</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'members'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> BandMembersForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">object</span><span style="color: #339933;">,</span> <span style="color: #000088;">$numMembers</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>This in turn means a change to the <strong>BandMembersForm</strong> class, which should be edited to look like this:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandMembersForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$band</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$count</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>Band <span style="color: #000088;">$band</span><span style="color: #339933;">,</span> <span style="color: #000088;">$count</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">band</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$band</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$count</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">band</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">Members</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$member</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$member</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$i</span> <span style="color: #339933;">++;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000088;">$count</span> <span style="color: #339933;">=</span> <a href="http://www.php.net/max"><span style="color: #990000;">max</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">count</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$j</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$i</span><span style="color: #339933;">;</span> <span style="color: #000088;">$j</span> <span style="color: #339933;">&lt;</span> <span style="color: #000088;">$count</span><span style="color: #339933;">;</span> <span style="color: #000088;">$j</span> <span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedForm</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$j</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> EmbeddedBandMemberForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>What the above changes do are allow us to insert extra blank band members as we please. We then use this to recreate the &#8220;extra&#8221; band member form exactly as it would appear if it were rendered as part of the whole form.</p>
<p>All that is left to do is create the AJAX handler and some unobtrusive JavaScript to fetch and insert the new member form. Open <strong>apps/frontend/modules/band/templates/_form.php</strong> and update the contents to the following:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">&lt;?php</span> use_helper<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Javascript'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> include_stylesheets_for_form<span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> include_javascripts_for_form<span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
<br />
&lt;form action=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'band/'</span><span style="color: #339933;">.</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isNew</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #0000ff;">'create'</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">'update'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isNew</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #0000ff;">'?id='</span><span style="color: #339933;">.</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #0000ff;">''</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot; method=&quot;post&quot; <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isMultipart</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> and <span style="color: #b1b100;">print</span> <span style="color: #0000ff;">'enctype=&quot;multipart/form-data&quot; '</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&gt;<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isNew</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&lt;input type=&quot;hidden&quot; name=&quot;sf_method&quot; value=&quot;put&quot; /&gt;<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; &lt;table id=&quot;band&quot;&gt;<br />
&nbsp; &nbsp; &lt;tfoot&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;tr&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &lt;td colspan=&quot;2&quot;&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;noscript&gt;&lt;p&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;strong&gt;NOTE:&lt;/strong&gt; To add more members, please save this form, and more spaces will be presented.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/p&gt;&lt;/noscript&gt;<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp;nbsp;&lt;a href=&quot;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'band/index'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;Cancel&lt;/a&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isNew</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp;nbsp;<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> link_to<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Delete'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'band/delete?id='</span><span style="color: #339933;">.</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getObject</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'method'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'delete'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'confirm'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Are you sure?'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endif</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;input type=&quot;submit&quot; value=&quot;Save&quot; /&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &lt;/td&gt;<br />
&nbsp; &nbsp; &nbsp; &lt;/tr&gt;<br />
&nbsp; &nbsp; &lt;/tfoot&gt;<br />
&nbsp; &nbsp; &lt;tbody&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$form</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; &nbsp; &lt;/tbody&gt;<br />
&nbsp; &lt;/table&gt;<br />
&lt;/form&gt;<br />
<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> javascript_tag<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span><br />
&nbsp; $$('#band table').each(function(e)<br />
&nbsp; {<br />
&nbsp; &nbsp; if (e.select('table').length)<br />
&nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; e.select('tbody')[0].id = 'band_members';<br />
<br />
&nbsp; &nbsp; &nbsp; e.insert('<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">echo</span> escape_javascript<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &lt;tfoot&gt;&lt;tr&gt;&lt;td colspan=<span style="color: #000099; font-weight: bold;">\&quot;</span>2<span style="color: #000099; font-weight: bold;">\&quot;</span>&gt;&quot;</span><span style="color: #339933;">.</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; button_to_remote<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Add member'</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a><span style="color: #009900;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'url'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'band/memberForm'</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'with'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;'count='+$$('#band_members table').length&quot;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'update'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'band_members'</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'position'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'bottom'</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/tfoot&gt;<br />
&nbsp; &nbsp; &nbsp; &quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>');<br />
&nbsp; &nbsp; }<br />
&nbsp; });<br />
<span style="color: #000000; font-weight: bold;">&lt;?php</span> end_javascript_tag<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></div></div>
<p>It&#8217;s important to note that this code is somewhat ugly because I wanted to avoid manually changing the form&#8217;s layout. In a production situation you could implement a much more elegant solution by customising the form layout or writing a custom form renderer.</p>
<p>This point aside, your form should now look like the image below when JavaScript is enabled (when JavaScript is disabled a message will be displayed informing the user of how to add additional members):</p>
<p><img class="alignnone size-full wp-image-242" title="Form with add member button added" src="http://ezzatron.com/wp-content/uploads/2009/12/form_with_ajax.png" alt="Form with add member button added" width="433" height="608" /></p>
<p>We&#8217;re now able to add additional slots for new members dynamically using the &#8220;Add member&#8221; button. We&#8217;re facing one last hurdle unfortunately; when we add a new member slot and hit the save button we&#8217;re presented with a form error:</p>
<p><img class="alignnone size-full wp-image-245" title="Validation error when adding members dynamically" src="http://ezzatron.com/wp-content/uploads/2009/12/dynamic_validation_error.png" alt="Validation error when adding members dynamically" width="433" height="165" /></p>
<p>Thankfully this is fairly easy to remedy. The issue is that when the update action handles the posted data, it creates a fresh instance of <strong>BandForm</strong> which has no knowledge of our &#8220;extra&#8221; band member form. To fix this we can override the <strong>BandForm</strong> class&#8217; <strong>bind()</strong> method to detect the number of band members passed and expand the form as needed:</p>
<div class="codecolorer-container php vibrant" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><div class="php codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000000; font-weight: bold;">class</span> BandForm <span style="color: #000000; font-weight: bold;">extends</span> BaseBandForm<br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// ...</span><br />
<br />
&nbsp; <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> bind<span style="color: #009900;">&#40;</span><a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #000088;">$taintedValues</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <a href="http://www.php.net/array"><span style="color: #990000;">array</span></a> <span style="color: #000088;">$taintedFiles</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><br />
&nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><a href="http://www.php.net/isset"><span style="color: #990000;">isset</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'members'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <a href="http://www.php.net/is_array"><span style="color: #990000;">is_array</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'members'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNumMembers</span><span style="color: #009900;">&#40;</span><a href="http://www.php.net/count"><span style="color: #990000;">count</span></a><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'members'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">bind</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #339933;">,</span> <span style="color: #000088;">$taintedFiles</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>And hey presto, our form now works perfectly!</p>
<h2>Conclusion</h2>
<p>If you got this far I&#8217;m sure you&#8217;ll agree that this was not by any means an easy exercise. The symfony forms system <em>is </em>powerful and flexible, but it seems like perhaps this type of situation was not really brought into consideration when it was designed. I would love to see the symfony architects consider ways that the implementation of expanding forms could be simplified, or at least better documented.</p>
<p>Once again if you have any suggestions on how to improve this implementation I&#8217;d really love to hear them. I&#8217;m sure there are aspects of the symfony forms system that I don&#8217;t understand fully which could make this whole exercise somewhat simpler, and that would certainly be valuable knowledge.</p>
<p>If you are interested, there is a guide to implementing a similar system <a title="How to Embed AJAX(!) Forms in Symfony 1.2 Admin Generator" href="http://israelwebdev.wordpress.com/2009/05/04/how-to-embed-ajax-forms-in-symfony-12-admin-generator/">here</a>, however it seems to deal with the symfony admin generator specifically, and it also seems to have the disadvantage that the parent object must exist before child objects can be added.</p>
<p>Good luck with your own implementations, let me know how they go!</p>
<h2>Source code</h2>
<ul>
<li><a href="http://expandingform.sf.ezzatron.com/source/_form.phps">_form.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/actions.class.phps">actions.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/BandForm.class.phps">BandForm.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/BandMembersForm.class.phps">BandMembersForm.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/BaseFormDoctrine.class.phps">BaseFormDoctrine.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/EmbeddedBandMemberForm.class.phps">EmbeddedBandMemberForm.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/EmbeddedBandMemberValidatorSchema.class.phps">EmbeddedBandMemberValidatorSchema.class.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/fixtures.yml">fixtures.yml</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/memberFormSuccess.phps">memberFormSuccess.php</a></li>
<li><a href="http://expandingform.sf.ezzatron.com/source/schema.yml">schema.yml</a></li>
</ul>
<script type="text/javascript">
  addthis_url    = 'http%3A%2F%2Fezzatron.com%2F2009%2F12%2F03%2Fexpanding-forms-with-symfony-1-2-and-doctrine%2F';
  addthis_title  = 'Expanding+forms+with+symfony+1.2+and+Doctrine';
  addthis_pub    = 'ezzatron';
</script><script type="text/javascript" src="http://s7.addthis.com/js/addthis_widget.php?v=12" ></script>
]]></content:encoded>
			<wfw:commentRss>http://ezzatron.com/2009/12/03/expanding-forms-with-symfony-1-2-and-doctrine/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
	</channel>
</rss>
