<?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>blog.barros.ws &#187; form</title>
	<atom:link href="http://blog.barros.ws/tag/form/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.barros.ws</link>
	<description>web development tips</description>
	<lastBuildDate>Sun, 06 Jun 2010 00:34:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using embedFormForEach in Symfony, Part II</title>
		<link>http://blog.barros.ws/2009/01/01/using-embedformforeach-in-symfony-part-ii/</link>
		<comments>http://blog.barros.ws/2009/01/01/using-embedformforeach-in-symfony-part-ii/#comments</comments>
		<pubDate>Thu, 01 Jan 2009 21:58:18 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[embedForm]]></category>
		<category><![CDATA[embedFormForEach]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=106</guid>
		<description><![CDATA[In my last post I talked about  embedFormForEach method, that will embed a form inside another N times, and in the end of that article, I promised a new post on this subject to show how to use it to dynamically add/remove/sort cars, and here it is.  As usual, I put live an [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://blog.barros.ws/2008/12/01/using-embedformforeach-in-symfon/">last post</a> I talked about  embedFormForEach method, that will embed a form inside another N times, and in the end of that article, I promised a new post on this subject to show how to use it to dynamically add/remove/sort cars, and here it is.  As usual, I put live an <a href="http://blog.barros.ws/symfony/citypicker">example here</a> (I integrated this new form on the old <a href="http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/">city picker form</a>). In this example, when you create (or edit) an user, you will see a new control called Cars, and a green plus icon. If you click that icon, it will add a new &#8220;car form&#8221; into the user form. You can add as many cars as you want. Each new form has a set of controls that can be used to sort and remove cars from the form. Let&#8217;s take a look on how it all works.</p>
<p><span id="more-106"></span></p>
<p>Before we start, as this example is integrated into previous city picker system, I recommend that you <a href="http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/">read it before</a>, and also the <a href="http://blog.barros.ws/2008/12/01/using-embedformforeach-in-symfon/">previous article on embedFormForEach</a>.</p>
<p>Ok, let&#8217;s start with database model:</p>
<p>config/schema.yml:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code"><pre class="txt" style="font-family:monospace;">  cp_users:
    _attributes:     { phpName: User, idMethod: native }
    id:              ~
    name:            { type: varchar(100), required: true }
    country_id:      { type: integer, required: true, foreignTable: cp_countries, foreignReference: id }
    state_id:        { type: integer, required: true, foreignTable: cp_states, foreignReference: id }
    city_id:         { type: integer, required: true, foreignTable: cp_cities, foreignReference: id }
    cars:            { type: longvarchar }
    created_at:      ~
    updated_at:      ~</pre></td></tr></table></div>

<p>Only thing I added here was at line 8, a new column where we&#8217;ll store cars information. Notice that it&#8217;s a single column of <em>longvarchar</em> type, and we&#8217;ll save car information as a <a href="http://br2.php.net/manual/en/function.serialize.php">serialized</a> array. As we&#8217;re going to store car information as a serialized array, we need to overwrite <em>getCars</em> and <em>setCars</em> methods to make it do the conversion for us:</p>
<p>lib/model/User.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setCars<span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span><span style="color: #339933;">,</span><span style="color: #000088;">$raw</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$raw</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$cars</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_values</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		parent<span style="color: #339933;">::</span><span style="color: #004000;">setCars</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">serialize</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getCars<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">return</span> <span style="color: #339933;">@</span><span style="color: #990000;">unserialize</span><span style="color: #009900;">&#40;</span>parent<span style="color: #339933;">::</span><span style="color: #004000;">getCars</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: #009900;">&#125;</span>
&nbsp;
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getNumberOfCars<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$cars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCars</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000088;">$ncars</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
		<span style="color: #009900;">&#123;</span>
			<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$k</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$v</span><span style="color: #009900;">&#41;</span>
				<span style="color: #000088;">$ncars</span> <span style="color: #339933;">=</span> <span style="color: #990000;">max</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ncars</span><span style="color: #339933;">,</span><span style="color: #990000;">intval</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$k</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #b1b100;">return</span> <span style="color: #000088;">$ncars</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p><em>setCars</em> will receive an array as parameter and serialize it, and <em>getCars</em> will do the opposite, get a string from database and unserialize it  into an array. Notice that <em>setCars</em> expects another parameter, called $raw. If this value is false (default), it will <b>rebuild</b> the array keys, to ensure a sequential value. But as you will see later on, there will be one place that it&#8217;s <b>not</b> desired, so we need to instruct <em>setCars</em> to <b>not</b> rebuild keys, passing $raw = true. <em>getNumberOfCars</em>, as the name suggests, returns the number of cars the object has. You might wonder why didn&#8217;t I just use <em>return count($this->getCars())</em> for this&#8230; This method won&#8217;t return the actual number of cars, but the highest <b>key + 1</b> in the array, and the reason for this will be explained later on.</p>
<p>To receive input from the user, we&#8217;re gonna use the CarForm we created in previous article. Notice that it&#8217;s <b>exactly</b> the same form:</p>
<p>lib/form/CarForm.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> CarForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm
<span style="color: #009900;">&#123;</span>
	<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>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setWidgets</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'make'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ferrari'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Ferrari'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'bmw'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'BMW'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'porsche'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Porsche'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValidators</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'make'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorChoice<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #339933;">,</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ferrari'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'bmw'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'porsche'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Please enter model'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabels</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'make'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Make:'</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Model:'</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNameFormat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'%s'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<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>
	<span style="color: #009900;">&#125;</span>	
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Again, if you look into previous example, you&#8217;ll find another form called CarsForm (plural), that was responsible to get the number of cars user wanted to input. This form <b>won&#8217;t</b> be used in this new example, rather, we&#8217;ll embed CarForm inside CPUserForm:</p>
<p>lib/form/CPUserForm.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> CPUserForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormPropel
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$ncars</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&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><span style="color: #000088;">$object</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$options</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$CSRFSecret</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$object</span><span style="color: #339933;">,</span><span style="color: #000088;">$options</span><span style="color: #339933;">,</span><span style="color: #000088;">$CSRFSecret</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// calculate number of cars</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getNumberOfCars</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// embed cars form</span>
  	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #000088;">$cars_form</span>  <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedFormForEach</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars'</span><span style="color: #339933;">,</span><span style="color: #000088;">$cars_form</span><span style="color: #339933;">,</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'%content%'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'%content%'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  		<span style="color: #666666; font-style: italic;">// set default</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setDefault</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars'</span><span style="color: #339933;">,</span><span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCars</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: #009900;">&#125;</span>
  	<span style="color: #b1b100;">else</span> <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;">&quot;cars&quot;</span><span style="color: #339933;">,</span><span style="color: #000000; font-weight: bold;">new</span> sfForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;<span style="color: #009933; font-weight: bold;">%c</span>ontent%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  	
  <span style="color: #009900;">&#125;</span>
&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>
  <span style="color: #009900;">&#123;</span>
  	<span style="color: #666666; font-style: italic;">// build state criteria</span>
  	<span style="color: #000088;">$stateC</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$stateC</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span>StatePeer<span style="color: #339933;">::</span><span style="color: #004000;">COUNTRY_ID</span><span style="color: #339933;">,</span><span style="color: #000088;">$this</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;">getCountryId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// build city criteria</span>
   	<span style="color: #000088;">$cityC</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Criteria<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$cityC</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span>CityPeer<span style="color: #339933;">::</span><span style="color: #004000;">STATE_ID</span><span style="color: #339933;">,</span><span style="color: #000088;">$this</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;">getStateId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setWidgets</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'name'</span>   			<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'country_id'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormPropelSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Country'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'-- Country --'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'order_by'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Name'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'asc'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'state_id'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormPropelSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'State'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'-- State/Province --'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'order_by'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Name'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'asc'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'criteria'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$stateC</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'city_id'</span>			<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormPropelSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'model'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'City'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'add_empty'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'-- City --'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'order_by'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Name'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'asc'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'criteria'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$cityC</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'id'</span>				<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputHidden<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValidators</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    	<span style="color: #0000ff;">'name'</span>			<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span>
    							<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'trim'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'required'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'required'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Please enter name'</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span>
    					<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    	<span style="color: #0000ff;">'country_id'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPropelChoice<span style="color: #009900;">&#40;</span>
    							<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Country'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'column'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'required'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Please choose country'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'invalid'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Invalid country'</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span>
    					<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    	<span style="color: #0000ff;">'state_id'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPropelChoice<span style="color: #009900;">&#40;</span>
    							<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'State'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'column'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'criteria'</span>	<span style="color: #339933;">=&gt;</span> clone <span style="color: #000088;">$stateC</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'required'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Please choose state'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'invalid'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Invalid state'</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span>
    					<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    	<span style="color: #0000ff;">'city_id'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPropelChoice<span style="color: #009900;">&#40;</span>
    							<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'model'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'City'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'column'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'id'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'criteria'</span>	<span style="color: #339933;">=&gt;</span> clone <span style="color: #000088;">$cityC</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    								<span style="color: #0000ff;">'required'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Please choose city'</span><span style="color: #339933;">,</span>
    								<span style="color: #0000ff;">'invalid'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'- Invalid city'</span><span style="color: #339933;">,</span>
    							<span style="color: #009900;">&#41;</span>
    					<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    	<span style="color: #0000ff;">'id'</span>			<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorNumber<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>false<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabels</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
		<span style="color: #0000ff;">'name'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Name'</span><span style="color: #339933;">,</span>
	<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNameFormat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user[%s]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<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>
  <span style="color: #009900;">&#125;</span>
&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><span style="color: #990000;">array</span> <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> <span style="color: #990000;">array</span> <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>
  <span style="color: #009900;">&#123;</span>
  	<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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #339933;">;</span><span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  		<span style="color: #009900;">&#123;</span>
  			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><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;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #009900;">&#125;</span>
  	<span style="color: #009900;">&#125;</span>
&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>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getModelName<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	<span style="color: #b1b100;">return</span> <span style="color: #0000ff;">'User'</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This form is the same we used in the city picker article, with some new things added in order to handle car form. In fact, <em>configure</em> method is <b>exactly</b> the same. Only <em>__constructor</em> and <em>bind</em> methods were added. Let&#8217;s talk about each method:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$ncars</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span>
&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><span style="color: #000088;">$object</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #000088;">$options</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$CSRFSecret</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$object</span><span style="color: #339933;">,</span><span style="color: #000088;">$options</span><span style="color: #339933;">,</span><span style="color: #000088;">$CSRFSecret</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// calculate number of cars</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getNumberOfCars</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// embed cars form</span>
  	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #000088;">$cars_form</span>  <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedFormForEach</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars'</span><span style="color: #339933;">,</span><span style="color: #000088;">$cars_form</span><span style="color: #339933;">,</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'%content%'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'%content%'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  		<span style="color: #666666; font-style: italic;">// set default</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setDefault</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars'</span><span style="color: #339933;">,</span><span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCars</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: #009900;">&#125;</span>
  	<span style="color: #b1b100;">else</span> <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;">&quot;cars&quot;</span><span style="color: #339933;">,</span><span style="color: #000000; font-weight: bold;">new</span> sfForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;<span style="color: #009933; font-weight: bold;">%c</span>ontent%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>  	
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>__constructor is where we actually embed the CarForm into CPUserForm. As we&#8217;ll use <em>embedFormForEach</em>, we need to know, beforehand, the number of times we&#8217;ll embed the form. To determine this number, we use the <em>getNumberOfCars</em> method, and also, we store resulting value in a private variable <em>ncars</em>, that will be used inside <em>bind</em> method. If any car was defined, we embed CarForm <em>$ncars</em> times, and then set default values, otherwise, we just embed a generic <em>sForm</em> form.</p>
<p>As I talked before, <em>getNumberOfCars</em> is a bit different and the reason is not hard to explain. Every time you use the green plus icon to add a new car form, it will add a new user[cars][N] element, where N is a sequential number, starting from 0. Suppose you add 4 car forms, and then you remove the third one. You would end up with: user[cars][0], user[cars][1], users[cars][3]. You see the gap? We don&#8217;t have [2] anymore. In this case, if <em>getNumberOfCars</em> returns 3 (the actuall number of cars), CPUserForm would embed only three CarForm, and user[cars][3] would become invalid, as it would be the forth form. That&#8217;s the reason we must return the highest key (plus 1), in ths case, 4. And now is where <em>bind</em> method takes place:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">  <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><span style="color: #990000;">array</span> <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> <span style="color: #990000;">array</span> <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>
  <span style="color: #009900;">&#123;</span>
  	<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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">ncars</span><span style="color: #339933;">;</span><span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  		<span style="color: #009900;">&#123;</span>
  			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><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;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #009900;">&#125;</span>
  	<span style="color: #009900;">&#125;</span>
&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>
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Still using the same scenario (added 4 cars, then removed the third). As I said, we&#8217;ll still need to embed four forms in order to make it work, but you might think: in CarForm, make and model are required, wouldn&#8217;t it throw an error?? The answer is YES. We embed 4 forms, but supply data only for 3, so it will throw an validation error. To avoid this, we need to implement a <a href="http://blog.barros.ws/2008/11/05/conditional-validator-in-symfony-another-approach/">conditional validation</a>.  Remember on constructor we saved the variable ncars? We&#8217;ll use it here to remove <em>removed</em> (uh?) cars. For this, we traverse through cars values, and if we don&#8217;t find it, we unset both widget and validator for that index. Doing this, the form won&#8217;t try to validate a removed field, and also, will remove the widget from the form, preventing it from appear again.</p>
<p>Ok, what about the actions?</p>
<p>apps/frontend/modules/citypicker/actions/actions.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeEdit<span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</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;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> UserPeer<span style="color: #339933;">::</span><span style="color: #004000;">retrieveByPK</span><span style="color: #009900;">&#40;</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;">&quot;id&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #b1b100;">else</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<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;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errors</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isMethod</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #666666; font-style: italic;">// pre-populate country, state and city in order to filter select boxes</span>
  		<span style="color: #000088;">$data</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;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCountryId</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'country_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStateId</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'state_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCityId</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'city_id'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  		<span style="color: #666666; font-style: italic;">// check validity</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCity</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCity</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStateId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStateId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCityId</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getState</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getState</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCountryId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCountryId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setStateId</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCountry</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCountryId</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  		<span style="color: #666666; font-style: italic;">// pre-populate cars so we can get number of cars entered</span>
  		<span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setCars</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'cars'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CPUserForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bind</span><span style="color: #009900;">&#40;</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;">'user'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</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;">'refresh'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #0000ff;">&quot;Y&quot;</span><span style="color: #009900;">&#41;</span>
  		<span style="color: #009900;">&#123;</span>
  			<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isValid</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  			<span style="color: #009900;">&#123;</span>
  				<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  				<span style="color: #666666; font-style: italic;">// if we are handling a Soap request, do NOT redirect</span>
  				<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isSoapRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">redirect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker/index'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  			<span style="color: #009900;">&#125;</span>
&nbsp;
		  	<span style="color: #666666; font-style: italic;">// get errors into array</span>
		  	<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;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getFormFieldSchema</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getError</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span>
		  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errors</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$e</span><span style="color: #339933;">;</span>
  		<span style="color: #009900;">&#125;</span>
  		<span style="color: #b1b100;">else</span>
  		<span style="color: #009900;">&#123;</span>
  			<span style="color: #666666; font-style: italic;">// render city/state/country</span>
  			<span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderPartial</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'address_edit'</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #009900;">&#125;</span>
  	<span style="color: #009900;">&#125;</span>
  	<span style="color: #b1b100;">else</span> 
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CPUserForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>Again, most code on this action is to handle city picker and was detailed in <a href="http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/">another article</a>. <b>Only</b> thing that&#8217;s related to CarForm is at line 22. Remember we use <em>getNumberOfCars</em> on CPUserForm constructor? So, we need to pre-populate user object we&#8217;ll send to the form with received car information, so it can determine beforehand the number of forms it need to embed. Also, we set $raw=true when calling setCars method, in order to <strong>preserve keys</strong>, or we&#8217;ll break the system.</p>
<p>Now only thing that&#8217;s missing is the template, where we&#8217;ll add all the javascripts needed to make it work.</p>
<p>apps/frontend/modules/citypicker/templates/editSuccess.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">&lt;form method=&quot;post&quot; action=&quot;<span style="color: #000000; font-weight: bold;">&lt;?=</span>url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker/edit?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> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot;&gt;
  <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;id&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
  &lt;table&gt;
  	<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: #000088;">$errors</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    &lt;tr&gt;
    	&lt;td colspan=&quot;2&quot;&gt;
    		&lt;ul&gt;
    			<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$errors</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$error</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
					&lt;li&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$error</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/li&gt;
				<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endforeach</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    		&lt;/ul&gt;
    	&lt;/td&gt;
    &lt;/tr&gt;
	<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>
    &lt;tr&gt;
      &lt;th&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderLabel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/th&gt;
      &lt;td&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;name&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;th&gt;Address&lt;/th&gt;
      &lt;td&gt;
        &lt;div id=&quot;address&quot;&gt;
        	<span style="color: #000000; font-weight: bold;">&lt;?=</span>include_partial<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'address_edit'</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;/div&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
    	&lt;th&gt;
    		Cars
    		&lt;a href=&quot;#&quot; title=&quot;Add new car&quot; onclick=&quot;new Ajax.Updater('fieldset_cars', '<span style="color: #000000; font-weight: bold;">&lt;?=</span>url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker/addCar'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>', {parameters: {number: ncars}, asynchronous:true, evalScripts:false, insertion:Insertion.Bottom, onSuccess:function(request, json){ncars++;}});; return false;&quot;&gt;
    			<span style="color: #000000; font-weight: bold;">&lt;?=</span>image_tag<span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_admin_web_dir'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/images/add.png'</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'alt'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Add new car'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'border'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'0'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    		&lt;/a&gt;
    	&lt;/th&gt;
    	&lt;td id=&quot;fieldset_cars&quot;&gt;
    		<span style="color: #000000; font-weight: bold;">&lt;?</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getWidget</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setFormFormatterName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'options'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
   			<span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
    	&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td colspan=&quot;2&quot;&gt;
        &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;save&quot;/&gt;
        <span style="color: #000000; font-weight: bold;">&lt;?=</span>button_to<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cancel'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'citypicker/index'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/form&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
	var	ncars = <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getWidget</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getWidget</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getFields</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>;
&lt;/script&gt;</pre></td></tr></table></div>

<p>Ok, you just need to pay attention on code from line 27 on, everything above it is to handle citypicker (once again)&#8230;. In this template, we place the gren plus icon and attach a JavaScript event to it. This JavaScript will request an action using AJAX and will append the result in the fieldset_cars container (the action will result in HTML code). Notice that I didn&#8217;t use symfony helper to build this ajax call. The reason is that we need to send to the action current number of cars we have in the form, so it can return correct HTML code (field index), and I didn&#8217;t find any means to make it work with the helper, so I wrote the Ajax.Updater by myself. It will request the <em>addCar</em> action, and send value stored in <em>ncars</em> variable as a parameter, and then will increment it on success (so we keep track of how many cars we have). <em>ncars</em> is initialized at line 48, retrieving the number of embedded forms.<br />
Another important detail is at line 35. Here we change the <em>FormatterName</em> for CarForm (I could have set it inside CarForm configure method, but this would break previous example). This new formatter will add sort/remove controls to the form:</p>
<p>lib/widget/sfWidgetFormSchemaFormatterOptions.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> sfWidgetFormSchemaFormatterOptions <span style="color: #000000; font-weight: bold;">extends</span> sfWidgetFormSchemaFormatter
<span style="color: #009900;">&#123;</span>
	protected <span style="color: #000088;">$rowFormat</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">;</span>
&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>sfWidgetFormSchema <span style="color: #000088;">$widgetSchema</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">rowFormat</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot; 
	&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;
			Car
		    &lt;a title=&quot;</span>Move up<span style="color: #0000ff;">&quot; href=&quot;</span><span style="color: #666666; font-style: italic;">#&quot; onclick=&quot;if($(this).up('table').previous('table')) $(this).up('table').previous('table').insert({before: $(this).up('table')}); return false&quot;&gt;&quot;.image_tag('sf_admin/uparrow.png',array('border'=&gt;0,'alt'=&gt;'Move up')).&quot;
</span>		    <span style="color: #339933;">&lt;</span>a title<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Move down&quot;</span> href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;#&quot;</span> onclick<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;if($(this).up('table').next('table')) $(this).up('table').next('table').insert({after: $(this).up('table')}); return false&quot;</span><span style="color: #339933;">&gt;</span><span style="color: #0000ff;">&quot;.image_tag('sf_admin/downarrow.png',array('border'=&gt;0,'alt'=&gt;'Move down')).&quot;</span>
			<span style="color: #339933;">&lt;</span>a title<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;'Remove this option&quot;</span> href<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;#&quot;</span> onclick<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;if(window.confirm('Are you sure you want to remove this option?')) $(this.parentNode.parentNode.parentNode).remove(); return false;&quot;</span><span style="color: #339933;">&gt;</span><span style="color: #0000ff;">&quot;.image_tag(sfConfig::get('sf_admin_web_dir').'/images/delete.png',array('border'=&gt;0,'alt'=&gt;'Remove this option')).&quot;</span><span style="color: #339933;">&lt;/</span>a<span style="color: #339933;">&gt;</span>
		<span style="color: #339933;">&lt;/</span>th<span style="color: #339933;">&gt;</span>
	<span style="color: #339933;">&lt;/</span>tr<span style="color: #339933;">&gt;</span>
	<span style="color: #339933;">%</span>field<span style="color: #339933;">%</span>
	<span style="color: #339933;">&lt;/</span>table<span style="color: #339933;">&gt;</span><span style="color: #0000ff;">&quot;;
&nbsp;
		parent::__construct(<span style="color: #006699; font-weight: bold;">$widgetSchema</span>);
	}
}</span></pre></td></tr></table></div>

<p>This formatter is a little bit different from normal formatters. Usually we only define a few variables inside the class, but we can&#8217;t do this here (well, we can, but we would need to write the &lt;img&gt;s by hand). The reason I defined the variable inside class __constructor is because I&#8217;m using image_tag helper to build the string, and we can&#8217;t to this when defining a variable in a class. Other than that, it&#8217;s a normal formatter, that wraps the form into a set of controls. Remember in <em>setCars</em> method, we <b>rebuild</b> array keys? The reason is explained here.. If you look at the javascript that sort the form, it simply swap the &lt;table&gt; elements, but field indexes will be kept the same. For instance, we have two cars added: user[cars][0] and user[cars][1]. If we swap it, we&#8217;ll have: user[cars][1] and user[cars][0]. Also, we can have gaps on the keys, so we need to rebuild the keys.</p>
<p>Ok, the last step now is the addCar action, that&#8217;s responsible to add a new form into the CPUserForm when u click the green plus icon:</p>
<p>apps/frontend/modules/citypicker/actions/actions.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeAddCar<span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	<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>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// get next number</span>
  	<span style="color: #000088;">$number</span> <span style="color: #339933;">=</span> <span style="color: #990000;">intval</span><span style="color: #009900;">&#40;</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;">&quot;number&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// build widget</span>
  	<span style="color: #000088;">$form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$widgetSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSchemaDecorator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSchema<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  		<span style="color: #0000ff;">'user[cars]['</span><span style="color: #339933;">.</span><span style="color: #000088;">$number</span><span style="color: #339933;">.</span><span style="color: #0000ff;">']'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSchemaDecorator<span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getWidgetSchema</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;<span style="color: #009933; font-weight: bold;">%c</span>ontent%&quot;</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</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: #0000ff;">&quot;<span style="color: #009933; font-weight: bold;">%c</span>ontent%&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setFormFormatterName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'options'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$widgetSchema</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>At line 6 we get the number of cars we already have, in order to build the next field index. Then, we need to build the form object that will be rendered by the template and sent back. One important point is: we need to build this widget as so the fields name is prefixed by: user[cars][$number]. For this, we wrap CarForm into a sfWidgetFormSchemaDecorator. Also, we need to set FormatterName to add the controls to the new form. Finally, we render it in the template:</p>
<p>apps/frontend/modules/citypicker/templates/addCarSuccess.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>And that&#8217;s it, our new form is ready to work. For this example I didn&#8217;t put attention to the design, but you can make it look nicer but changing the <em>options</em> formatter, and by using other formatter for the forms than the table one I&#8217;m using.</p>
<p>I&#8217;m not sure If I explained very well all the details of this implementation, so if you have any doubts, or comments, feel free to drop me a line on the comments section.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2009/01/01/using-embedformforeach-in-symfony-part-ii/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>Using embedFormForEach in Symfony</title>
		<link>http://blog.barros.ws/2008/12/01/using-embedformforeach-in-symfon/</link>
		<comments>http://blog.barros.ws/2008/12/01/using-embedformforeach-in-symfon/#comments</comments>
		<pubDate>Mon, 01 Dec 2008 23:07:14 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[embedForm]]></category>
		<category><![CDATA[embedFormForEach]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=92</guid>
		<description><![CDATA[The new Form sub-framework, introduced in Symfony 1.1, is really great, and the more I work with it, the more I like it. One of the nicest feature of form sub-framework is the ability to embed a form inside another one, using the embedForm method. Also, symfony provides another method, called embedFormForEach that will embed [...]]]></description>
			<content:encoded><![CDATA[<p>The new Form sub-framework, introduced in Symfony 1.1, is really great, and the more I work with it, the more I like it. One of the nicest feature of form sub-framework is the ability to embed a form inside another one, using the embedForm method. Also, symfony provides another method, called embedFormForEach that will embed a form inside another one N times. At first glance this method doesn&#8217;t seem to be very useful, but I found it really useful in a project I worked a few weeks ago. Consider the following scenario: you want a form to ask users to input information about all cars they have (make and model). In this form you have a select box (this can be an input box too, but I&#8217;m using a select box in this example) where users specify how many cars they have and then it will show X fields where users can input cars model and make (X = number of cars user selected), using ajax to load fields. You can see an <a href="http://blog.barros.ws/symfony/cars" target="_blank">example here</a>.  </p>
<p><span id="more-92"></span></p>
<p>For this example, we will need two forms: one containing the number of cars, and another one containing car details (that will be embedded into first one).</p>
<p>lib/CarsForm.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> CarsForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm
<span style="color: #009900;">&#123;</span>
    <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><span style="color: #000088;">$defaults</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$options</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$CSRFSecret</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>   
        parent<span style="color: #339933;">::</span>__construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$defaults</span><span style="color: #339933;">,</span><span style="color: #000088;">$options</span><span style="color: #339933;">,</span><span style="color: #000088;">$CSRFSecret</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">embedFormForEach</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars'</span><span style="color: #339933;">,</span><span style="color: #000000; font-weight: bold;">new</span> CarForm<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$defaults</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'cars_count'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>?<span style="color: #000088;">$defaults</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'cars_count'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">:</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>   
&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>
    <span style="color: #009900;">&#123;</span>   
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setWidgets</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'cars_count'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">5</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValidators</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'cars_count'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorChoice<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">2</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">4</span><span style="color: #339933;">,</span><span style="color: #cc66cc;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabels</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'cars_count'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Number of Cars'</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNameFormat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars[%s]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<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>
    <span style="color: #009900;">&#125;</span>   
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This is the main form, where we ask for number of cars and where we will embed details form. All the trick is done in the form constructor, specifically in line 7. <em>embedFormForEach</em> expect three parameters:</p>
<ul>
<li>name</li>
<li>form to embed</li>
<li>number of times to embed</li>
</ul>
<p>Our form expect to receive the number of cars in <em>$defaults</em> array, that stores default values of fields in the form, but before assigning it, we check if the number is within our list of allowed value. Note that list of values is hardcoded into the form. I just did it for the sake of simplicity, but I recommend creating a static method somewhere that will return these values. Ok, if our test succeed, we use received value and create requested number of <em>CarForm</em> form, otherwise we just create one (default).</p>
<p>lib/CarForm.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> CarForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm
<span style="color: #009900;">&#123;</span>
    <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>
    <span style="color: #009900;">&#123;</span>   
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setWidgets</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'make'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ferrari'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Ferrari'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'bmw'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'BMW'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'porsche'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Porsche'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'model'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValidators</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'make'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorChoice<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ferrari'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'bmw'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'porsche'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'model'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Please enter model'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabels</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'make'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Make:'</span><span style="color: #339933;">,</span>   
            <span style="color: #0000ff;">'model'</span>        <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Model:'</span><span style="color: #339933;">,</span> 
        <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>     
&nbsp;
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNameFormat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'%s'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<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>
    <span style="color: #009900;">&#125;</span>   
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This is the form with car details, called CarForm. This is a simple for, with nothing special, but there&#8217;s just one detail. At line 20, we set NameFormat to &#8220;%s&#8221;. Again, allowed values are hardcoded in the form, this should be avoided in real applications.</p>
<p>Ok, now that we already have the forms, we need to create the action and templates to handle the forms. </p>
<p>apps/frontend/modules/cars/actions/actions.class.php:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"> <span style="color: #009933; font-style: italic;">/**
  * Executes index action
  *
  * @param sfRequest $request A request object
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeIndex<span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	<span style="color: #666666; font-style: italic;">// prepare form</span>
  	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isMethod</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'post'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  	<span style="color: #009900;">&#123;</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarsForm<span style="color: #009900;">&#40;</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;">'cars'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">bind</span><span style="color: #009900;">&#40;</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;">'cars'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isValid</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
  		<span style="color: #009900;">&#123;</span>
  			<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">cars</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getValue</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  			<span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setTemplate</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'result'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  		<span style="color: #009900;">&#125;</span>
  	<span style="color: #009900;">&#125;</span>
  	<span style="color: #b1b100;">else</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarsForm<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars_count'</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>This looks like a common action that handles form submission, but with one little change: we have to send default values to form constructor. If we are handling a GET request, we just set it to 1 (line 19), as we want just 1 form to be displayed at the beginning, but if we are handling a POST, we send entire form values to constructor (line 11), as our constructor will need to know beforehand how many cars are being submitted.<br />
In the template, we will add a small piece of JavaScript to update the form, using AJAX, based on the number of cars the user selected:</p>
<p>apps/frontend/modules/cars/templates/indexSuccess.php</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;form name=&quot;cars_frm&quot; action=&quot;<span style="color: #000000; font-weight: bold;">&lt;?=</span>url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars/index'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&quot; method=&quot;post&quot;&gt;
  &lt;table&gt;
    <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars_count&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderRow</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'onchange'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">&quot;new Ajax.Updater(&quot;</span>cars_table<span style="color: #0000ff;">&quot;, '&quot;</span><span style="color: #339933;">.</span>url_for<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars/refresh'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;', { parameters: { cars_count: <span style="color: #006699; font-weight: bold;">$F</span>('cars_cars_count') } } )&quot;</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>
    &lt;tr&gt;        
      &lt;td&gt;              
        &lt;table id=&quot;cars_table&quot;&gt; 
          <span style="color: #000000; font-weight: bold;">&lt;?php</span> include_partial<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'car_form'</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'form'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
        &lt;/table&gt;                
      &lt;/td&gt;             
    &lt;/tr&gt;       
  &lt;/table&gt;
  &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;Submit&quot; /&gt;&lt;/p&gt;
&lt;/form&gt;</pre></div></div>

<p>apps/frontend/modules/cars/templates/_car_form.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;cars&quot;</span><span style="color: #009900;">&#93;</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></pre></div></div>

<p>In template, I added an listener to the <em>onchange</em> event of number of cars select box that will send a request to the <em>refresh</em> action, sending selected number of cars as parameter, and finally update cars_table container  (all using prototype library). <em>refresh</em> action will receive the number of cars, instantiate the form, sending the number to the constructor, and then render _car_form partial.</p>
<p>apps/frontend/modules/actions/actions.class.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #009933; font-style: italic;">/**
  * Update cars form
  *
  * @param sfWebRequest $request Web request object
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeRefresh<span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CarsForm<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'cars_count'</span><span style="color: #339933;">=&gt;</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;">'cars_count'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">renderPartial</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'car_form'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>That&#8217;s it, the form is complete. After you validate it, getField(&#8216;cars&#8217;) will return an associative array containing cars details submitted by the user. In this example I just write it back to the user, but you can do anything you want with this data, like <a href="http://br2.php.net/manual/en/function.serialize.php" target="_blank">serializing</a> and then saving into DB.</p>
<p>apps/frontend/moduled/cars/templates/resultSuccess.php</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;p&gt;Selected cars:&lt;/p&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$cars</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$car</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
	&lt;p&gt;&lt;b&gt;Make:&lt;/b&gt; <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$car</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;make&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;br/&gt;&lt;b&gt;Model:&lt;/b&gt; <span style="color: #000000; font-weight: bold;">&lt;?=</span><span style="color: #000088;">$car</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;model&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/p&gt;
<span style="color: #000000; font-weight: bold;">&lt;?php</span> <span style="color: #b1b100;">endforeach</span><span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Well, this example is a very simple one, but I think it&#8217;s a good start to understand how <em>embedFormForEach</em> can be used in your Symfony applications. Say, what if you want to remove the number of cars select box and rather have controls to dynamically add, delete and even sort car details?? Yes, that&#8217;s possible too, but I&#8217;ll leave this for a next article, that I should write as soon as I have some free time, for now I&#8217;ll leave this idea as an challenge <img src='http://blog.barros.ws/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2008/12/01/using-embedformforeach-in-symfon/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Conditional validator in Symfony, another approach</title>
		<link>http://blog.barros.ws/2008/11/05/conditional-validator-in-symfony-another-approach/</link>
		<comments>http://blog.barros.ws/2008/11/05/conditional-validator-in-symfony-another-approach/#comments</comments>
		<pubDate>Wed, 05 Nov 2008 12:10:27 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[conditional validator]]></category>
		<category><![CDATA[form]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=53</guid>
		<description><![CDATA[Today morning I was reading the Symfony blog, more specifically A week of symfony #96 and then I came across a tutorial talking about conditional validators.This is very usefull, I find myself using this technique very often, so I decided to write about another techinique I use sometimes to implement a conditional validation, but for [...]]]></description>
			<content:encoded><![CDATA[<p>Today morning I was reading the Symfony blog, more specifically <a title="A week of symfony #96" href="http://www.symfony-project.org/blog/2008/11/02/a-week-of-symfony-96-27-october-2-november-2008" target="_blank">A week of symfony #96</a> and then I came across a <a title="How to implement a conditional validator?" href="http://www.symfony-project.org/cookbook/1_2/en/conditional-validator" target="_blank">tutorial talking about conditional validators</a>.This is very usefull, I find myself using this technique very often, so I decided to write about another techinique I use sometimes to implement a conditional validation, but for a different scenario. Imagine the following: you have a contact form where the users specify how they want to be contacted, email or phone, throught a select box. Then you have two input boxes where the users can enter both email and phone. If the user opts to be contacted via email, email field becomes mandatory and phone number optional, and the opposite happens if the user opts to be contacted via phone. So, how to implement such a form in symfony? </p>
<p><span id="more-53"></span><br />
A normal form would look like this:</p>
<p>lib/form/ContactForm.class.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> ContactForm <span style="color: #000000; font-weight: bold;">extends</span> sfForm
<span style="color: #009900;">&#123;</span>
  <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>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setWidgets</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'method'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormSelect<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'phone'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Phone'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Email'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'phone'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'msg'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormTextarea<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValidators</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'method'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorChoice<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'choices'</span><span style="color: #339933;">=&gt;</span>array<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'phone'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
			<span style="color: #0000ff;">'invalid'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Invalid email address'</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'phone'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Please enter your phone number'</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'msg'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span>true<span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="color: #0000ff;">'required'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'Please enter your message'</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setLabels</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
	<span style="color: #0000ff;">'email'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Email:'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'phone'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Phone:'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'method'</span>	<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Contact type:'</span><span style="color: #339933;">,</span>
	<span style="color: #0000ff;">'msg'</span>		<span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Message:'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">widgetSchema</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setNameFormat</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'contact[%s]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">errorSchema</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<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>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>The problem with this form is the fact that both phone and email are ALWAYS mandatory, regardless of the value of method. So, what we need is a way to intercept method&#8217;s value and update validators. So, what we need is intercept the <em><strong>bind</strong></em> method in order to check method&#8217;s value:</p>
<p>lib/form/ContactForm.class.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <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><span style="color: #990000;">array</span> <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> <span style="color: #990000;">array</span> <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>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">@</span><span style="color: #000088;">$taintedValues</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;method&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'phone'</span><span style="color: #009900;">&#41;</span> <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;">&quot;email&quot;</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>
    <span style="color: #b1b100;">else</span> <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;">&quot;phone&quot;</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>
&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>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>As can be seen, we create our own bind method, overriding parent one, and before calling the actual bind method, we inspect the values sent by the user and if <em>method</em> is <em>phone</em>, we remove the required option from <em>email</em> validator, otherwise we remove the required option from <em>phone</em> validator and finally call parent method.</p>
<p>The resulting form <a title="Conditional Validator" href="http://blog.barros.ws/symfony/contact" target="_blank">can be seen here</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2008/11/05/conditional-validator-in-symfony-another-approach/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>
