<?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</title>
	<atom:link href="http://blog.barros.ws/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.barros.ws</link>
	<description>web development tips</description>
	<lastBuildDate>Fri, 06 Mar 2009 12:33:59 +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>Convert lat, lng and zoom values to pixel (x,y) on a map</title>
		<link>http://blog.barros.ws/2009/03/06/convert-lat-lng-and-zoom-values-to-pixel-xy-on-a-map/</link>
		<comments>http://blog.barros.ws/2009/03/06/convert-lat-lng-and-zoom-values-to-pixel-xy-on-a-map/#comments</comments>
		<pubDate>Fri, 06 Mar 2009 12:33:14 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[perl]]></category>
		<category><![CDATA[gmap]]></category>
		<category><![CDATA[mercator]]></category>
		<category><![CDATA[projection]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=156</guid>
		<description><![CDATA[Working on a project this week, that involves Google Maps, I needed to, given a latitude, a longitude and a zoom level, calculate the pixel position (x,y) within the map. If you need to do this using javascript, it&#8217;s pretty easy, as GMap API provides a handy method to do this:

var pixel = map.getCurrentMapType&#40;&#41;.getProjection&#40;&#41;.fromLatLngToPixel&#40;new GLatLng&#40;10,20&#41;,map.getZoom&#40;&#41;&#41;;

Unfortunately, [...]]]></description>
			<content:encoded><![CDATA[<p>Working on a project this week, that involves Google Maps, I needed to, given a latitude, a longitude and a zoom level, calculate the pixel position (x,y) within the map. If you need to do this using javascript, it&#8217;s pretty easy, as GMap API provides a handy method to do this:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> pixel <span style="color: #339933;">=</span> map.<span style="color: #660066;">getCurrentMapType</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getProjection</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">fromLatLngToPixel</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> GLatLng<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">10</span><span style="color: #339933;">,</span><span style="color: #CC0000;">20</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>map.<span style="color: #660066;">getZoom</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Unfortunately, my need was to convert lat, lng and zoom into pixel position from PHP. I &#8220;googled&#8221; about this subject for a while, and it&#8217;s incredible how frequent this need is, and how this information lacks. I saw a lot of people asking for similar things, and also some people that claim that got it working, but without providing any code for this. Googling a bit more I figured out that google uses one thing called <a href="http://en.wikipedia.org/wiki/Mercator_projection" target="_blank">Mercator Projection</a>, but even this being a standard, I didn&#8217;t find anything that does what I needed. After a lot of time searching about this, I finally stumbled upon a perl script with a set of methods that accomplishes the task. Actually, this perl script is more focused on working with map &#8220;tiles&#8221;, but there are two methods that does exactly what I needed. It was just a matter of converting these perl methods into php and we&#8217;re done. </p>
<p><span id="more-156"></span></p>
<p>Here&#8217;s the &#8220;magic&#8221; perl script:</p>

<div class="wp_syntax"><div class="code"><pre class="perl" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Calculate tile characteristics given a bounding box of coordinates and a zoom...</span>
<span style="color: #666666; font-style: italic;"># Author. John D. Coryat 01/2008...</span>
<span style="color: #666666; font-style: italic;"># USNaviguide LLC.</span>
<span style="color: #666666; font-style: italic;"># Published under Apache 2.0 license.</span>
<span style="color: #666666; font-style: italic;"># Adapted from: Google Maps API Javascript...</span>
<span style="color: #666666; font-style: italic;">##</span>
<span style="color: #666666; font-style: italic;"># In order to correctly locate objects of interest on a Custom Map Overlay Google Maps, </span>
<span style="color: #666666; font-style: italic;"># the characteristics of each tile to build are required.</span>
<span style="color: #666666; font-style: italic;">##</span>
<span style="color: #666666; font-style: italic;"># Google_Tiles					# Calculate all tiles for a bounding box and zoom</span>
<span style="color: #666666; font-style: italic;"># Google_Tile_Factors				# Calculate the factors needed ( Zoom, Tilesize )</span>
<span style="color: #666666; font-style: italic;"># Google_Tile_Calc				# Calculate a single tile features from a tile name and zoom</span>
<span style="color: #666666; font-style: italic;"># Google_Tile_to_Pix				# Calculate tile name to pixel</span>
<span style="color: #666666; font-style: italic;"># Google_Coord_to_Pix				# Calculate coordinate to Pixel</span>
<span style="color: #666666; font-style: italic;"># Google_Pix_to_Tile				# Calculate a tile name from a pixel location and zoom</span>
&nbsp;
<span style="color: #000066;">require</span> <span style="color: #cc66cc;">5.003</span> <span style="color: #339933;">;</span>
<span style="color: #000066;">package</span> USNaviguide_Google_Tiles <span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> strict <span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> Math<span style="color: #339933;">::</span><span style="color: #006600;">Trig</span> <span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">BEGIN</span> <span style="color: #009900;">&#123;</span>
 <span style="color: #000000; font-weight: bold;">use</span> Exporter <span style="color: #339933;">;</span>
 <span style="color: #000000; font-weight: bold;">use</span> vars <span style="color: #000066;">qw</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$VERSION</span> <span style="color: #0000ff;">@ISA</span> <span style="color: #0000ff;">@EXPORT</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$VERSION</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">1.0</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">@ISA</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">qw</span> <span style="color: #009900;">&#40;</span> Exporter <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">@EXPORT</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">qw</span> <span style="color: #009900;">&#40;</span> 
 Google_Tiles
 Google_Tile_Factors
 Google_Tile_Calc
 Google_Tile_to_Pix
 Google_Coord_to_Pix
 Google_Pix_to_Tile
 <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;">#</span>
<span style="color: #666666; font-style: italic;"># Call as: &lt;array of Hashes&gt; = &amp;Google_Tiles(&lt;LatitudeS&gt;, &lt;LongitudeW&gt;, &lt;LatitudeN&gt;, &lt;LongitudeE&gt;, &lt;Zoom&gt;, [&lt;option: tileSize&gt;], [&lt;option: Partial/Whole&gt;]) ;</span>
<span style="color: #666666; font-style: italic;"># Partial/Whole option: (Default: Partial)</span>
<span style="color: #666666; font-style: italic;">#	Partial: Include the edge to create partial tiles</span>
<span style="color: #666666; font-style: italic;">#       Whole: Include only tiles that are contained by the bounds</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;">#          Returned Array Specifications:</span>
<span style="color: #666666; font-style: italic;">#            Each element is a reference to a Hash:</span>
<span style="color: #666666; font-style: italic;">#              NAMEY - Tile Name y</span>
<span style="color: #666666; font-style: italic;">#              NAMEX - Tile Name x</span>
<span style="color: #666666; font-style: italic;">#              PYS - Pixel South</span>
<span style="color: #666666; font-style: italic;">#              PXW - Pixel West</span>
<span style="color: #666666; font-style: italic;">#              PYN - Pixel North</span>
<span style="color: #666666; font-style: italic;">#              PXE - Pixel East</span>
<span style="color: #666666; font-style: italic;">#              LATS - South Latitude</span>
<span style="color: #666666; font-style: italic;">#              LNGW - West Longitude</span>
<span style="color: #666666; font-style: italic;">#              LATN - North Latitude</span>
<span style="color: #666666; font-style: italic;">#              LNGE - East Longitude</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;">#          Note: X is width, Y is height...</span>
<span style="color: #666666; font-style: italic;">#</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Tiles
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$latS</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lngW</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$latN</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lngE</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$zoom</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tileSize</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$parwho</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$ty</span>		<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tx</span>		<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@ret</span>	<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%first</span>	<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;"># First Results Hash</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%last</span>	<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;"># Last Results Hash</span>
&nbsp;
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;Google_Tile_Factors</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$zoom</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tileSize</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;"># Calculate Tile Factors</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000066;">defined</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$parwho</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">or</span> <span style="color: #339933;">!</span><span style="color: #0000ff;">$parwho</span><span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$parwho</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">'Partial'</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># NW: Convert Coordinates to Pixels...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NORTH'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'WEST'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;Google_Coord_to_Pix</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$latN</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$lngW</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Pixels to Tile Name...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;PixtoTileName</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NORTH'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'WEST'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'N'</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'W'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$parwho</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># SE: Convert Coordinates to Pixels...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'SOUTH'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'EAST'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;Google_Coord_to_Pix</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$latS</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$lngE</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Pixels to Tile Name...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;PixtoTileName</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'SOUTH'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'EAST'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'S'</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'E'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$parwho</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Calculate tile values for all tiles...</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span>			<span style="color: #666666; font-style: italic;"># Across the date line</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$ty</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$ty</span> <span style="color: #339933;">&lt;=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">++</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: #0000ff;">$tx</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span> <span style="color: #339933;">&lt;=</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">push</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@ret</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&amp;Google_Tile_Calc</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tx</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
   <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$tx</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span> <span style="color: #339933;">&lt;=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">push</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@ret</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&amp;Google_Tile_Calc</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tx</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</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: #009900;">&#125;</span> <span style="color: #b1b100;">else</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$ty</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$ty</span> <span style="color: #339933;">&lt;=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">++</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: #0000ff;">$tx</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span> <span style="color: #339933;">&lt;=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span> <span style="color: #0000ff;">$tx</span><span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span>
   <span style="color: #009900;">&#123;</span>
    <span style="color: #000066;">push</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@ret</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&amp;Google_Tile_Calc</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tx</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</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: #009900;">&#125;</span>
&nbsp;
 <span style="color: #0000ff;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NORTH'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NORTH'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'WEST'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$first</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'WEST'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$#ret</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'SOUTH'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'SOUTH'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$#ret</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'EAST'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$last</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'EAST'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000066;">return</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">@ret</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;"># Calculate Tile Factors...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Tile_Factors
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$zoom</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tileSize</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%value</span>	<span style="color: #339933;">=</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;"># Validate and correct input parameters...</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000066;">defined</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$zoom</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">or</span> <span style="color: #0000ff;">$zoom</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$zoom</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000066;">defined</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$tileSize</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">or</span> <span style="color: #339933;">!</span><span style="color: #0000ff;">$tileSize</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$tileSize</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">256</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Calculate Values...</span>
&nbsp;
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'zoom'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #0000ff;">$zoom</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PI'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">3.1415926536</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bc'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PI'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'Wa'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PI'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">180</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'cp'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span> <span style="color: #339933;">**</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'zoom'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">8</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span> <span style="color: #339933;">**</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'zoom'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span> <span style="color: #339933;">;</span>		<span style="color: #666666; font-style: italic;"># Maximum Tile Number</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngDeg'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">=</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'cp'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">360</span><span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngRad'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">=</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'cp'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">/</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bc'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bmO'</span><span style="color: #009900;">&#125;</span>	<span style="color: #339933;">=</span> <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'cp'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">/</span> <span style="color: #cc66cc;">2</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'tileSize'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$tileSize</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000066;">return</span> <span style="color: #0000ff;">\%value</span> <span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Calculate tile values from Name...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Tile_Calc
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%result</span>	<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Tile Name to Pixels...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PYN'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PXW'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;Google_Tile_to_Pix</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEY'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'NAMEX'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Pixels to Coordinates (Upper Left Corner)...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'LATN'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'LNGW'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;PixtoCoordinate</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PYN'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PXW'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PYS'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PYN'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">255</span> <span style="color: #339933;">;</span>
 <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PXE'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PXW'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">255</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Pixels to Coordinates (Lower Right Corner)...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'LATS'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'LNGE'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;PixtoCoordinate</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PYS'</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$result</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PXE'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000066;">return</span> <span style="color: #0000ff;">%result</span> <span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Calculate a tile name from a pixel location and zoom...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Pix_to_Tile
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$ty</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$tx</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Convert Pixels to Tile Name...</span>
&nbsp;
 <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$tx</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&amp;PixtoTileName</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$tx</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'N'</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'W'</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">'Partial'</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000066;">return</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$ty</span><span style="color: #339933;">,</span><span style="color: #0000ff;">$tx</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;"># Translate a coordinate to a pixel location...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Coord_to_Pix
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lat</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$lng</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@d</span>		<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span> 
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$e</span>		<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.0f&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bmO'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">$lng</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngDeg'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$e</span> <span style="color: #339933;">=</span> <span style="color: #000066;">sin</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$lat</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'Wa'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$e</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0.99999</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$e</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0.99999</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$e</span> <span style="color: #339933;">&lt;</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">0.99999</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$e</span> <span style="color: #339933;">=</span> <span style="color: #339933;">-</span><span style="color: #cc66cc;">0.99999</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #0000ff;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.0f&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bmO'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">+</span> <span style="color: #cc66cc;">0.5</span> <span style="color: #339933;">*</span> <span style="color: #000066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">$e</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span> <span style="color: #339933;">-</span> <span style="color: #0000ff;">$e</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngRad'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #000066;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">@d</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;"># Translate a pixel location to a tile name...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> PixtoTileName
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$y</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$x</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$yd</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;"># Y Direction: N or S</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$xd</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;"># X Direction: W or E</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$parwho</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;"># Partial / Whole</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$yn</span>		<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>					<span style="color: #666666; font-style: italic;"># Y Name</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$xn</span>		<span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>					<span style="color: #666666; font-style: italic;"># X Name</span>
&nbsp;
 <span style="color: #0000ff;">$yn</span> <span style="color: #339933;">=</span> <span style="color: #000066;">int</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$y</span> <span style="color: #339933;">/</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'tileSize'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>		<span style="color: #666666; font-style: italic;"># Round Down</span>
 <span style="color: #0000ff;">$xn</span> <span style="color: #339933;">=</span> <span style="color: #000066;">int</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$x</span> <span style="color: #339933;">/</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'tileSize'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>		<span style="color: #666666; font-style: italic;"># Round Down</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$parwho</span> <span style="color: #b1b100;">ne</span> <span style="color: #ff0000;">'Partial'</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: #0000ff;">$yd</span> <span style="color: #b1b100;">eq</span> <span style="color: #ff0000;">'N'</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #0000ff;">$yn</span><span style="color: #339933;">++</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: #0000ff;">$yn</span><span style="color: #339933;">--</span> <span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$xd</span> <span style="color: #b1b100;">eq</span> <span style="color: #ff0000;">'W'</span> <span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #0000ff;">$xn</span><span style="color: #339933;">++</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: #0000ff;">$xn</span><span style="color: #339933;">--</span> <span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #666666; font-style: italic;"># Make sure tile numbers are sane...</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$yn</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$yn</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elsif</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$yn</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$yn</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$xn</span> <span style="color: #339933;">&gt;</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$xn</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'max'</span><span style="color: #009900;">&#125;</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">elsif</span> <span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$xn</span> <span style="color: #339933;">&lt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #0000ff;">$xn</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span> <span style="color: #339933;">;</span>
 <span style="color: #009900;">&#125;</span>
&nbsp;
 <span style="color: #000066;">return</span><span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">$yn</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$xn</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;"># Translate a tile name to a pixel location...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> Google_Tile_to_Pix
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$y</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$x</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #000066;">return</span><span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.0f&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$y</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'tileSize'</span><span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.0f&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$x</span> <span style="color: #339933;">*</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'tileSize'</span><span style="color: #009900;">&#125;</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;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Translate a pixel location to a coordinate...</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">sub</span> PixtoCoordinate
<span style="color: #009900;">&#123;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$value</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$y</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$x</span>		<span style="color: #339933;">=</span> <span style="color: #000066;">shift</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">@d</span>		<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$e</span>		<span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$y</span> <span style="color: #339933;">-</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bmO'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngRad'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">-</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.6f&quot;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$x</span> <span style="color: #339933;">-</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'bmO'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'pixLngDeg'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
&nbsp;
 <span style="color: #0000ff;">$d</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span>	<span style="color: #339933;">=</span> <span style="color: #000066;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%0.6f&quot;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">2</span> <span style="color: #339933;">*</span> atan<span style="color: #009900;">&#40;</span><span style="color: #000066;">exp</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$e</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'PI'</span><span style="color: #009900;">&#125;</span> <span style="color: #009966; font-style: italic;">/ 2) /</span> <span style="color: #0000ff;">$$value</span><span style="color: #009900;">&#123;</span><span style="color: #ff0000;">'Wa'</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
 <span style="color: #000066;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">@d</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">__END__</span>
&nbsp;
<span style="color: #666666; font-style: italic;">=head1 SYNOPSIS
&nbsp;
#!/usr/bin/perl -w
# Test Program:
&nbsp;
# Google Tile Calculator Test Program...
# Author. John D. Coryat 01/2008 USNaviguide LLC
&nbsp;
use strict;
use USNaviguide_Google_Tiles ;
&nbsp;
my $latS        = 34.177442 ;
my $lngW        = -91.318359 ;
my $latN        = 35.797300 ;
my $lngE        = -88.681641 ;
my $zoom        = 8 ;
my $x           = '' ;
my %tile        = ( ) ;
my $i           = 0 ;
&nbsp;
my @d = &amp;Google_Tiles($latS, $lngW, $latN, $lngE, $zoom,0,'Whole');
&nbsp;
print &quot;Total: &quot; . scalar(@d) . &quot;\n&quot; ;
&nbsp;
for ( $i = 0; $i &lt;= $#d; $i++ )
{
 print &quot;Tile # $i Y: $d[$i]{'NAMEY'} X: $d[$i]{'NAMEX'}\n&quot; ;
&nbsp;
 %tile = %{$d[$i]} ;
&nbsp;
 foreach $x (sort keys %tile)
 {
  print &quot;\t$x: $tile{$x}\n&quot; ;
 }
}
&nbsp;
=cut</span></pre></div></div>

<p>Original link to this code is: <a href="http://www.usnaviguide.com/google-tiles.htm">http://www.usnaviguide.com/google-tiles.htm</a></p>
<p>The interesting methods in the script are:</p>
<ul>
<li><strong>Google_Tile_Factors:</strong> This method receives a zoom level and the tile size (256 in google maps) and return an array with some values that are used in next method.</li>
<li><strong>Google_Coord_to_Pix:</strong> This method receives the array returned by the previous method, a latitude and a longitude, and will return an array with a (x,y) pair that correspond to the pixel position in the map. Note that it won&#8217;t return a pixel position relative to the current view, but relative to the entire map.</li>
</ul>
<p>What about the PHP version?? Well, unfortunately my code is part of a project and I can&#8217;t post it here, but it&#8217;s pretty easy to convert these perl methods into PHP (I don&#8217;t have ANY experience with perl, and did it in a few minutes).</p>
<p>That&#8217;s it, I hope this helps you as it helped me.</p>
<p>Carlos</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2009/03/06/convert-lat-lng-and-zoom-values-to-pixel-xy-on-a-map/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>sfPropelActAsSortableBehaviorPlugin group patch</title>
		<link>http://blog.barros.ws/2009/02/20/sfpropelactassortablebehaviorplugin-group-patch/</link>
		<comments>http://blog.barros.ws/2009/02/20/sfpropelactassortablebehaviorplugin-group-patch/#comments</comments>
		<pubDate>Fri, 20 Feb 2009 14:17:33 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[behavior]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[propel]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=145</guid>
		<description><![CDATA[I guess that most Symfony developers should know this Symfony plugin, but for those who not, here&#8217;s an small quote:
&#8220;The sfPropelActAsSortableBehaviorPlugin is a symfony plugin that provides a new Propel behavior.Model classes with this behavior enabled become sortable, which means that they have new methods to deal with a position attribute.&#8221;
This Symfony plugin is really [...]]]></description>
			<content:encoded><![CDATA[<p>I guess that most Symfony developers should know this Symfony plugin, but for those who not, here&#8217;s an small quote:</p>
<p><em>&#8220;The sfPropelActAsSortableBehaviorPlugin is a symfony plugin that provides a new Propel behavior.Model classes with this behavior enabled become sortable, which means that they have new methods to deal with a position attribute.&#8221;</em></p>
<p>This Symfony plugin is really useful as it can save you a lot of code if you need to sort your objects, but in a recent project I worked on, I noticed this plugin lacks one functionality: it can&#8217;t handle <em>&#8220;sorting groups&#8221;</em> within the same object. For instance, suppose you have an Product and Category tables, and that each product belongs to a single category. Then, suppose you want to be able to sort your products so you can control how they show up in your pages. Using sfPropelActAsSortableBehaviorPlugin you can only sort the <b>entire</b> Product table, and that&#8217;s not really what we want. We need to be able to sort products within each category.<br />
I guess this problem is really common, and as I had to handle this in a recent project, I decided to write a patch for this plugin, and I&#8217;d like to share it. Before one ask me why I didn&#8217;t submit it as a official ticket, the reason is that there is already a patch submitted to handle this issue, from almost a year ago, that was not released yet, and I bet most people (including me) is not aware of, so I&#8217;m writing this post to tell about this for other users, and maybe make Kris Wallsmith (current leader) release his version, that in fact seem to be more powerful than mine, as it support creating sorting groups using more than one column.</p>
<p>So, how does it work?? sfPropelActAsSortableBehaviorPlugin is really simple to use, all you need is a <b>Integer</b> column in your model, and then activate the new behavior for you class using something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">sfPropelBehavior<span style="color: #339933;">::</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Item'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'act_as_sortable'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'column'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'rank'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>After applying this patch, the only thing you need to do is to add one more element to the above array:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">sfPropelBehavior<span style="color: #339933;">::</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Item'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'act_as_sortable'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'column'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'rank'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'group'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'category_id'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>And that&#8217;s it. New sfPropelActAsSortableBehaviorPlugin will use &#8220;category_id&#8221; as a <em>&#8220;sorting group&#8221;</em>. </p>
<p>You can now use all methods provided by the new behavior to sort your objects, just like you used to do without the patch. Also, if you don&#8217;t have a group category, just omit it from behavior initialization, and it will work as if u didn&#8217;t apply this patch.</p>
<p>Find below the full patch:</p>
<p><span id="more-145"></span></p>

<div class="wp_syntax"><div class="code"><pre class="diff" style="font-family:monospace;">diff -ur sfPropelActAsSortableBehaviorPlugin-0.6.1/lib/sfPropelActAsSortableBehavior.class.php sfPropelActAsSortableBehaviorPlugin-0.6.1-new/lib/sfPropelActAsSortableBehavior.class.php
<span style="color: #888822;">--- sfPropelActAsSortableBehaviorPlugin-0.6.1/lib/sfPropelActAsSortableBehavior.class.php	<span style="">2007</span>-08-07 <span style="">10</span>:<span style="">56</span>:<span style="">57.000000000</span> -0300</span>
<span style="color: #888822;">+++ sfPropelActAsSortableBehaviorPlugin-0.6.1-new/lib/sfPropelActAsSortableBehavior.class.php	<span style="">2009</span>-02-<span style="">20</span> <span style="">10</span>:<span style="">59</span>:<span style="">25.000000000</span> -0300</span>
<span style="color: #440088;">@@ -<span style="">21</span>,<span style="">14</span> +<span style="">21</span>,<span style="">18</span> @@</span>
    *
    * @return mixed sortable object
    **/
<span style="color: #991111;">-  public static function retrieveByPosition<span style="">&#40;</span>$peerClass, $position, $con = null<span style="">&#41;</span></span>
<span style="color: #00b000;">+  public static function retrieveByPosition<span style="">&#40;</span>$peerClass, $position, $con = null, $group = null<span style="">&#41;</span></span>
   <span style="">&#123;</span>
     $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_column', 'rank'<span style="">&#41;</span>;
<span style="color: #991111;">-    $rankColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $rankColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $rankColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_group'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $groupColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $groupColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    </span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
     $c = new Criteria;
<span style="color: #991111;">-    $c-&gt;add<span style="">&#40;</span>$rankColumnPhpName, $position<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $c-&gt;add<span style="">&#40;</span>$rankColumnPhpName, $position<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $c-&gt;add<span style="">&#40;</span>$groupColumnPhpName, $group<span style="">&#41;</span>;</span>
&nbsp;
     return call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'doSelectOne'<span style="">&#41;</span>, $c, $con<span style="">&#41;</span>; 
   <span style="">&#125;</span>
<span style="color: #440088;">@@ -<span style="">41</span>,<span style="">16</span> +<span style="">45</span>,<span style="">26</span> @@</span>
    *
    * @return integer maximum position
    **/
<span style="color: #991111;">-  public static function getMaxPosition<span style="">&#40;</span>$peerClass, $con = null<span style="">&#41;</span></span>
<span style="color: #00b000;">+  public static function getMaxPosition<span style="">&#40;</span>$peerClass, $con = null, $group = null<span style="">&#41;</span></span>
   <span style="">&#123;</span>
<span style="color: #991111;">-    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_group'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    </span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
     $sql = sprintf<span style="">&#40;</span>'SELECT MAX<span style="">&#40;</span>%s<span style="">&#41;</span> AS max FROM %s', 
       $rankColumnName,
       constant<span style="">&#40;</span>&quot;$peerClass::TABLE_NAME&quot;<span style="">&#41;</span>
<span style="color: #991111;">-    <span style="">&#41;</span>; </span>
<span style="color: #991111;">-    $rs = $con-&gt;prepareStatement<span style="">&#40;</span>$sql<span style="">&#41;</span>-&gt;executeQuery<span style="">&#40;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    <span style="">&#41;</span>; </span>
<span style="color: #00b000;">+    </span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span></span>
<span style="color: #00b000;">+    <span style="">&#123;</span></span>
<span style="color: #00b000;">+    	$sql .= sprintf<span style="">&#40;</span>&quot; WHERE %s = ?&quot;,$groupColumnName<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    	$stmt = $con-&gt;prepareStatement<span style="">&#40;</span>$sql<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    	$stmt-&gt;setString<span style="">&#40;</span><span style="">1</span>,$group<span style="">&#41;</span>;	</span>
<span style="color: #00b000;">+    <span style="">&#125;</span></span>
<span style="color: #00b000;">+    else $stmt = $con-&gt;prepareStatement<span style="">&#40;</span>$sql<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rs = $stmt-&gt;executeQuery<span style="">&#40;</span><span style="">&#41;</span>;</span>
     $rs-&gt;next<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
     return $rs-&gt;getInt<span style="">&#40;</span>'max'<span style="">&#41;</span>;
<span style="color: #440088;">@@ -<span style="">66</span>,<span style="">10</span> +<span style="">80</span>,<span style="">13</span> @@</span>
    *
    * @return array list of sortable objects
    **/
<span style="color: #991111;">-  public static function doSelectOrderByPosition<span style="">&#40;</span>$peerClass, $order = Criteria::ASC, $criteria = null, $con = null<span style="">&#41;</span></span>
<span style="color: #00b000;">+  public static function doSelectOrderByPosition<span style="">&#40;</span>$peerClass, $order = Criteria::ASC, $criteria = null, $con = null, $group = null<span style="">&#41;</span></span>
   <span style="">&#123;</span>
     $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_column', 'rank'<span style="">&#41;</span>;
<span style="color: #991111;">-    $rankColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $rankColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $rankColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.self::getClassFromPeerClass<span style="">&#40;</span>$peerClass<span style="">&#41;</span>.'_group'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $groupColumnPhpName = call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'translateFieldName'<span style="">&#41;</span>, $groupColumnName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    </span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
     if <span style="">&#40;</span>$criteria === null<span style="">&#41;</span> 
<span style="color: #440088;">@@ -<span style="">90</span>,<span style="">7</span> +<span style="">107</span>,<span style="">8</span> @@</span>
     else
     <span style="">&#123;</span>
       $criteria-&gt;addDescendingOrderByColumn<span style="">&#40;</span>$rankColumnPhpName<span style="">&#41;</span>;
<span style="color: #991111;">-    <span style="">&#125;</span></span>
<span style="color: #00b000;">+    <span style="">&#125;</span></span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $c-&gt;add<span style="">&#40;</span>$groupColumnPhpName,$group<span style="">&#41;</span>;</span>
&nbsp;
     return call_user_func<span style="">&#40;</span>array<span style="">&#40;</span>$peerClass, 'doSelect'<span style="">&#41;</span>, $criteria, $con<span style="">&#41;</span>; 
   <span style="">&#125;</span>
<span style="color: #440088;">@@ -<span style="">159</span>,<span style="">6</span> +<span style="">177</span>,<span style="">32</span> @@</span>
   public function setPosition<span style="">&#40;</span>$object, $position<span style="">&#41;</span>
   <span style="">&#123;</span>
     return $object-&gt;setByName<span style="">&#40;</span>sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'_column', 'rank'<span style="">&#41;</span>, $position, BasePeer::TYPE_FIELDNAME<span style="">&#41;</span>;
<span style="color: #00b000;">+  <span style="">&#125;</span></span>
<span style="color: #00b000;">+  </span>
<span style="color: #00b000;">+  /**</span>
<span style="color: #00b000;">+   * Gets the group of a sortable object</span>
<span style="color: #00b000;">+   * </span>
<span style="color: #00b000;">+   * @param mixed sortable object</span>
<span style="color: #00b000;">+   * </span>
<span style="color: #00b000;">+   * @return mixed group of the sortable object</span>
<span style="color: #00b000;">+   */</span>
<span style="color: #00b000;">+  public function getGroup<span style="">&#40;</span>$object<span style="">&#41;</span></span>
<span style="color: #00b000;">+  <span style="">&#123;</span></span>
<span style="color: #00b000;">+   	$groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'_group'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+   	if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> return $object-&gt;getByName<span style="">&#40;</span>$groupColumnName, BasePeer::TYPE_FIELDNAME<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+   	else return null;</span>
<span style="color: #00b000;">+  <span style="">&#125;</span></span>
<span style="color: #00b000;">+  </span>
<span style="color: #00b000;">+  /**</span>
<span style="color: #00b000;">+   * Sets the group of a sortable object</span>
<span style="color: #00b000;">+   * </span>
<span style="color: #00b000;">+   * @param mixed sortable object</span>
<span style="color: #00b000;">+   * @param mixed group value</span>
<span style="color: #00b000;">+   */</span>
<span style="color: #00b000;">+  public function setGroup<span style="">&#40;</span>$object, $group<span style="">&#41;</span></span>
<span style="color: #00b000;">+  <span style="">&#123;</span></span>
<span style="color: #00b000;">+  	$groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'_group'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+  	if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> return $object-&gt;setByName<span style="">&#40;</span>$groupColumnName, $group, BasePeer::TYPE_FIELDNAME<span style="">&#41;</span>;</span>
   <span style="">&#125;</span>
&nbsp;
   /**
<span style="color: #440088;">@@ -<span style="">170</span>,<span style="">7</span> +<span style="">214</span>,<span style="">7</span> @@</span>
    **/
   public function getNext<span style="">&#40;</span>$object<span style="">&#41;</span>
   <span style="">&#123;</span>
<span style="color: #991111;">-    return self::retrieveByPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer', self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> + <span style="">1</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    return self::retrieveByPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer', self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> + <span style="">1</span>, null, self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
   <span style="">&#125;</span>
&nbsp;
   /**
<span style="color: #440088;">@@ -<span style="">182</span>,<span style="">7</span> +<span style="">226</span>,<span style="">7</span> @@</span>
    **/
   public function getPrevious<span style="">&#40;</span>$object<span style="">&#41;</span>
   <span style="">&#123;</span>
<span style="color: #991111;">-    return self::retrieveByPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer', self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> - <span style="">1</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    return self::retrieveByPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer', self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> - <span style="">1</span>, null, self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
   <span style="">&#125;</span>
&nbsp;
   /**
<span style="color: #440088;">@@ -<span style="">206</span>,<span style="">7</span> +<span style="">250</span>,<span style="">7</span> @@</span>
    **/    
   public function isLast<span style="">&#40;</span>$object<span style="">&#41;</span>
   <span style="">&#123;</span>
<span style="color: #991111;">-    return self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> == self::getMaxPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    return self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span> == self::getMaxPosition<span style="">&#40;</span>get_class<span style="">&#40;</span>$object<span style="">&#41;</span>.'Peer', null, self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
   <span style="">&#125;</span>
&nbsp;
   /**
<span style="color: #440088;">@@ -<span style="">286</span>,<span style="">31</span> +<span style="">330</span>,<span style="">36</span> @@</span>
   <span style="">&#123;</span>
     $class = get_class<span style="">&#40;</span>$object<span style="">&#41;</span>;
     $peerClass = $class.'Peer';
<span style="color: #991111;">-    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_group'<span style="">&#41;</span>;</span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
     $oldPosition = self::getPosition<span style="">&#40;</span>$object<span style="">&#41;</span>;
     if <span style="">&#40;</span>$oldPosition == $newPosition<span style="">&#41;</span> return $oldPosition;
<span style="color: #991111;">-</span>
<span style="color: #00b000;">+</span>
     try
     <span style="">&#123;</span>
       $con-&gt;begin<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
       // Move the object away
<span style="color: #991111;">-      self::setPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass<span style="">&#41;</span> + <span style="">1</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      self::setPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass,null,self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span> + <span style="">1</span><span style="">&#41;</span>;</span>
       $object-&gt;save<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
       // Shift the objects between the old and the new position
<span style="color: #991111;">-      $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s %s <span style="">1</span> WHERE %s BETWEEN ? AND ?',</span>
<span style="color: #00b000;">+      $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s %s <span style="">1</span> WHERE %s BETWEEN ? AND ?%s',</span>
         constant<span style="">&#40;</span>&quot;$peerClass::TABLE_NAME&quot;<span style="">&#41;</span>,
         $rankColumnName,
         $rankColumnName,
         <span style="">&#40;</span>$oldPosition &lt; $newPosition<span style="">&#41;</span> ? '-' : '+',
<span style="color: #991111;">-        $rankColumnName</span>
<span style="color: #991111;">-      <span style="">&#41;</span>;</span>
<span style="color: #00b000;">+        $rankColumnName,</span>
<span style="color: #00b000;">+        $groupColumnName?&quot; AND $groupColumnName = ?&quot;:&quot;&quot;</span>
<span style="color: #00b000;">+        </span>
<span style="color: #00b000;">+      <span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      </span>
       $stmt = $con-&gt;prepareStatement<span style="">&#40;</span>$query<span style="">&#41;</span>;
       $stmt-&gt;setInt<span style="">&#40;</span><span style="">1</span>, min<span style="">&#40;</span>$oldPosition, $newPosition<span style="">&#41;</span><span style="">&#41;</span>;
<span style="color: #991111;">-      $stmt-&gt;setInt<span style="">&#40;</span><span style="">2</span>, max<span style="">&#40;</span>$oldPosition, $newPosition<span style="">&#41;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      $stmt-&gt;setInt<span style="">&#40;</span><span style="">2</span>, max<span style="">&#40;</span>$oldPosition, $newPosition<span style="">&#41;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $stmt-&gt;setString<span style="">&#40;</span><span style="">3</span>,self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
       $stmt-&gt;executeQuery<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
       // Move the object back in
<span style="color: #440088;">@@ -<span style="">357</span>,<span style="">9</span> +<span style="">406</span>,<span style="">9</span> @@</span>
   public function moveToBottom<span style="">&#40;</span>$object, $con = null<span style="">&#41;</span>
   <span style="">&#123;</span>
     $class = get_class<span style="">&#40;</span>$object<span style="">&#41;</span>;
<span style="color: #991111;">-    $peerClass = $class.'Peer';</span>
<span style="color: #991111;">-</span>
<span style="color: #991111;">-    return self::moveToPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass<span style="">&#41;</span>, $con<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $peerClass = $class.'Peer';</span>
<span style="color: #00b000;">+    </span>
<span style="color: #00b000;">+    return self::moveToPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass,null,self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>, $con<span style="">&#41;</span>;</span>
   <span style="">&#125;</span>
&nbsp;
   /**
<span style="color: #440088;">@@ -<span style="">378</span>,<span style="">7</span> +<span style="">427</span>,<span style="">8</span> @@</span>
   <span style="">&#123;</span>
     $class = get_class<span style="">&#40;</span>$object<span style="">&#41;</span>;
     $peerClass = $class.'Peer';
<span style="color: #991111;">-    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_group'<span style="">&#41;</span>;</span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
     try
<span style="color: #440088;">@@ -<span style="">386</span>,<span style="">14</span> +<span style="">436</span>,<span style="">16</span> @@</span>
       $con-&gt;begin<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
       // Shift the objects with a position higher than the given position
<span style="color: #991111;">-      $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s + <span style="">1</span> WHERE %s &gt;= ?',</span>
<span style="color: #00b000;">+      $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s + <span style="">1</span> WHERE %s &gt;= ?%s',</span>
         constant<span style="">&#40;</span>&quot;$peerClass::TABLE_NAME&quot;<span style="">&#41;</span>,
         $rankColumnName,
         $rankColumnName,
<span style="color: #991111;">-        $rankColumnName</span>
<span style="color: #00b000;">+        $rankColumnName,</span>
<span style="color: #00b000;">+        $groupColumnName?&quot; AND $groupColumnName = ?&quot;:&quot;&quot;</span>
       <span style="">&#41;</span>;
       $stmt = $con-&gt;prepareStatement<span style="">&#40;</span>$query<span style="">&#41;</span>;
<span style="color: #991111;">-      $stmt-&gt;setInt<span style="">&#40;</span><span style="">1</span>, $position<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      $stmt-&gt;setInt<span style="">&#40;</span><span style="">1</span>, $position<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $stmt-&gt;setString<span style="">&#40;</span><span style="">2</span>,self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
       $stmt-&gt;executeQuery<span style="">&#40;</span><span style="">&#41;</span>;
&nbsp;
       // Move the object in the list, at the given position
<span style="color: #440088;">@@ -<span style="">427</span>,<span style="">7</span> +<span style="">479</span>,<span style="">7</span> @@</span>
     // new records need to be initialized with position = maxPosition +<span style="">1</span> unless position is already set
     if<span style="">&#40;</span>!$object-&gt;getId<span style="">&#40;</span><span style="">&#41;</span> &amp;&amp; !$object-&gt;isColumnModified<span style="">&#40;</span>$rankColumnPhpName<span style="">&#41;</span><span style="">&#41;</span>
     <span style="">&#123;</span>
<span style="color: #991111;">-      self::setPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass<span style="">&#41;</span>+<span style="">1</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+      self::setPosition<span style="">&#40;</span>$object, self::getMaxPosition<span style="">&#40;</span>$peerClass,null,self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>+<span style="">1</span><span style="">&#41;</span>;</span>
     <span style="">&#125;</span>
   <span style="">&#125;</span> 
&nbsp;
<span style="color: #440088;">@@ -<span style="">442</span>,<span style="">17</span> +<span style="">494</span>,<span style="">20</span> @@</span>
   <span style="">&#123;</span>  
     $class = get_class<span style="">&#40;</span>$object<span style="">&#41;</span>;
     $peerClass = $class.'Peer';
<span style="color: #991111;">-    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $rankColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_column', 'rank'<span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $groupColumnName = sfConfig::get<span style="">&#40;</span>'propel_behavior_act_as_sortable_'.$class.'_group'<span style="">&#41;</span>;</span>
     if<span style="">&#40;</span>!$con<span style="">&#41;</span> $con = Propel::getConnection<span style="">&#40;</span>constant<span style="">&#40;</span>&quot;$peerClass::DATABASE_NAME&quot;<span style="">&#41;</span><span style="">&#41;</span>;
&nbsp;
<span style="color: #991111;">-    $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s - <span style="">1</span> WHERE %s &gt; ?',</span>
<span style="color: #00b000;">+    $query = sprintf<span style="">&#40;</span>'UPDATE %s SET %s = %s - <span style="">1</span> WHERE %s &gt; ?%s',</span>
       constant<span style="">&#40;</span>&quot;$peerClass::TABLE_NAME&quot;<span style="">&#41;</span>,
       $rankColumnName,
       $rankColumnName,
<span style="color: #991111;">-      $rankColumnName</span>
<span style="color: #00b000;">+      $rankColumnName,</span>
<span style="color: #00b000;">+      $groupColumnName?&quot; AND $groupColumnName = ?&quot;:&quot;&quot;</span>
     <span style="">&#41;</span>;
     $stmt = $con-&gt;prepareStatement<span style="">&#40;</span>$query<span style="">&#41;</span>;
<span style="color: #991111;">-    $stmt-&gt;setInt<span style="">&#40;</span><span style="">1</span>, $object-&gt;getPosition<span style="">&#40;</span><span style="">&#41;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    $stmt-&gt;setInt<span style="">&#40;</span><span style="">1</span>, $object-&gt;getPosition<span style="">&#40;</span><span style="">&#41;</span><span style="">&#41;</span>;</span>
<span style="color: #00b000;">+    if<span style="">&#40;</span>$groupColumnName<span style="">&#41;</span> $stmt-&gt;setString<span style="">&#40;</span><span style="">2</span>, self::getGroup<span style="">&#40;</span>$object<span style="">&#41;</span><span style="">&#41;</span>;</span>
     $stmt-&gt;executeQuery<span style="">&#40;</span><span style="">&#41;</span>;
   <span style="">&#125;</span>
 <span style="">&#125;</span></pre></div></div>

<p>You can also <a href="/files/sfPropelActAsSortableBehaviorPlugin-0.6.1.diff">download the patch here</a>.<br />
For those who want to take a look at Kris Wallsmith&#8217;s patch, just <a href="http://trac.symfony-project.org/ticket/3240" target="_blank">click here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2009/02/20/sfpropelactassortablebehaviorplugin-group-patch/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>This site may harm your computer???</title>
		<link>http://blog.barros.ws/2009/01/31/this-site-may-harm-your-computer/</link>
		<comments>http://blog.barros.ws/2009/01/31/this-site-may-harm-your-computer/#comments</comments>
		<pubDate>Sat, 31 Jan 2009 15:27:45 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[fun]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[harm]]></category>
		<category><![CDATA[phishing]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=127</guid>
		<description><![CDATA[Today (actually a few minutes ago), I was googling about some random subjects, when I clicked on a link and got that well known Google anti-phishing page alerting me that the website I was about to view could harm my computer. Well, nothing wrong here so far, BUT&#8230;. I went back to Google results I [...]]]></description>
			<content:encoded><![CDATA[<p>Today (actually a few minutes ago), I was googling about some random subjects, when I clicked on a link and got that well known Google anti-phishing page alerting me that the website I was about to view could harm my computer. Well, nothing wrong here so far, BUT&#8230;. I went back to Google results I noticed that ALL results was marked as harmful. That was weird, so to be sure, I started a new search for the word Google, and guess what?? I got the same warnings, even for Google pages. This is clearly some guy doing something really wrong at Google.  A few minutes (less than 4 minutes) later, the problem was solved, but I had a chance to take some screenshots <img src='http://blog.barros.ws/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .. Well, this is an really off-topic and useless post, but this was, at least, funny to witness this!</p>

<a href='http://blog.barros.ws/2009/01/31/this-site-may-harm-your-computer/picture-1-2/' title='picture-1'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2009/01/picture-1-150x150.png" class="attachment-thumbnail" alt="" title="picture-1" /></a>
<a href='http://blog.barros.ws/2009/01/31/this-site-may-harm-your-computer/picture-2-2/' title='picture-2'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2009/01/picture-2-150x150.png" class="attachment-thumbnail" alt="" title="picture-2" /></a>

]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2009/01/31/this-site-may-harm-your-computer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<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>10</slash:comments>
		</item>
		<item>
		<title>SOAP WebService in Symfony</title>
		<link>http://blog.barros.ws/2008/11/16/soap-webservice-in-symfony/</link>
		<comments>http://blog.barros.ws/2008/11/16/soap-webservice-in-symfony/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 01:05:34 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[soap]]></category>
		<category><![CDATA[webservice]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=69</guid>
		<description><![CDATA[One interesting topic on web development is webservice development. There are several techniques to implement a webservice out there, and today I&#8217;ll talk about one technique that I worked in the recent past that I really like: SOAP. As per wikipedia:
SOAP, originally defined as Simple Object Access Protocol, is a protocol specification for exchanging structured [...]]]></description>
			<content:encoded><![CDATA[<p>One interesting topic on web development is <em>webservice development</em>. There are several techniques to implement a webservice out there, and today I&#8217;ll talk about one technique that I worked in the recent past that I really like: <a href="http://en.wikipedia.org/wiki/SOAP_(protocol)" target="_blank">SOAP</a>. As per wikipedia:</p>
<p><em>SOAP, originally defined as Simple Object Access Protocol, is a protocol specification for exchanging structured information in the implementation of Web Services in computer networks. It relies on Extensible Markup Language (XML) as its message format and usually relies on other Application Layer protocols, most notably Remote Procedure Call (RPC) and HTTP for message negotiation and transmission. SOAP forms the foundation layer of the web services protocol stack providing a basic messaging framework upon which abstract layers can be built.</em></p>
<p>The plan for this tutorial is to build a complete set of webservice methods to interact with the citypicker, <a href="http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/">built in a previous post</a>. For this, I&#8217;ll use a great symfony plugin called <a href="http://www.symfony-project.org/plugins/ckWebServicePlugin">ckWebService</a>. This plugin enables the developer to expose your actions as a SOAP webservices. Another great functionality is the built-in WSDL generator, that parses module&#8217;s doc comment in order to identify which actions should be exposed and it&#8217;s input/output parameters. </p>
<p><span id="more-69"></span></p>
<p>Let&#8217;s start by installing ckWebService plugin in our symfony project. I&#8217;ll not install the latest release, instead I&#8217;ll checkout from trunk svn, as it contains some nice improvements if compared to latest release:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">barrosws@barros.ws [~/symfony/blog]# cd plugins/
barrosws@barros.ws [~/symfony/blog/plugins]# svn co http://svn.symfony-project.com/plugins/ckWebServicePlugin/trunk ckWebServicePlugin</pre></div></div>

<p>OBSERVATION: Current trunk version has a small bug (actually a wrong variable name) that must be fixed before continuing:</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> getResultProperty<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</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;">resultMember</span><span style="color: #339933;">;</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;">resultProperty</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now we need to configure the plugin in order to make it work. The <a href="http://www.symfony-project.org/plugins/ckWebServicePlugin/2_1_0?tab=plugin_readme">read-me located at plugin page</a> provides a complete guide to configure it. For this project we use a basic configuration:</p>
<p>apps/frontend/config/app.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">soap:
  enable_soap_parameter: on
  ck_web_service_plugin:
    wsdl: soap.wsdl 
    handler: ckSoapHandler
    persist: %SOAP_PERSISTENCE_SESSION%
    render: off
    result_callback: getSoapResult
    soap_options:
      encoding: utf-8
      soap_version: %SOAP_1_2%</pre></div></div>

<p>apps/frontend/config/filters.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">soap_parameter:
  class: ckSoapParameterFilter
  param:
    condition: %APP_ENABLE_SOAP_PARAMETER%</pre></div></div>

<p>apps/frondend/config/factories.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;">soap:
  controller:
    class: ckWebServiceController</pre></div></div>

<p>Done! That&#8217;s all we need to start exposing actions as SOAP webservices. For now on we can expose any of our previously created action by adding a special tag to the doc comment, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #009933; font-style: italic;">/**
  * Action description
  * @ws-enable
  *
  * @param string $name
  * @return boolean
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeSomeAction<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;">/* action here */</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>This doc comment will expose the action and instruct the WSDL generator that this action expects a string input parameter, called $name and that it will return a boolean value. An interesting thing about this plugin is that it will place all input parameters in the $request object, so the action can access it as if it was called from a browser, passing name as a query string or a post value:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #339933;">...</span>
    <span style="color: #000088;">$name</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;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span></pre></div></div>

<p>Also, notice that $request parameter was removed from the doc comment. This is necessary because if we keep it, the WSDL generator will add $request as a parameter to the webservice, what is not the case here.</p>
<p>Let&#8217;s start the implementation for this project. We have three actions that will be exposed:</p>
<ul>
<li>executeIndex: to list users;</li>
<li>executeEdit: to insert/edit users;</li>
<li>executeDel: to delete users.</li>
</ul>
<p>One might think that we will need to add @ws-enable to these actions doc comment&#8230; well, yes, that&#8217;s the original idea, but I prefer using a different approach. My approach is to create a new module, called soap (or whatever you want) and create <em>wrappers</em> to actual actions. This will reduce the number changes needed to be done in the actual actions (sometimes it won&#8217;t require any change at all) and will make it possible for the developer to code the entire system without even caring about webservice, all adjustments can be easily made only when actually implementing the webservice. In some emails I exchanged with Christian Kerl, the plugin author, he said me that this is not the best way to achieve this result. The correct way to do this is to create a custom SoapHandler, but this will <strong>kill</strong> WSDL generator (he said work is in progress), so I&#8217;ll stick to my way by now (trunk version has all the necessary changes to make this possible &#8211; it&#8217;s not the case with latest release).</p>
<p>So, let&#8217;s create our new module:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">barrosws@barros.ws [~/symfony/blog]# symfony generate:module frontend soap
&gt;&gt; dir+      /home/barrosws/symfony/blog/apps/frontend/modules/soap/templates
&gt;&gt; file+     /home/barrosws/symfony/blog/app...soap/templates/indexSuccess.php
&gt;&gt; dir+      /home/barrosws/symfony/blog/apps/frontend/modules/soap/actions
&gt;&gt; file+     /home/barrosws/symfony/blog/app.../soap/actions/actions.class.php
&gt;&gt; file+     /home/barrosws/symfony/blog/tes...al/frontend/soapActionsTest.php
&gt;&gt; tokens    /home/barrosws/symfony/blog/tes...al/frontend/soapActionsTest.php
&gt;&gt; tokens    /home/barrosws/symfony/blog/app...soap/templates/indexSuccess.php
&gt;&gt; tokens    /home/barrosws/symfony/blog/app.../soap/actions/actions.class.php</pre></div></div>

<p>The first action will expose is executeIndex, that will return a list of all users registered in the system. This is the simplest one and I&#8217;ll use to explain some important points:</p>
<p>apps/frontend/modules/soap/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;">/**
  * Get users
  *
  * @ws-enable
  * 
  * @return SoapUser[]
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetUsers<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;">// call actual action</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">forward</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'index'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// set result</span>
  	<span style="color: #000088;">$actionInstance</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLastActionInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$actionInstance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$actionInstance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">users</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>As I said before, we will create <em>wrappers</em> to actual actions. For this action, we don&#8217;t have any input parameter, so we don&#8217;t need any extra processing. First thing the action does is a forward to actual action. Note that I use the forward method from the <strong>controller</strong> instead of forward method from sfAction. This is necessary because we need continue our execution flow AFTER actual action returns (sfAction&#8217;s forward won&#8217;t return control to us). Return value is expected to be located in the deepest action instance, in our case, citypicker/index action, in a property called <em>result</em> (in our case, we store the result of a UserPeer::doSelect() call &#8211; made in citypicker/index action and stored in users property). In order to do this we need to get this action&#8217;s instance and that&#8217;s what getLastActionInstance method do: </p>
<p>apps/frontend/modules/soap/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;">/**
   * Get last action instance
   * 
   * @return sfActionInstance
   */</span>  
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">function</span> getLastActionInstance<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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getActionStack</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLastEntry</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getActionInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>This method will simply return last actions instance from the action stack, and we will use it in all of our <em>wrappers</em>.  If you look at doc comments, you will notice return value is declared as an array of SoapUser objects. SoapUser class is defined as follows:</p>
<p>lib/soap/SoapUser.class.php</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> SoapUser
<span style="color: #009900;">&#123;</span>
	<span style="color: #009933; font-style: italic;">/**
	 * User name
	 * 
	 * @var string
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #009933; font-style: italic;">/**
	 * Country ID
	 * 
	 * @var integer
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$country_id</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #009933; font-style: italic;">/**
	 * State ID
	 * 
	 * @var integer
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$state_id</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #009933; font-style: italic;">/**
	 * City ID
	 * 
	 * @var integer
	 */</span>
	<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$city_id</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>

<p>Doc comments are <strong>REQUIRED</strong> here too, because WSDL generator will use it to build the object definition. When sending result back, our result (array of User objects) will be converted into SoapUser objects, making these properties available.</p>
<p>Our first method is complete. In order to start using it, we need to generate the WSDL definition, using the built-in WSDL generator. The generator will also create the frontend dispatcher, in web/ directory:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">barrosws@barros.ws [~/symfony/blog]# symfony webservice:generate-wsdl frontend soap http://blog.barros.ws/symfony
&gt;&gt; file-     /home/barrosws/symfony/blog/web/soap.php
&gt;&gt; file+     /home/barrosws/symfony/blog/web/soap.php
&gt;&gt; tokens    /home/barrosws/symfony/blog/web/soap.php
&gt;&gt; file+     /home/barrosws/symfony/blog/web/soap.wsdl</pre></div></div>

<p>In order to test it we can use a nice piece of software called <a href="http://www.soapui.org/">SoapUI</a>. This software will read soap.wsdl and build the request, all using a nice GUI. I recommend downloading the trial of PRO version, as it is capable of generating forms (web like) where you can input parameters:</p>
<p><center><a href="http://blog.barros.ws/wp-content/uploads/2008/11/picture-3.png"><img src="http://blog.barros.ws/wp-content/uploads/2008/11/picture-3-300x224.png" alt="" title="SoapUI - getUsers request" width="300" height="224" class="alignnone size-medium wp-image-83" /></a></center></p>
<p>executeDel actions is similar to executeIndex:</p>
<p>apps/frontend/modules/soap/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;">/**
  * Deletes an user
  *
  * @ws-enable
  * @param integer $id
  * 
  * @return boolean
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeDelUser<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;">// call actual action</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">forward</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'del'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// set result</span>
  	<span style="color: #000088;">$actionInstance</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLastActionInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<span style="color: #000088;">$actionInstance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now, executeEdit (executeNewUser in our wrapper) is a bit trickier:</p>
<p>apps/frontend/modules/soap/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;">/**
  * Creates a new user in the system
  *
  * @ws-enable
  * @param SoapUser $user
  * 
  * @return boolean
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeNewUser<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;">// convert input param from OBJECT to ARRAY</span>
  	<span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setParameter</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'user'</span><span style="color: #339933;">,</span><span style="color: #990000;">get_object_vars</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: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// call actual action</span>
  	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getController</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">forward</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'citypicker'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'edit'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #666666; font-style: italic;">// check errors</span>
  	<span style="color: #000088;">$actionInstance</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getLastActionInstance</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: #339933;">!</span><span style="color: #000088;">$actionInstance</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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">throwSoapFormException</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$actionInstance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">form</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  	<span style="color: #000088;">$actionInstance</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">result</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>First difference we can note is the fact this action requires one input parameters. In doc comment we declare that this action expects an SoapUser object as input, but the actual action expects an simple array. The first step then is to convert received object into an array. For this we use <em>get_object_vars</em> and after conversion, we set it back to the $request object. Finally we call actual action, that will act as if the user had submitted the form. Next difference is that we need to check if there was any error processing input data. We do this by checking if form, in actual action instance, is valid, and if not return an error message. In order to throw an exception with detailed errors, I created an small method called throwSoapFormException, that will iterate through all errors in the form and build  single string, with one error per line:</p>
<p>apps/frontend/modules/soap/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;">/**
   * Throw a SoapFault error based on form errors
   * 
   * @param sfForm $form
   */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> throwSoapFormException<span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</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;">$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;">$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>
&nbsp;
	throw <span style="color: #000000; font-weight: bold;">new</span> SoapFault<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ERROR'</span><span style="color: #339933;">,</span><span style="color: #990000;">implode</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;n&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$errors</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></div></div>

<p>And that&#8217;s it, we can now create new users using the new SOAP interface:</p>
<p><center><a href="http://blog.barros.ws/wp-content/uploads/2008/11/picture-4.png"><img src="http://blog.barros.ws/wp-content/uploads/2008/11/picture-4-300x225.png" alt="" title="SoapUI - newUser" width="300" height="225" class="alignnone size-medium wp-image-85" /></a></center></p>
<p>Well, actually one small thing is missing to make it really work&#8230; Did u notice that I didn&#8217;t touch actual actions yet? Sometimes we don&#8217;t need to touch it, but that&#8217;s not our case. If you look at <a href="http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/">citypicker post</a> you will notice that both &#8220;del&#8221; and &#8220;edit&#8221; actions redirect the user back to index page on success. We <strong>can&#8217;t</strong> do this when running on soap mode, or we will lose control and we won&#8217;t be able to send correct result back to the client. To fix this, we just need to make an small change:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><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></pre></div></div>

<p>isSoapRequest is a new method added by ckWebservicePlugin and it will return true when executing the actions via SOAP. Adding this check we just perform the redirect when NOT in SOAP mode.</p>
<p>That&#8217;s all we need to talk about how to expose your actions via SOAP, but in order to complete our example, we need to create some methods to fetch countries/states/cities informations. For this we create 6 new actions:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #009933; font-style: italic;">/**
  * Get countries list
  * @ws-enable
  *
  * @return SoapGeo[]
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetCountries<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;">result</span> <span style="color: #339933;">=</span> CountryPeer<span style="color: #339933;">::</span><span style="color: #004000;">doSelect</span><span style="color: #009900;">&#40;</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: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
  * Get a country
  *
  * @ws-enable
  * @param integer $id
  * 
  * @return SoapGeo
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetCountry<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;">result</span> <span style="color: #339933;">=</span> CountryPeer<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;">'id'</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: #009933; font-style: italic;">/**
  * Get states list
  *
  * @ws-enable
  * @param integer $country_id
  *
  * @return SoapGeo[]
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetStates<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;">$country</span> <span style="color: #339933;">=</span> CountryPeer<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;">'country_id'</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: #339933;">!</span><span style="color: #000088;">$country</span><span style="color: #009900;">&#41;</span> throw <span style="color: #000000; font-weight: bold;">new</span> SoapFault<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ERROR'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'Invalid country'</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;">result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$country</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStates</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
  * Get a state
  *
  * @ws-enable
  * @param integer $id
  * 
  * @return SoapGeo
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetState<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;">result</span> <span style="color: #339933;">=</span> StatePeer<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;">'id'</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: #009933; font-style: italic;">/**
  * Get cities list
  *
  * @ws-enable
  * @param integer $state_id
  *
  * @return SoapGeo[]
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetCities<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;">$state</span> <span style="color: #339933;">=</span> StatePeer<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;">'state_id'</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: #339933;">!</span><span style="color: #000088;">$state</span><span style="color: #009900;">&#41;</span> throw <span style="color: #000000; font-weight: bold;">new</span> SoapFault<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'ERROR'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'Invalid state'</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;">result</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$state</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCitys</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #009933; font-style: italic;">/**
  * Get a city
  *
  * @ws-enable
  * @param integer $id
  * 
  * @return SoapGeo
  */</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> executeGetCity<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;">result</span> <span style="color: #339933;">=</span> CityPeer<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;">'id'</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></div></div>

<p>And to finish, we need to create the SoapGeo class, that will store country name and id:</p>
<p>lib/soap/SoapGeo.class.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000000; font-weight: bold;">class</span> SoapGeo
<span style="color: #009900;">&#123;</span>
    <span style="color: #009933; font-style: italic;">/**
     * ID
     *
     * @var integer
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$id</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Name
     *
     * @var string
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>And we&#8217;re done. With this we can now build an external app to create/edit/delete users in the database. I spent several days working with the plugin before coming up with this solution and I hope this will save other developers some time dealing with SOAP implementations. Also, I&#8217;d like to thank Christian Kerl for all new changes made to trunk version that is making this plugin even better.</p>
<p>If one wants to test our SOAP interface, the .wsdl file is located at <a href="http://blog.barros.ws/symfony/soap.wsdl">http://blog.barros.ws/symfony/soap.wsdl</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2008/11/16/soap-webservice-in-symfony/feed/</wfw:commentRss>
		<slash:comments>38</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>19</slash:comments>
		</item>
		<item>
		<title>Joomla like theme for symfony admin generator</title>
		<link>http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/</link>
		<comments>http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 21:52:43 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[admin generator]]></category>
		<category><![CDATA[joomla]]></category>
		<category><![CDATA[theme]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=39</guid>
		<description><![CDATA[When I first started working with symfony admin generator, I searched for some nice themes that I could use in my project, and for my surprise, I didn&#8217;t find anything. Searching a bit more I came across a blog post on SymfonyLab (http://www.symfonylab.com/backend-generator-theme/) asking about themes. In the post the author pointed an joomla like [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">When I first started working with symfony admin generator, I searched for some nice themes that I could use in my project, and for my surprise, I didn&#8217;t find anything. Searching a bit more I came across a blog post on SymfonyLab (<a title="http://www.symfonylab.com/backend-generator-theme/" href="http://www.symfonylab.com/backend-generator-theme/" target="_blank">http://www.symfonylab.com/backend-generator-theme/</a>) asking about themes. In the post the author pointed an joomla like theme (<a title="http://www.symfony-project.org/forum/index.php/m/16515" href="http://www.symfony-project.org/forum/index.php/m/16515" target="_blank">http://www.symfony-project.org/forum/index.php/m/16515</a>), created by a user called Draven, that I really liked, but it&#8217;s outdated. I&#8217;m not really a joomla fan, but I must admin I like their backend design, so I decided to do a new implementation of this theme. It&#8217;s based on Draven&#8217;s implementation, in fact the css is almost the same, with some changes here there, and some small layout changes as well (specially in the edit page). Just one note that&#8217;s worth saying, it&#8217;s not really a THEME, but just a css, some layout templates and a collection of images, that changes the look of generated admin module. Here are some screenshots:</p>

<a href='http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/picture-1/' title='Login screen'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2008/10/picture-1-150x150.png" class="attachment-thumbnail" alt="" title="Login screen" /></a>
<a href='http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/picture-2/' title='Dashboard screen'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2008/10/picture-2-150x150.png" class="attachment-thumbnail" alt="" title="Dashboard screen" /></a>
<a href='http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/picture-3/' title='List screen'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2008/10/picture-3-150x150.png" class="attachment-thumbnail" alt="" title="List screen" /></a>
<a href='http://blog.barros.ws/2008/10/29/joomla-like-theme-for-symfony-admin-generator/picture-4/' title='Edit screen'><img width="150" height="150" src="http://blog.barros.ws/wp-content/uploads/2008/10/picture-4-150x150.png" class="attachment-thumbnail" alt="" title="Edit screen" /></a>

<p>Also you can see it in action <a href="http://blog.barros.ws/symfony/admin.php" target="_blank">here</a> (use anything as username/password).</p>
<p><span id="more-39"></span></p>
<p>It&#8217;s pretty simple to install and use this theme, just download the files <a href="http://blog.barros.ws/wp-content/uploads/2008/10/symfony-joomla.zip">here</a>. This package contains a web directory with a set of images, javascripts and css, all stored in a dir called sf_admin. Also, it contains a set of layout templates that you must add to your backend application. Note that along with the layout templates, there are two files that are NOT layout templates, but templates that you should moved to the appropriated action, loginSuccess.php and dashboardSuccess.php. loginSuccess.php is the login screen and should be moved to your login module, and dashboard is the main admin screen and should be moved to your main module.</p>
<p>First file that needs to be changed is the main view.yml file for the backend app, in order to add the custom javascripts, css and set the layout.</p>
<p>app/backend/config.view.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">  stylesheets:    [sf_admin/main,sf_admin/theme]
  javascripts:    [sf_admin/JSCookMenu_mini,sf_admin/theme]
&nbsp;
  has_layout:     on
  layout:         layout</pre></div></div>

<p>Note that loginSuccess.php template must NOT have a layout because it has a different look, so, don&#8217;t forget to set has_layout: off to the correct view.yml when using it. Now, for each module, you must set a new css in the generator.yml config file:</p>
<p>app/backend/modules/some_module/config/generator.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      SomeModel
    theme:            default
    css:              sf_admin/main</pre></div></div>

<p>Also in generators, I suggest to ALWAYS add a fieldset caption to the edit page, otherwise it will not look as expected. You can do something like:</p>
<p>app/backend/modules/some_module/config/generator.yml:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">    edit:
      title:          User manager: edit
      display:
        &quot;Details&quot;:             [id,name]
      fields:
        name:           { name: Name, help: &quot;Enter name here&quot; }
      actions:
        _delete:        { name: Delete }
        _list:          { name: Close }
        _save_and_list: { name: Save }</pre></div></div>

<p>One drawback this theme has is the fact that all &#8220;actions&#8221; have absolute positioning, in order to place it at top right. This means that each action as a static location, thus, you cannot add an save action as the first button in one view, and then add as the second button in another view, they will ALWAYS be placed in the same position (btw, to change actions location/order/etc, just edit css/sf_admin/main.css file and search for .sf_admin_action_create &#8211; or any other action name &#8211; and change the <b><i>right</i></b> value). I tried to move it&#8217;s container and then set contents to float:right, but it didn&#8217;t work as expected. Actually it worked just fine, but the problem was with the delete button. Delete button is in a different container, because it needs to live in a new &lt;form&gt; tag, so it was not possible to make it float. But as original author (Draven) said, it&#8217;s not a real theme. One can create a complete new theme to address these small details, but for me, this works like a charm <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/10/29/joomla-like-theme-for-symfony-admin-generator/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Country/State/City picker in Symfony 1.1</title>
		<link>http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/</link>
		<comments>http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/#comments</comments>
		<pubDate>Sun, 26 Oct 2008 14:49:03 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[symfony]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[city picker]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=38</guid>
		<description><![CDATA[Have you ever seen those forms where you select a country, then it populates a list of states, then you pick a state and it populate a list of cities? I&#8217;ve seem many of these and I really like them. In one of my past projects I was asked to add a similar form to [...]]]></description>
			<content:encoded><![CDATA[<p>Have you ever seen those forms where you select a country, then it populates a list of states, then you pick a state and it populate a list of cities? I&#8217;ve seem many of these and I really like them. In one of my past projects I was asked to add a similar form to the system, using symfony, and I&#8217;ll show how I accomplished this, making use of the excellent new symfony 1.1 form system. For those who want to see what it looks like before keep on reading, I put very simple sample online <a title="City Picker" href="http://blog.barros.ws/symfony/citypicker" target="_blank">in this link</a>.</p>
<p><span id="more-38"></span></p>
<p>Let&#8217;s start with the database model (config/schema.yml):</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">propel:
  _attributes:   { noXsd: false, defaultIdMethod: none, package: lib.model }
&nbsp;
  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 }
    created_at:      ~
    updated_at:      ~
&nbsp;
  cp_countries:
    _attributes:     { phpName: Country, idMethod: native }
    id:              ~
    code:            { type: varchar(2), required: true }
    name:            { type: varchar(100), required: true }
&nbsp;
  cp_states:
    _attributes:     { phpName: State, idMethod: native }
    id:              ~
    country_id:      { type: integer, required: true, foreignTable: cp_countries, foreignReference: id, onDelete: &quot;CASCADE&quot; }
    name:            { type: varchar(100), required: true }
&nbsp;
  cp_cities:
    _attributes:     { phpName: City, idMethod: native }
    id:              ~
    state_id:        { type: integer, required: true, foreignTable: cp_states, foreignReference: id, onDelete: &quot;CASCADE&quot; }
    name:            { type: varchar(100), required: true }</pre></div></div>

<p>This is a very simple database model, with user, country, state and city. In this schema, each city is related to a single state and each state is related to a single country. You may ask why I did add all these three elements in the user model, as we can get these info from the city. Honestly, there&#8217;s no reason for this, but I left if there just for the sake of simplicity. We can remove state and country and create a getState() and getCountry() methods on User class to get these informations, but I&#8217;ll leave it as an exercise for the readers. So, first step is to build this model and then generate SQL script:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ symfony propel:build-model
$ symfony propel:build-sql
$ symfony propel:insert-sql</pre></div></div>

<p>Also, for this example I created a module called citypicker, inside frontend application:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ symfony generate:module frontend citypicker</pre></div></div>

<p>First step in this sample is to create the list view, I&#8217;ll not explain in details about it because it&#8217;s just a simple list view with nothing special, I&#8217;ll just put the action and template code here:</p>
<p>actions.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> 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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">users</span> <span style="color: #339933;">=</span> UserPeer<span style="color: #339933;">::</span><span style="color: #004000;">doSelect</span><span style="color: #009900;">&#40;</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: #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> executeDel<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;">$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: #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;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  	<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></pre></div></div>

<p>indexSuccess.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">&lt;table width=&quot;50%&quot; align=&quot;center&quot; border=&quot;1&quot;&gt;
	&lt;tr&gt;
		&lt;th&gt;ID&lt;/th&gt;
		&lt;th align=&quot;left&quot;&gt;Name&lt;/th&gt;
		&lt;th align=&quot;left&quot;&gt;Country&lt;/th&gt;
		&lt;th align=&quot;left&quot;&gt;State&lt;/th&gt;
		&lt;th align=&quot;left&quot;&gt;City&lt;/th&gt;
	&lt;/tr&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;">$users</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$user</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 align=&quot;center&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span>link_to<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'citypicker/edit?id='</span><span style="color: #339933;">.</span><span style="color: #000088;">$user</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> - <span style="color: #000000; font-weight: bold;">&lt;?=</span>link_to<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'del'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'citypicker/del?id='</span><span style="color: #339933;">.</span><span style="color: #000088;">$user</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>&lt;/td&gt;
			&lt;td&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span>esc_entities<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getName</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;/td&gt;
			&lt;td&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</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: #000000; font-weight: bold;">?&gt;</span>&lt;/td&gt;
			&lt;td&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</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: #000000; font-weight: bold;">?&gt;</span>&lt;/td&gt;
			&lt;td&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</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: #000000; font-weight: bold;">?&gt;</span>&lt;/td&gt;
		&lt;/tr&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;/table&gt;
&lt;p align=&quot;center&quot;&gt;<span style="color: #000000; font-weight: bold;">&lt;?=</span>button_to<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'New user'</span><span style="color: #339933;">,</span><span style="color: #0000ff;">'citypicker/edit'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>&lt;/p&gt;</pre></div></div>

<p>Now we need to create the edit view, where the citipicker will be shown. For this, we need to create the form that will handle user input. In this example I didn&#8217;t use propel:build-forms command, instead I created the form from scratch (that&#8217;s one point to improve). The resulting code is as follows:</p>
<p>lib/form/CPUserForm.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> CPUserForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormPropel
<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: #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> 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></div></div>

<p>This form is not much different from a common form, using sfWidgetFormPropelSelect to show a list of available objects, except by the new option I added, criteria. As can be seen at the top of the code, I build two criterias that are used to filter state and city, based on current selection. This will make the state select only display states belonging to selected country, and cities belonging to selected state. Also, if no country is selected, state and city list will be empty.<br />
Another important step that must be done in order to use sfWidgetFormPropelSelect is to create the magic method __toString to Country, State and City objects. Just add the following code to ALL three classes:</p>
<p>lib/model/Country.class.php, lib/model/State.class.php, lib/model/City.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> __toString<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: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The template needs a special attention as well. As will we use AJAX to update the select boxes without reloading the page, we need to split the edit template in two files, the main file and a partial file that will contain the select boxes and the ajax calls:</p>
<p>editSuccess.php:</p>

<div class="wp_syntax"><div 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;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;</pre></div></div>

<p>_address_edit.php:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span> use_helper<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Javascript'</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span>
<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;country_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: #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;">'$(this.form).request({
						parameters: {refresh: &quot;Y&quot; },
						onComplete: function (r) { $(&quot;address&quot;).update(r.responseText) }
					});'</span>
<span style="color: #009900;">&#41;</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;state_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: #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;">'$(this.form).request({
						parameters: {refresh: &quot;Y&quot; },
						onComplete: function (r) { $(&quot;address&quot;).update(r.responseText) }
					});'</span>
<span style="color: #009900;">&#41;</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;city_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></pre></div></div>

<p>This code submits the form every time the user changes either country or state boxes. Note that it will append an extra parameter to the form, called refresh, in order to tell the action that it&#8217;s only updating the boxes, and not actually submitting the form. Also, when the call is finished, it will update the #address (div container defined in editSuccess.php template file) element with the response received.</p>
<p>Now, the only piece missing to make this work is the actual edit action, that will handle both form submission and boxes update. </p>
<p>actions.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> 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: #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>
  				<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></div></div>

<p>Again, this action is not much different from a common edit action, but there are some extra code to handle the box update. At first, we extract selected country, state and city from the parameters array and populate the user object with these values. This step is needed in order to make the criterias (defined in the form) to work, as it fetches data from the object. Also, we validate these data in order to ensure that selected state belongs to selected country, and that selected city belongs to selected state (well, I guess this can be removed as the criterias will filter it, but I&#8217;ll leave it as I didnt test &#8211; another point to improve). Another change is the check for the refresh parameter. If it&#8217;s set to Y, we skip form validation and just render the _address_edit partial. This partial will be received by the ajax call and will update the form with new select boxes values. Another small detail on this sample is the error handling. After validation, if there&#8217;s any error, I get the list of error messages and create an array with these values, then send it to the template, that in turn will render a unordered list with the messages. I did this because this form has a special design and putting the error messages together with the fields would mess the box design.</p>
<p>Well, that&#8217;s it, now you have the form working. There are some things that can be done in order to improve user experience. Actually experience told me that it MUST be done. One thing is to disable ALL boxes as soon as the user changes it&#8217;s value and only re-enabling after update is finished. Also, you can add an ajax indicator somewhere to tell the user that it&#8217;s still working. If you don&#8217;t do this, it&#8217;s most likely that users will get confused with the boxes (and they WILL, trust me, hehe). </p>
<p>This small tutorial maybe looks a bit confuse, with lots of code with not much explanation, but I hope this can be useful for you. It would be nice to hear feedback from the readers, specially comments about how to improve the form (I&#8217;m not really an symfony expert). </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2008/10/26/countrystatecity-picker-in-symfony-11/feed/</wfw:commentRss>
		<slash:comments>38</slash:comments>
		</item>
		<item>
		<title>Overlabel with Prototype</title>
		<link>http://blog.barros.ws/2008/07/30/overlabel-with-prototype/</link>
		<comments>http://blog.barros.ws/2008/07/30/overlabel-with-prototype/#comments</comments>
		<pubDate>Thu, 31 Jul 2008 00:44:19 +0000</pubDate>
		<dc:creator>Carlos Barros</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[overlabel]]></category>
		<category><![CDATA[prototype]]></category>

		<guid isPermaLink="false">http://blog.barros.ws/?p=37</guid>
		<description><![CDATA[Some time ago I was searching for some overlabel script to use in a project and found a great script, created by Mike Brittain (here), and since then I&#8217;ve used this script in all my projects. But last week I was working in a project that uses Prototype library and I wondered if there was [...]]]></description>
			<content:encoded><![CDATA[<p>Some time ago I was searching for some overlabel script to use in a project and found a great script, created by Mike Brittain (<a href="http://alistapart.com/articles/makingcompactformsmoreaccessible">here</a>), and since then I&#8217;ve used this script in all my projects. But last week I was working in a project that uses <a href="http://www.prototypejs.org/">Prototype</a> library and I wondered if there was an overlabel plugin for prototype. After some time googling about the subject, I only came up with a <a href="http://jquery.com/">JQuery</a> plugin (<a href="http://scott.sauyet.com/thoughts/archives/2007/03/31/overlabel-with-jquery/">here</a>), that is a port of Mike Brittain script to JQuery library. So, as I didn&#8217;t find what I was looking for, I decided to make my own port and created a prototype plugin. This took me less than 15 minutes to get a working version of it.</p>
<p>This is the resulting code:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> overLabelPlugin <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
 overlabel<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>obj<span style="color: #009900;">&#41;</span>
 <span style="color: #009900;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span>  field<span style="color: #339933;">;</span>
&nbsp;
  obj <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>obj<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// check for attribute</span>
  <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>obj.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'for'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span>
   <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>field <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span>obj.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'for'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// apply overlabel style</span>
  obj.<span style="color: #660066;">className</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">'overlabel-apply'</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>field.<span style="color: #660066;">value</span> <span style="color: #339933;">!=</span> <span style="color: #3366CC;">''</span><span style="color: #009900;">&#41;</span>
   $$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'label[for='</span><span style="color: #339933;">+</span>$<span style="color: #009900;">&#40;</span>field<span style="color: #009900;">&#41;</span>.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">']'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">invoke</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'hide'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #006600; font-style: italic;">// setup event handlers</span>
  field.<span style="color: #000066;">onfocus</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   $$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'label[for='</span><span style="color: #339933;">+</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">']'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">invoke</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'hide'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  field.<span style="color: #000066;">onblur</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">value</span> <span style="color: #339933;">===</span> <span style="color: #3366CC;">''</span><span style="color: #009900;">&#41;</span>
    $$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'label[for='</span><span style="color: #339933;">+</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">']'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">invoke</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'show'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  obj.<span style="color: #660066;">onclick</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
   $<span style="color: #009900;">&#40;</span>$<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">readAttribute</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'for'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #000066;">focus</span><span style="color: #009900;">&#40;</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: #009900;">&#125;</span>
&nbsp;
Event.<span style="color: #660066;">observe</span><span style="color: #009900;">&#40;</span>window<span style="color: #339933;">,</span><span style="color: #3366CC;">'load'</span><span style="color: #339933;">,</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
 Element.<span style="color: #660066;">addMethods</span><span style="color: #009900;">&#40;</span>overLabelPlugin<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The only change I made to the original technique was the usage of hide() and show() instead of <em>text-ident:-1000px;</em> to hide/show overlabels.</p>
<p>To activate overlabel, you can do something like:</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">html</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">title</span>&gt;</span>Overlabel with Prototype<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">title</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">style</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/css&quot;</span>&gt;</span>
  label.overlabel-apply {
    position:absolute;
    top:3px;
    left:5px;
    z-index:1;
    color:#999;
    font-family:verdana serif sans-serif;
    font-size:10pt;
  }
  div.overlabel_container {
    position:relative;
  }
  <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>stype&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;prototype.js&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;overlabel.js&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">script</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text/javascript&quot;</span>&gt;</span>
  Event.observe(window,'load',function ()
  {
   $$('.overlabel').invoke('overlabel');
  });&gt;
&nbsp;
  <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">script</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">head</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;overlabel_container&quot;</span>&gt;</span>
   <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">label</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;overlabel&quot;</span> <span style="color: #000066;">for</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;uname&quot;</span>&gt;</span>Username<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">label</span>&gt;</span>
   <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">input</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;uname&quot;</span> <span style="color: #000066;">name</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;uname&quot;</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;text&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span>
  <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span>
 <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">body</span>&gt;</span>
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">html</span>&gt;</span></pre></div></div>

<p>I&#8217;m by no means a Prototype expert, so if there&#8217;s some better way to do this, please let me know. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.barros.ws/2008/07/30/overlabel-with-prototype/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
