<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>symfony 1.x scales and arpeggios</title>
	<atom:link href="http://arpeggios.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://arpeggios.wordpress.com</link>
	<description>A symfony 1.x development blog by Nicolas Martin</description>
	<lastBuildDate>Wed, 07 Dec 2011 16:22:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='arpeggios.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>symfony 1.x scales and arpeggios</title>
		<link>http://arpeggios.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://arpeggios.wordpress.com/osd.xml" title="symfony 1.x scales and arpeggios" />
	<atom:link rel='hub' href='http://arpeggios.wordpress.com/?pushpress=hub'/>
		<item>
		<title>[REFACTORED] Enabling pagination with raw SQL queries</title>
		<link>http://arpeggios.wordpress.com/2009/08/27/refactored-enabling-pagination-with-raw-sql-queries/</link>
		<comments>http://arpeggios.wordpress.com/2009/08/27/refactored-enabling-pagination-with-raw-sql-queries/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 17:15:05 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Arpeggios]]></category>
		<category><![CDATA[pagination]]></category>
		<category><![CDATA[propel]]></category>
		<category><![CDATA[refactoring]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=639</guid>
		<description><![CDATA[In my previous post, I explained how to use sfPager to paginate through raw SQL queries, introducing the statementPager class. Even if this class helped me to solve problems, I&#8217;ve never been so proud of it since this class does not behave like a real pager. In fact, I should have named it statementChunker. In [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=639&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In my previous <a href="http://arpeggios.wordpress.com/2009/02/02/enabling-pagination-with-raw-sql-queries">post</a>, I explained how to use sfPager to paginate through raw SQL queries, introducing the statementPager class.</p>
<p>Even if this class helped me to solve problems, I&#8217;ve never been so proud of it since this class does not behave like a real pager. In fact, I should have named it statementChunker.</p>
<p>In order to paginate through resultsets, the class have to  fetch all resultsets until we reach the desired page, only returning an array of  corresponding resultsets. So this class doesn&#8217;t really &#8216;paginate&#8217;, resulting a memory outage when working with large resulsets.</p>
<p>Here is a typical complex query I want to paginate, done the statementPager way :</p>
<pre><span class="Special">&lt;?php</span>

<span class="phpVarSelector">$</span><span class="Identifier">connection</span> <span class="phpOperator">=</span> Propel<span class="phpOperator">::</span>getConnection<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">query</span> <span class="phpOperator">=</span> '<span class="Constant">SELECT SUBSTRING_INDEX(field, "/", 1) AS field </span>
<span class="Constant">FROM table </span>
<span class="Constant">WHERE other_field LIKE </span>'<span class="phpOperator">%</span>pattern<span class="phpOperator">%</span>'<span class="Constant"> </span>
<span class="Constant">GROUP BY field </span>
<span class="Constant">ORDER BY sub</span>';
<span class="phpVarSelector">$</span><span class="Identifier">statement</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">connection</span><span class="phpMemberSelector">-&gt;</span>prepare<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">query</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> statementPager<span class="phpParent">(</span><span class="Type">null</span>, <span class="Number">10</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>setStatement<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">statement</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>setPage<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">request</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">page</span>', <span class="Number">1</span><span class="phpParent">))</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>init<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">results</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>getResults<span class="phpParent">()</span>;</pre>
<p>I recently discovered that Propel allows you build custom criterias. I&#8217;ve got everything out-of-the-box to run the same query the Propel way, with native SQL pagination :</p>
<pre><span class="Special">&lt;?php</span>

<span class="phpVarSelector">$</span><span class="Identifier">c</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> Criteria;
<span class="phpVarSelector">$</span><span class="Identifier">c</span><span class="phpMemberSelector">-&gt;</span><span class="Function">add</span><span class="phpParent">(</span>TablePeer<span class="phpOperator">::</span>FIELD, '<span class="Constant">%pattern%</span>', Criteria<span class="phpOperator">::</span>LIKE<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">c</span><span class="phpMemberSelector">-&gt;</span>addAsColumn<span class="phpParent">(</span>'<span class="Constant">field</span>', '<span class="Constant">SUBSTRING_INDEX(</span>'<span class="phpOperator">.</span>TablePeer<span class="phpOperator">::</span>FIELD<span class="phpOperator">.</span>'<span class="Constant">, "/", 1) AS field</span>'<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">c</span><span class="phpMemberSelector">-&gt;</span>addDescendingOrderByColumn<span class="phpParent">(</span>'<span class="Constant">sub</span>'<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">c</span><span class="phpMemberSelector">-&gt;</span>addGroupByColumn<span class="phpParent">(</span>'<span class="Constant">field</span>'<span class="phpParent">)</span>;

<span class="phpVarSelector">$</span><span class="Identifier">pager</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> sfPropelPager<span class="phpParent">(</span>'<span class="Constant">Table</span>', <span class="Number">20</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>setCriteria<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">c</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>setPeerMethod<span class="phpParent">(</span>'<span class="Constant">doSelectStmt</span>'<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>setPage<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">request</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">page</span>', <span class="Number">1</span><span class="phpParent">))</span>;
<span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>init<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">results</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>getResults<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>fetchAll<span class="phpParent">()</span>;</pre>
<p>That&#8217;s a pretty valuable refactoring session : one class less to maintain and a performance boost as an outcome ! (and also a good lesson in humility)</p>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">$this-&gt;pager = new statementPager(null, 20);</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">$this-&gt;pager-&gt;setStatement($this-&gt;statement);</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">$this-&gt;pager-&gt;setPage($request-&gt;getParameter(&#8216;page&#8217;, 1));</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">$this-&gt;pager-&gt;init();</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/639/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/639/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/639/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=639&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2009/08/27/refactored-enabling-pagination-with-raw-sql-queries/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Enabling pagination with raw SQL queries</title>
		<link>http://arpeggios.wordpress.com/2009/02/02/enabling-pagination-with-raw-sql-queries/</link>
		<comments>http://arpeggios.wordpress.com/2009/02/02/enabling-pagination-with-raw-sql-queries/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 19:49:38 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Arpeggios]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[pager]]></category>
		<category><![CDATA[propel]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=584</guid>
		<description><![CDATA[sfPager is an abstract class that lets you deal with pagination at a high level. The symfony core comes with two concrete implementations of sfPager : sfPropelPager and sfDoctrinePager (one for each ORM). The benefit of this abstraction is that you can reuse the business-logic of pagination and apply it to anything, without reinventing the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=584&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>sfPager is an abstract class that lets you deal with pagination at a high level. The symfony core comes with two concrete implementations of sfPager : sfPropelPager and sfDoctrinePager (one for each ORM).</p>
<p>The benefit of this abstraction is that you can reuse the business-logic of pagination and apply it to anything, without reinventing the wheel.</p>
<p><a href="http://snippets.symfony-project.org/snippets/from/scottmeves/order_by/date">Scott Meves</a> have already submitted a <a href="http://snippets.symfony-project.org/snippet/177">snippet</a> in which he explains how to extend the sfPager class to paginate an array.</p>
<h4>Raw SQL</h4>
<p>Whatever you use Propel or Doctrine, it is sometimes needed to write raw SQL queries.</p>
<pre class="php"><span class="phpVarSelector">$</span><span class="Identifier">connection</span> <span class="phpOperator">=</span> Propel<span class="phpOperator">::</span>getConnection<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">query</span> <span class="phpOperator">=</span> '<span class="Constant">SELECT MAX(%s) AS max FROM %s</span>';
<span class="phpVarSelector">$</span><span class="Identifier">query</span> <span class="phpOperator">=</span> <span class="phpFunctions">sprintf</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">query</span>, ArticlePeer<span class="phpOperator">::</span>CREATED_AT, ArticlePeer<span class="phpOperator">::</span>TABLE_NAME<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">statement</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">connection</span><span class="phpMemberSelector">-&gt;</span>prepare<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">query</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">statement</span><span class="phpMemberSelector">-&gt;</span>execute<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">resultset</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">statement</span><span class="phpMemberSelector">-&gt;</span>fetch<span class="phpParent">(</span><span class="phpFunctions">PDO</span><span class="phpOperator">::</span>FETCH_OBJ<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">max</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">resultset</span><span class="phpMemberSelector">-&gt;</span>max;</pre>
<p>When you do so, you loose all the relation object mapping. Besides, you cannot use any of the sf*Pager anymore.</p>
<p>Nevertheless, both Propel and Doctrine are based on PDO. It means that using raw queries doesn&#8217;t mean bypassing database abstraction. When you execute a query, you still retrieve a collection of PDOResulset objects, which are &#8216;abstract&#8217; representations of database entries.</p>
<h4>the statementPager class</h4>
<p>Let&#8217;s create a custom pager to paginate this collection (an array of objects) :</p>
<pre class="php"><span class="Type">class</span> statementPager <span class="Type">extends</span> sfPager
<span class="phpParent">{</span>
  <span class="Type">protected</span> <span class="phpVarSelector">$</span><span class="Identifier">resultsetArray</span> <span class="phpOperator">=</span> <span class="Type">array</span><span class="phpParent">()</span>;

  <span class="Type">public</span> <span class="PreProc">function</span> <span class="phpOperator">__construct</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">class</span> <span class="phpOperator">=</span> <span class="Type">null</span>, <span class="phpVarSelector">$</span><span class="Identifier">maxPerPage</span> <span class="phpOperator">=</span> <span class="Number">10</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="Type">parent</span><span class="phpOperator">::</span><span class="phpOperator">__construct</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">class</span>, <span class="phpVarSelector">$</span><span class="Identifier">maxPerPage</span><span class="phpParent">)</span>;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> setStatement<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">statement</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">statement</span>;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> init<span class="phpParent">()</span>
  <span class="phpParent">{</span>
    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement<span class="phpMemberSelector">-&gt;</span>execute<span class="phpParent">()</span>;

    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>setNbResults<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement<span class="phpMemberSelector">-&gt;</span>rowCount<span class="phpParent">())</span>;

    <span class="Statement">if</span> <span class="phpParent">((</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getPage<span class="phpParent">()</span> <span class="Statement">==</span> <span class="Number">0</span> <span class="phpOperator">||</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()</span> <span class="Statement">==</span> <span class="Number">0</span><span class="phpParent">))</span>
    <span class="phpParent">{</span>
     <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>setLastPage<span class="phpParent">(</span><span class="Number">0</span><span class="phpParent">)</span>;
    <span class="phpParent">}</span>
    <span class="Statement">else</span>
    <span class="phpParent">{</span>
     <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>setLastPage<span class="phpParent">(</span><span class="phpFunctions">ceil</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getNbResults<span class="phpParent">()</span> <span class="phpOperator">/</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()))</span>;
    <span class="phpParent">}</span>
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> getResults<span class="phpParent">()</span>
  <span class="phpParent">{</span>

    <span class="Statement">if</span> <span class="phpParent">((</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getPage<span class="phpParent">()</span> <span class="Statement">==</span> <span class="Number">0</span> <span class="phpOperator">||</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()</span> <span class="Statement">==</span> <span class="Number">0</span><span class="phpParent">))</span>
    <span class="phpParent">{</span>
      <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>setLastPage<span class="phpParent">(</span><span class="Number">0</span><span class="phpParent">)</span>;
    <span class="phpParent">}</span>
    <span class="Statement">else</span>
    <span class="phpParent">{</span>
      <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>setLastPage<span class="phpParent">(</span><span class="phpFunctions">ceil</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getNbResults<span class="phpParent">()</span> <span class="phpOperator">/</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()))</span>;
    <span class="phpParent">}</span>

    <span class="phpVarSelector">$</span><span class="Identifier">row_num</span> <span class="phpOperator">=</span> <span class="Number">1</span>;
    <span class="Statement">while</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">resultset</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement<span class="phpMemberSelector">-&gt;</span>fetch<span class="phpParent">(</span><span class="phpFunctions">PDO</span><span class="phpOperator">::</span>FETCH_OBJ<span class="phpParent">))</span>
    <span class="phpParent">{</span>
      <span class="Statement">if</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">row_num</span> <span class="Statement">&gt;</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()</span><span class="phpOperator">*</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getPage<span class="phpParent">()</span><span class="Number">-1</span><span class="phpParent">)</span>
      <span class="phpOperator">and</span> <span class="phpVarSelector">$</span><span class="Identifier">row_num</span> <span class="Statement">&lt;=</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getPage<span class="phpParent">()</span><span class="phpOperator">*</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getMaxPerPage<span class="phpParent">()</span> <span class="phpParent">))</span>
      <span class="phpParent">{</span>
        <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>resultsetArray<span class="phpParent">[]</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">resultset</span>;
      <span class="phpParent">}</span>
      <span class="phpVarSelector">$</span><span class="Identifier">row_num</span><span class="phpOperator">++</span>;
    <span class="phpParent">}</span>

    <span class="Statement">return</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>resultsetArray;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> retrieveObject<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">offset</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="Statement">return</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>resultsetArray<span class="phpParent">[</span><span class="phpVarSelector">$</span><span class="Identifier">offset</span><span class="phpParent">]</span>;

  <span class="phpParent">}</span>
<span class="phpParent">}</span></pre>
<p>To avoid populating a big array with all resultsets (which is the current limitation of the <a href="http://snippets.symfony-project.org/snippet/177">snippet</a>), we only stack those that match with the current page range ( simulating the limit/offset behavior of a SQL query). This is not an optimal solution, but it really helps keeping memory usage low since the $resultset variable is overwritten on each pass.</p>
<p>To initialize the pager, simply pass a PDOStatement instance to the pager after preparing the query :</p>
<pre><span class="phpVarSelector">$</span><span class="Identifier">connection</span> <span class="phpOperator">=</span> Propel<span class="phpOperator">::</span>getConnection<span class="phpParent">(</span>CampainPeer<span class="phpOperator">::</span>DATABASE_NAME, Propel<span class="phpOperator">::</span>CONNECTION_READ<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">query</span> <span class="phpOperator">=</span> '<span class="Constant">SELECT COUNT(l.id) AS cnt, column AS custom_column</span>
<span class="Constant">FROM table c</span>
<span class="Constant">left join another_table l ON l.id=c.another_id</span>
<span class="Constant">GROUP BY c.name</span>
<span class="Constant">order by l.created_at DESC</span>';

<span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">connection</span><span class="phpMemberSelector">-&gt;</span>prepare<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">query</span><span class="phpParent">)</span>;

<span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>pager <span class="phpOperator">=</span> <span class="PreProc">new</span> statementPager<span class="phpParent">(</span><span class="Type">null</span>, <span class="Number">10</span><span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>pager<span class="phpMemberSelector">-&gt;</span>setStatement<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>statement<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>pager<span class="phpMemberSelector">-&gt;</span>setPage<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">request</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">page</span>', <span class="Number">1</span><span class="phpParent">))</span>;
<span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>pager<span class="phpMemberSelector">-&gt;</span>init<span class="phpParent">()</span>;</pre>
<p>The pager is now initialized and can be used just like any pager :</p>
<pre><span class="Special">&lt;?php</span> <span class="Statement">foreach</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">pager</span><span class="phpMemberSelector">-&gt;</span>getResults<span class="phpParent">()</span> <span class="Statement">as</span> <span class="phpVarSelector">$</span><span class="Identifier">resultset</span><span class="phpParent">)</span><span class="phpOperator">:</span> <span class="Special">?&gt;</span>
  <span class="Special">&lt;?php</span> <span class="phpFunctions">print_r</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">resultset</span><span class="phpParent">)</span> <span class="Special">?&gt;</span>
<span class="Special">&lt;?php</span> <span class="Statement">endforeach</span> <span class="Special">?&gt;</span></pre>
<p>Will output 10 resultsets :</p>
<pre>stdClass Object
(
  [cnt] =&gt; 1
  [custom_column] =&gt; 526
)
stdClass Object
(
  [cnt] =&gt; 3
  [custom_column] =&gt; 527
)
stdClass Object
(
  [cnt] =&gt; 0
  [custom_column] =&gt; 123
)
stdClass Object
(
  [cnt] =&gt; 0
  [custom_column] =&gt; 187
)
stdClass Object
(
  [cnt] =&gt; 1
  [custom_column] =&gt; 109
)
stdClass Object
(
  [cnt] =&gt; 1
  [custom_column] =&gt; 526
)
stdClass Object
(
  [cnt] =&gt; 3
  [custom_column] =&gt; 527
)
stdClass Object
(
  [cnt] =&gt; 3444
  [custom_column] =&gt; 456
)
stdClass Object
(
  [cnt] =&gt; 110
  [custom_column] =&gt; 789
)
stdClass Object
(
  [cnt] =&gt; 220
  [custom_column] =&gt; 101
)</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/584/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/584/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/584/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=584&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2009/02/02/enabling-pagination-with-raw-sql-queries/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Developement-Driven Tests</title>
		<link>http://arpeggios.wordpress.com/2008/12/17/developement-driven-tests/</link>
		<comments>http://arpeggios.wordpress.com/2008/12/17/developement-driven-tests/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 20:21:14 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=541</guid>
		<description><![CDATA[TDD is one of the best practices that symfony promotes. The main reason that many PHP developers don&#8217;t invest earlier into testing solutions is that TDD deals with practice, not knowledge of a particular language or framework. Learning a test framework and how to write unit and functional tests is quite easy. Build an automated [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=541&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a title="Test-Driven Development" href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> is one of the best practices that symfony promotes.</p>
<p>The main reason that many PHP developers don&#8217;t invest earlier into testing solutions is that TDD deals with <em>practice</em>, not <em>knowledge</em> of a particular language or framework.</p>
<p>Learning a test framework and how to write unit and functional tests is quite easy. Build an automated testing solutions is pretty easy too. It just takes some time.</p>
<p>The most difficult part is to learn how to set up good habits in your daily job, which includes :</p>
<ul>
<li>Writing relevant tests</li>
<li>Writing testable code</li>
<li>Running tests automatically</li>
</ul>
<p>It&#8217;s pretty easy to miss one of these steps during development and fall into the evil counterpart of Test-Driven Development methodology :  <strong>Development-Driven Tests</strong>, whose workflow can be compared to the old-fashioned and non-agile <a href="http://en.wikipedia.org/wiki/Waterfall_model">Waterfall</a> model.</p>
<p>Here are some practices to avoid if you don&#8217;t want to fall into DDT :</p>
<ul>
<li><strong>Writing tests after the code is finished</strong></li>
</ul>
<p>If you write the tests after the code, you are likely to treat testing as a constraining process. Your are pretty sure that your class is working, so why should you write test it now right ?</p>
<p>At that point, you will probably want to test only working functionalities, make sure that every test you write passes and that nothing fails at any moment. After all, your code is finished so you don&#8217;t want to push it too further and hurt it. That&#8217;s Development-Driven Test !</p>
<p>The purpose of TDD is exactly the opposite : Put the code under extreme conditions (edge cases and invalid data) and make sure that failures are handled correctly. Only then should you assert that the class is working under normal conditions.</p>
<p>Tests must be written before any<em> functional</em> code. That forces you to <em>&#8220;program to an interface, not an implementation.&#8221;</em></p>
<p>Here&#8217;s a useful hint to quickly step into test writing :  Uses the lime::todo() method to write the test-suite roadmap in plain english, and write tests step by step afterward :</p>
<pre><span class="phpVarSelector">$</span><span class="Identifier">t</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> lime_test<span class="phpParent">(</span><span class="Number">3</span>, <span class="PreProc">new</span> lime_output_color<span class="phpParent">())</span>;

<span class="phpVarSelector">$</span><span class="Identifier">t</span><span class="phpMemberSelector">-&gt;</span>todo<span class="phpParent">(</span>"<span class="Constant">Test if the class::method() with invalid data throws an exception</span>"<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">t</span><span class="phpMemberSelector">-&gt;</span>todo<span class="phpParent">(</span>"<span class="Constant">Test the class::method2() with missing parameter uses default values</span>"<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">t</span><span class="phpMemberSelector">-&gt;</span>todo<span class="phpParent">(</span>"<span class="Constant">Test the class::method3() returns an valid array with valid parameter</span>"<span class="phpParent">)</span>;</pre>
<ul>
<li><strong>Updating tests after fixing a bug</strong></li>
</ul>
<p>When a bug is reported, the first thing to do is to reproduce it in the test environment. Once the bug is clearly identified and reproduced in isolation, the test suite must fail explicitly :</p>
<pre><span class="phpVarSelector">$</span><span class="Identifier">t</span><span class="phpMemberSelector">-&gt;</span>diag<span class="phpParent">(</span>'<span class="Constant">Testing class::method() with new invalid data</span>'<span class="phpParent">)</span>;
<span class="phpVarSelector">$</span><span class="Identifier">input_data</span> <span class="phpOperator">=</span> "<span class="Constant">%data</span>";
<span class="phpVarSelector">$</span><span class="Identifier">t</span><span class="phpMemberSelector">-&gt;</span>is<span class="phpParent">(</span><span class="Type">class</span><span class="phpOperator">::</span>method<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">input_data</span><span class="phpParent">)</span>, <span class="Constant">true</span>, "<span class="Constant">'%' should be handled</span>"<span class="phpParent">)</span>;</pre>
<p>Now, you can modify the code in order to make the test suite pass again.</p>
<h4>Testing in the real world</h4>
<p>To bring TDD in your daily development is definitely not an easy task. Fortunately, the symfony platform provides a complete toolkit to help you dive into testing :</p>
<ul>
<li>environments</li>
<li>bundled test framework (lime)</li>
<li>tasks and test harnesses for automated test suites</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/541/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/541/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/541/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=541&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/12/17/developement-driven-tests/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Events functional testing</title>
		<link>http://arpeggios.wordpress.com/2008/11/12/events-functional-testing/</link>
		<comments>http://arpeggios.wordpress.com/2008/11/12/events-functional-testing/#comments</comments>
		<pubDate>Wed, 12 Nov 2008 17:45:13 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Solfège]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=483</guid>
		<description><![CDATA[Like many components of the framework, Events are highly testable. A real world example : an email logger, which I already covered here. We want to test the integration of this functionality throughout the application. A good practice in OOP is to decouple the logic from the implementation. Both must be isolated : Unit testing [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=483&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><span style="font-weight:normal;">Like many components of the framework, <a href="http://www.symfony-project.org/book/1_1/17-Extending-Symfony#Events">Events</a> are highly testable.</span></p>
<p>A real world example : an email logger, which I already covered <a href="http://arpeggios.wordpress.com/2008/08/18/creating-a-mail-logger-with-swift/">here</a>. We want to test the integration of this functionality throughout the application.</p>
<p>A good practice in OOP is to decouple the logic from the implementation. Both must be isolated : Unit testing (white box) for the implementation, and functional testing (black box) for the logic.</p>
<p>You may wonder, what belongs to unit or functional testing ?</p>
<p>To understand the difference, let&#8217;s ask the good questions :</p>
<blockquote><p>In my code, does the email class generates emails from templates correctly, using my SMTP server with SSL encryption ?</p></blockquote>
<p>This is pure implementation matters. I have to mock some classes, generate mock email, test config files, and even send it to myself to see if the it works. If I use native sendmail, we must check whether the program is running on the hosting server, that the server is actually reachable etc.</p>
<p>To answer these questions, write Unit Tests.</p>
<blockquote>
<p style="text-align:left;">In my application, does an email is sent to the author when he updates an article ?</p>
</blockquote>
<p>Now we talk business logic. Whatever library or server used behind, we just want to make sure that the application fulfills its functional requirements. During this test, we assume that the underlying email mechanism simply works in all cases, with every sending strategy unit-tested in isolation.</p>
<p>To answer this one, which involves more than one step to complete, write a Functional Test.</p>
<h4><span style="font-weight:normal;">Implementation example</span></h4>
<p>Suppose that our application registers a &#8216;mail.log&#8217; listener that will handle the email processing and sending when notified.</p>
<p>The listener for &#8216;mail.log&#8217; events is registered in the application configuration class. This is where all the email sending implementation is done :</p>
<pre><span class="Type">class</span> backendConfiguration <span class="Type">extends</span> sfApplicationConfiguration
<span class="phpParent">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> configure<span class="phpParent">()</span>
  <span class="phpParent">{</span>
     <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>dispatcher<span class="phpMemberSelector">-&gt;</span>connect<span class="phpParent">(</span>'<span class="Constant">mail.log</span>', <span class="Type">array</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span>, '<span class="Constant">listenToMailLog</span>'<span class="phpParent">))</span>;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> listenToMailLog<span class="phpParent">(</span>sfEvent <span class="phpVarSelector">$</span><span class="Identifier">event</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="Statement">if</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getEnvironment<span class="phpParent">()</span> <span class="Statement">==</span> '<span class="Constant">prod</span>'<span class="phpParent">)</span>
    <span class="phpParent">{</span>
      <span class="phpVarSelector">$</span><span class="Identifier">connection</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> Swift_Connection_SMTP<span class="phpParent">(</span>'<span class="Constant">smtp.domain.com</span>'<span class="phpParent">)</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">mailer</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> Swift<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">connection</span><span class="phpParent">)</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">recipients</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> Swift_RecipientList<span class="phpParent">()</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">recipients</span><span class="phpMemberSelector">-&gt;</span>addTo<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">event</span><span class="phpParent">[</span>'<span class="Constant">to</span>'<span class="phpParent">])</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">message</span>    <span class="phpOperator">=</span> <span class="PreProc">new</span> Swift_Message<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">event</span><span class="phpParent">[</span>'<span class="Constant">subject</span>'<span class="phpParent">]</span>, <span class="phpVarSelector">$</span><span class="Identifier">event</span><span class="phpParent">[</span>'<span class="Constant">body</span>'<span class="phpParent">]</span>, '<span class="Constant">text/html</span>'<span class="phpParent">)</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">mailer</span><span class="phpMemberSelector">-&gt;</span>send<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">message</span>, <span class="phpVarSelector">$</span><span class="Identifier">recipients</span>, <span class="phpVarSelector">$</span><span class="Identifier">smtp_config</span><span class="phpParent">[</span>'<span class="Constant">sender</span>'<span class="phpParent">])</span>;
    <span class="phpParent">}</span>
  <span class="phpParent">}</span>
<span class="phpParent">}</span></pre>
<p>Note : To go even further, you can imagine some emailLogger classes that implement several strategies of email generation and sending.</p>
<p><span style="font-weight:normal;">Here is the code to use when we want to send an email  :</span></p>
<pre><span class="Type">class</span> articleActions <span class="Type">extends</span> sfActions
<span class="phpParent">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> executeUpdate<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">request</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>

    <span class="Comment">// Update code here...</span>

    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getContext<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>getEventDispatcher<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>notify<span class="phpParent">(</span><span class="PreProc">new</span> sfEvent<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span>, '<span class="Constant">mail.log</span>', <span class="Type">array</span><span class="phpParent">(</span>
      '<span class="Constant">subject</span>' <span class="phpOperator">=</span><span class="phpRelation">&gt;</span> '<span class="Constant">[ARTICLE UPDATE]</span>',
      '<span class="Constant">body</span>' <span class="phpOperator">=</span><span class="phpRelation">&gt;</span> 'You have updated the article&gt;',
      '<span class="Constant">to</span>' <span class="phpOperator">=</span><span class="phpRelation">&gt;</span> '<span class="Constant">me@domain.com</span>'
    <span class="phpParent">)))</span>;
  <span class="phpParent">}</span>
<span class="phpParent">}</span></pre>
<h4>Testing the event</h4>
<p>Let&#8217;s create a simple event listener for test purposes. During the test sequence, we want to catch all the notified &#8216;mail.log&#8217; events, and check if they match some expectations :</p>
<pre><span class="PreProc">include</span><span class="phpParent">(</span><span class="phpFunctions">dirname</span><span class="phpParent">(</span><span class="Constant">__FILE__</span><span class="phpParent">)</span><span class="phpOperator">.</span>'<span class="Constant">/../../bootstrap/functional.php</span>'<span class="phpParent">)</span>;

<span class="Type">class</span> mockEventListener
<span class="phpParent">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> <span class="phpOperator">__construct</span><span class="phpParent">()</span>
  <span class="phpParent">{</span>
    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>event <span class="phpOperator">=</span> <span class="PreProc">new</span> sfEvent<span class="phpParent">(</span><span class="Type">null</span>, <span class="Type">null</span><span class="phpParent">)</span>;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> listenToMailLog<span class="phpParent">(</span>sfEvent <span class="phpVarSelector">$</span><span class="Identifier">event</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>event <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">event</span>;
  <span class="phpParent">}</span>

  <span class="Type">public</span> <span class="PreProc">function</span> getLastEvent<span class="phpParent">()</span>
  <span class="phpParent">{</span>
    <span class="phpVarSelector">$</span><span class="Identifier">last_event</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>event;
    <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>event <span class="phpOperator">=</span> <span class="PreProc">new</span> sfEvent<span class="phpParent">(</span><span class="Type">null</span>, <span class="Type">null</span><span class="phpParent">)</span>;
    <span class="Statement">return</span> <span class="phpVarSelector">$</span><span class="Identifier">last_event</span>;
  <span class="phpParent">}</span>
<span class="phpParent">}</span>

<span class="phpVarSelector">$</span><span class="Identifier">mockEventListener</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> mockEventListener;

<span class="phpVarSelector">$</span><span class="Identifier">dispatcher</span> <span class="phpOperator">=</span> sfContext<span class="phpOperator">::</span>getInstance<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>getEventDispatcher<span class="phpParent">()</span>;
<span class="phpVarSelector">$</span><span class="Identifier">dispatcher</span><span class="phpMemberSelector">-&gt;</span>connect<span class="phpParent">(</span>'<span class="Constant">mail.log</span>', <span class="Type">array</span><span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">mockEventListener</span>, '<span class="Constant">listenToMailLog</span>'<span class="phpParent">))</span>;

<span class="phpVarSelector">$</span><span class="Identifier">browser</span> <span class="phpOperator">=</span> <span class="PreProc">new</span> sfTestBrowser<span class="phpParent">()</span>;

<span class="phpVarSelector">$</span><span class="Identifier">browser</span><span class="phpMemberSelector">-&gt;</span>post<span class="phpParent">(</span>'<span class="Constant">/article/update</span>', <span class="Type">array</span><span class="phpParent">(</span>'<span class="Constant">title</span>' <span class="phpOperator">=</span><span class="phpRelation">&gt;</span> '<span class="Constant">newtitle</span>'<span class="phpParent">))</span><span class="phpOperator">-</span><span class="phpRelation">&gt;</span>
  isRequestParameter<span class="phpParent">(</span>'<span class="Constant">module</span>', '<span class="Constant">article</span>'<span class="phpParent">)</span><span class="phpOperator">-</span><span class="phpRelation">&gt;</span>
  isRequestParameter<span class="phpParent">(</span>'<span class="Constant">action</span>', '<span class="Constant">update</span>'<span class="phpParent">)</span>;

<span class="phpVarSelector">$</span><span class="Identifier">last_event</span> <span class="phpOperator">=</span> <span class="phpVarSelector">$</span><span class="Identifier">mockEventListener</span><span class="phpMemberSelector">-&gt;</span>getLastEvent<span class="phpParent">()</span>;

<span class="phpVarSelector">$</span><span class="Identifier">browser</span><span class="phpMemberSelector">-&gt;</span>test<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>is<span class="phpParent">(</span>
  <span class="phpVarSelector">$</span><span class="Identifier">last_event</span><span class="phpMemberSelector">-&gt;</span>getName<span class="phpParent">()</span>,
  '<span class="Constant">mail.log</span>',
  '<span class="Constant">An "email.log" event should have been notified</span>'
<span class="phpParent">)</span>;

<span class="phpVarSelector">$</span><span class="Identifier">browser</span><span class="phpMemberSelector">-&gt;</span>test<span class="phpParent">()</span><span class="phpMemberSelector">-&gt;</span>is<span class="phpParent">(</span>
  <span class="phpVarSelector">$</span><span class="Identifier">last_event</span><span class="phpParent">[</span>'<span class="Constant">subject</span>'<span class="phpParent">]</span>,
  '<span class="Constant">[ARTICLE UPDATE]</span>',
  '<span class="Constant">The "subject" should be "[ARTICLE UPDATE]"</span>'
<span class="phpParent">)</span>;</pre>
<p>Let&#8217;s run the test now :</p>
<pre>$ symfony test:functional backend articleActions</pre>
<p><a href="http://arpeggios.files.wordpress.com/2008/11/image-11.png"><img class="alignnone size-full wp-image-503" title="functional" src="http://arpeggios.files.wordpress.com/2008/11/image-11.png?w=425" alt="functional"   /></a></p>
<p style="text-align:left;">As the number of tests increase, the test suite grows and it becomes a real live documentation about every functional aspects of the application.</p>
<p style="text-align:left;">
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/483/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/483/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/483/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=483&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/11/12/events-functional-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>

		<media:content url="http://arpeggios.files.wordpress.com/2008/11/image-11.png" medium="image">
			<media:title type="html">functional</media:title>
		</media:content>
	</item>
		<item>
		<title>Using a module from another project</title>
		<link>http://arpeggios.wordpress.com/2008/10/10/using-a-module-from-another-project/</link>
		<comments>http://arpeggios.wordpress.com/2008/10/10/using-a-module-from-another-project/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 13:10:32 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[context]]></category>
		<category><![CDATA[filters]]></category>
		<category><![CDATA[modules]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=417</guid>
		<description><![CDATA[The MVC paradigm, adopted in symfony from top to bottom, brings highly decoupled components meant to be used independently. In a symfony application, modules are flexible and allow complex manipulations like : forwarding to another module/action and delegate request processing rendering a module/action in isolation (like an email generation module) Unfortunately, this agility is only [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=417&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The MVC paradigm, adopted in symfony from top to bottom, brings highly decoupled components meant to be used independently.</p>
<p>In a symfony application, modules are flexible and allow complex manipulations like :</p>
<ul>
<li>forwarding to another module/action and delegate request processing</li>
<li>rendering a module/action in isolation (like an email generation module)</li>
</ul>
<p>Unfortunately, this agility is only available inside a project context. You cannot use a module from another project.</p>
<p>Here is a trick to &#8216;load&#8217; components (modules, libs, validators or whatever) from an external project.</p>
<h4>Project configurations and contexts</h4>
<p>The Application configuration object is defined early in the process chain. sfContext loads it and creates a sfContext instance for the current application.</p>
<p>Since symfony 1.1, sfContext is not a singleton anymore. It is now possible to have several context instances.</p>
<p>You can create a configuration object for the external project/application,  add a sfContext instance to the stack, and switch between them using the <em>sfContext::switchTo()</em> method.</p>
<pre>sfContext<span class="phpOperator">::</span>createInstance<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">configuration</span><span class="phpParent">)</span>
sfContext<span class="phpOperator">::</span>switchTo<span class="phpParent">(</span>'<span class="Constant">another_app</span>'<span class="phpParent">)</span>;</pre>
<h4>ExternalProjectFilter</h4>
<p>Let&#8217;s create a filter that will handle all this job early in the process chain.</p>
<p>In <em>/apps/yourapp/config/filters.yml</em>:</p>
<pre>rendering: ~
security:  ~

external:
  class: ExternalProjectFilter
  param:
    sf_root_dir: /var/www/external_project_dir
    sf_app: external_app_name
    sf_env: dev
    sf_debug: true

cache:     ~
common:    ~
execution: ~</pre>
<p>Now let&#8217;s write the ExternalProjectFilter class in <em>/lib/ExternalProjectFilter.class.php</em></p>
<pre><span class="Type">class</span> ExternalProjectFilter <span class="Type">extends</span> sfFilter
<span class="phpParent">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> execute<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">filterChain</span><span class="phpParent">)</span>
  <span class="phpParent">{</span>
    <span class="Statement">if</span> <span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>isFirstCall<span class="phpParent">())</span>
    <span class="phpParent">{</span>
      <span class="phpVarSelector">$</span><span class="Identifier">current_app</span> <span class="phpOperator">=</span> sfConfig<span class="phpOperator">::</span>get<span class="phpParent">(</span>'<span class="Constant">sf_app</span>'<span class="phpParent">)</span>;

      <span class="phpVarSelector">$</span><span class="Identifier">configuration</span> <span class="phpOperator">=</span> ProjectConfiguration<span class="phpOperator">::</span>getApplicationConfiguration<span class="phpParent">(</span>
        <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">sf_app</span>'<span class="phpParent">)</span>,
        <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">sf_env</span>'<span class="phpParent">)</span>,
        <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">sf_debug</span>'<span class="phpParent">)</span>,
        <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">sf_root_dir</span>'<span class="phpParent">)</span>
      <span class="phpParent">)</span>;

      <span class="Comment">// Add an instance of the external project on the current context</span>
      sfContext<span class="phpOperator">::</span>createInstance<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">configuration</span><span class="phpParent">)</span>;

      <span class="Comment">// Add the external project's database connection settings</span>
      Propel<span class="phpOperator">::</span>setConfiguration<span class="phpParent">(</span>sfPropelDatabase<span class="phpOperator">::</span>getConfiguration<span class="phpParent">())</span>;
      Propel<span class="phpOperator">::</span>initialize<span class="phpParent">()</span>;

      <span class="Comment">// Autoload external project files</span>
      <span class="phpVarSelector">$</span><span class="Identifier">autoload</span> <span class="phpOperator">=</span> sfSimpleAutoload<span class="phpOperator">::</span>getInstance<span class="phpParent">()</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">autoload</span><span class="phpMemberSelector">-&gt;</span>addDirectory<span class="phpParent">(</span> <span class="phpVarSelector">$</span><span class="Identifier">this</span><span class="phpMemberSelector">-&gt;</span>getParameter<span class="phpParent">(</span>'<span class="Constant">sf_root_dir</span>'<span class="phpParent">)</span><span class="phpOperator">.</span>'<span class="Constant">/lib</span>'<span class="phpParent">)</span>;
      <span class="phpVarSelector">$</span><span class="Identifier">autoload</span><span class="phpMemberSelector">-&gt;</span>register<span class="phpParent">()</span>;

      <span class="Comment">// Switch back to the current context</span>
      sfContext<span class="phpOperator">::</span>switchTo<span class="phpParent">(</span><span class="phpVarSelector">$</span><span class="Identifier">current_app</span><span class="phpParent">)</span>;
    <span class="phpParent">}</span>

    <span class="phpVarSelector">$</span><span class="Identifier">filterChain</span><span class="phpMemberSelector">-&gt;</span>execute<span class="phpParent">()</span>;
  <span class="phpParent">}</span>
<span class="phpParent">}</span></pre>
<h3>Example</h3>
<p>In <em>/apps/yourapp/modules/article/template/indexSuccess.php</em></p>
<pre>...
sfContext<span class="phpOperator">::</span>switchTo<span class="phpParent">(</span>'<span class="Constant">external_app_name</span>'<span class="phpParent">)</span>;
<span class="PreProc">echo</span> sfContext<span class="phpOperator">::</span>getInstance<span class="phpParent">()</span><span class="phpOperator">-</span><span class="phpRelation">&gt;</span>getController<span class="phpParent">()</span><span class="phpOperator">-</span><span class="phpRelation">&gt;</span>getPresentationFor<span class="phpParent">(</span>'<span class="Constant">customer</span>', '<span class="Constant">index</span>'<span class="phpParent">)</span>;
sfContext<span class="phpOperator">::</span>switchTo<span class="phpParent">(</span>'<span class="Constant">your_app_name</span>'<span class="phpParent">)</span>;
...</pre>
<p><a href="http://arpeggios.files.wordpress.com/2008/10/external2.jpg"><img class="alignnone size-large wp-image-438" title="external2" src="http://arpeggios.files.wordpress.com/2008/10/external2.jpg?w=450&#038;h=276" alt="" width="450" height="276" /></a></p>
<h4>Limitations</h4>
<p>Projects cannot share the same default database connection name &#8216;propel&#8217;. The trick is to explicitly name the database in your schema/databases.yml :</p>
<p><em>schema.xml</em></p>
<pre><span class="Comment">&lt;?</span><span class="htmlArg">xml</span><span class="Type"> </span><span class="htmlArg">version</span>=<span class="Constant">"1.0"</span><span class="Type"> </span><span class="htmlArg">encoding</span>=<span class="Constant">"UTF-8"</span><span class="Comment">?&gt;</span>
<span class="htmlTag">&lt;</span><span class="Function">database</span><span class="htmlTag"> </span><span class="htmlArg"><strong>name</strong></span><strong>=<span class="Constant">"project"</span></strong><span class="htmlTag"> </span><span class="htmlArg">package</span>=<span class="Constant">"lib.model"</span><span class="htmlTag"> </span><span class="htmlArg">defaultIdMethod</span>=<span class="Constant">"native"</span><span class="htmlTag"> </span><span class="htmlArg">noXsd</span>=<span class="Constant">"true"</span><span class="htmlTag">&gt;</span>
  <span class="htmlTag">&lt;</span><span class="Function">table</span><span class="htmlTag"> </span><span class="htmlArg">name</span>=<span class="Constant">"article"</span><span class="htmlTag">&gt;</span></pre>
<p><em>databases.yml</em></p>
<pre>all<span class="phpOperator">:</span>
  <strong>project</strong><span class="phpOperator">:</span>
    <span class="Type">class</span><span class="phpOperator">:</span>          sfPropelDatabase
    param<span class="phpOperator">:</span>
      dsn<span class="phpOperator">:</span>          mysql<span class="phpOperator">:</span><span class="Comment">//user:pass@host/db</span>
      encoding<span class="phpOperator">:</span>     utf8</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/417/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/417/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/417/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=417&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/10/10/using-a-module-from-another-project/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>

		<media:content url="http://arpeggios.files.wordpress.com/2008/10/external2.jpg?w=450" medium="image">
			<media:title type="html">external2</media:title>
		</media:content>
	</item>
		<item>
		<title>HTTP authentication with sfGuard</title>
		<link>http://arpeggios.wordpress.com/2008/09/28/http-authentification-with-sfguard/</link>
		<comments>http://arpeggios.wordpress.com/2008/09/28/http-authentification-with-sfguard/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 14:32:00 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Scales]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=341</guid>
		<description><![CDATA[Your application problably provides web services like a REST/SOAP API or RSS feeds. Such services are often publicly available. Nevertheless, you probably want to restrict access to these features, as the rest of the application. Since web services are meant to be programatically callable, you cannot use the standard form/post way. One common solution is [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=341&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Your application problably provides web services like a REST/SOAP API or RSS feeds. Such services are often publicly available. Nevertheless, you probably want to restrict access to these features, as the rest of the application.</p>
<p>Since web services are meant to be programatically callable, you cannot use the standard form/post way. One common solution is to to use HTTP authentication.</p>
<p>That said, it could be a good idea to use the same user restriction logic for that method.</p>
<h4>About forms</h4>
<p>In symfony 1.1 and above, the sfGuard authentification logic has moved to the bundled signin form.</p>
<p>One of the goal of the new form system, which is a full framework by itself, is to enable reuse of components.<br />
It means that the new form object now embeds the request, validation and error handling.</p>
<p>To enable a HTTP authentication form, we simply need to customize the signin form presentation, and enable HTTP as symfony&#8217;s request parameters.</p>
<h4>Example</h4>
<p>This example assumes that you have a symfony application running with sfGuard installed and set up.</p>
<p>The first thing to do is to override the default signin action of the sfGuardAuth module in the application :</p>
<pre style="font:Monospace;margin:0;padding:10px;">~apps/
 |~api/
 | |+config/
 | |+i18n/
 | |+lib/
 | `~modules/
 |   |+rss/
 |   `~sfGuardAuth/
 |     |~actions/
 |     | `-<strong>actions.class.php</strong></pre>
<p>In the signin methode, we set 401 status code to the response and add the WWW_Authenticate header, to enable HTTP authentification. Then, we simply map HTTP values to the request parameters expected by sfGuard. If user is validated, we redirect the user to the requested page :</p>
<pre><span class="Type">class</span> sfGuardAuthActions <span class="Type">extends</span> sfActions
{
  <span class="Type">public</span> <span class="PreProc">function</span> executeSignin($<span class="Identifier">request</span>)
  {
    $<span class="Identifier">user</span> = $<span class="Identifier">this</span>-&gt;getUser();

    <span class="Statement">if</span> ($<span class="Identifier">user</span>-&gt;isAuthenticated())
    {
      <span class="Statement">return</span> $<span class="Identifier">this</span>-&gt;redirect('<span class="Constant">@homepage</span>');
    }

    $<span class="Identifier">message</span> = '<span class="Constant">Authentification required</span>';

    $<span class="Identifier">this</span>-&gt;form = <span class="PreProc">new</span> sfGuardFormSignin;

    <span class="Statement">if</span> (isset($<span class="Identifier">_SERVER</span>['<span class="Constant">PHP_AUTH_USER</span>']))
    {
      $<span class="Identifier">request</span>-&gt;setParameter('<span class="Constant">signin</span>', <span class="Type">array</span>(
        '<span class="Constant">username</span>' =&gt;$<span class="Identifier">_SERVER</span>['<span class="Constant">PHP_AUTH_USER</span>'],
        '<span class="Constant">password</span>' =&gt;$<span class="Identifier">_SERVER</span>['<span class="Constant">PHP_AUTH_PW</span>'],
      ));

      $<span class="Identifier">this</span>-&gt;form-&gt;bind($<span class="Identifier">request</span>-&gt;getParameter('<span class="Constant">signin</span>'));
      <span class="Statement">if</span> ($<span class="Identifier">this</span>-&gt;form-&gt;isValid())
      {
        $<span class="Identifier">values</span> = $<span class="Identifier">this</span>-&gt;form-&gt;getValues();
        $<span class="Identifier">this</span>-&gt;getUser()-&gt;signin($<span class="Identifier">values</span>['<span class="Constant">user</span>']);

        <span class="Statement">return</span> $<span class="Identifier">this</span>-&gt;redirect($<span class="Identifier">request</span>-&gt;getUri());
      }
      <span class="Statement">else</span>
      {
        $<span class="Identifier">message</span> = $<span class="Identifier">this</span>-&gt;form-&gt;getErrorSchema();
      }
    }

    $<span class="Identifier">header_message</span> = "<span class="Constant">Basic realm=\"</span>$<span class="Identifier">message</span><span class="Constant">\"</span>";

    $<span class="Identifier">this</span>-&gt;getResponse()-&gt;setStatusCode(<span class="Constant">401</span>);
    $<span class="Identifier">this</span>-&gt;getResponse()-&gt;setHttpHeader('<span class="Constant">WWW_Authenticate</span>', $<span class="Identifier">header_message</span>);

    <span class="Statement">return</span> sfView::NONE;
  }
}</pre>
<p>You can see that we reuse sfGuard&#8217;s error messages in the HTTP header, to get the exact same authentification logic as a normal login form:</p>
<p><a href="http://arpeggios.files.wordpress.com/2008/09/picture-101.png"><img class="alignnone size-large wp-image-351" title="picture-101" src="http://arpeggios.files.wordpress.com/2008/09/picture-101.png?w=449&#038;h=263" alt="" width="449" height="263" /></a></p>
<p>The same behavior can be observed using a HTTP request with parameters encoded directly into the URL:</p>
<pre style="font:Monospace;margin:0;padding:10px;">$ curl -v "http://<strong>login:pass</strong>@apps.localhost/api/api_dev.php/index"
* About to connect() to apps.localhost port 80 (#0)
*   Trying 127.0.0.1... connected
* Connected to apps.localhost (127.0.0.1) port 80 (#0)
* Server auth using Basic with user 'as'
&gt; GET /api/api_dev.php/index HTTP/1.1
&gt; Authorization: Basic YXM6
&gt; User-Agent: curl/7.18.2 (i386-apple-darwin8.11.1) libcurl/7.18.2 zlib/1.2.3
&gt; Host: apps.localhost
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 401 Unauthorized

&lt; Server: Apache/2.0.59 (Unix) PHP/5.2.5 DAV/2
&lt; X-Powered-By: PHP/5.2.5
&lt; Set-Cookie: symfony=2711f6b7440442a3746fc38771072ca7; path=/
&lt; Expires: Thu, 19 Nov 1981 08:52:00 GMT
&lt; Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
&lt; Pragma: no-cache
* Authentication problem. Ignoring this.
&lt; <strong>Www-Authenticate: Basic realm="password [Required.]
username [The username and/or password is invalid.]"</strong>
&lt; Content-Length: 0
&lt; Content-Type: text/html; charset=utf-8
&lt;
* Connection #0 to host apps.localhost left intact
* Closing connection #0</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/341/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=341&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/09/28/http-authentification-with-sfguard/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>

		<media:content url="http://arpeggios.files.wordpress.com/2008/09/picture-101.png?w=449" medium="image">
			<media:title type="html">picture-101</media:title>
		</media:content>
	</item>
		<item>
		<title>Handling several Propel packages</title>
		<link>http://arpeggios.wordpress.com/2008/09/04/handling-several-propel-packages/</link>
		<comments>http://arpeggios.wordpress.com/2008/09/04/handling-several-propel-packages/#comments</comments>
		<pubDate>Thu, 04 Sep 2008 15:17:32 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Scales]]></category>
		<category><![CDATA[propel]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=12</guid>
		<description><![CDATA[When working on complex applications, it is mostly common to deal with several database connections. The main database is often built and adminstrated by yourself, but you sometimes need to handle external databases, probably with a read-only access. Symfony and propel allows you to easily manage these &#8216;externals&#8217; connections. You can create several schema.xml that [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=12&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">When working on complex applications, it is mostly common to deal with several database connections. The main database is often built and adminstrated by yourself, but you sometimes need to handle external databases, probably with a read-only access.</p>
<p align="justify">Symfony and propel allows you to easily manage these &#8216;externals&#8217; connections.</p>
<p align="justify">You can create several schema.xml that defines tables for each database.</p>
<pre>schema.xml
external_schema.xml</pre>
<p align="justify">Connection settings for several databases are handled by the databases.yml configuration file :</p>
<pre>prod:
  propel:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://user:password@localhost/database
  external:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://login:pass@hostname/external_db_name</pre>
<h2>Skipping sql code generation</h2>
<p align="justify">As we only want to access the external database, we can skip the sql generation for the external schema. We only need model objects to read data from that database (and also create, update and delete in case of a full access database).</p>
<p align="justify">Propel allows you that by adding the &#8220;skipSql&#8221; attribute to a table. Refer to the <a href="http://propel.phpdb.org/trac/wiki/Users/Documentation/1.2/Schema">Propel documentation</a> for the complete list of available options.</p>
<pre>&lt;<span class="Special">table</span>&nbsp;name=“article” idMethod=“native” skipSql=“<span class="Special">true</span>”&gt;
</pre>
<p align="justify">By doing such, no sql data will be generated. That way, you can still use propel tasks to automatically load your main database without creating the freshly built tables of the external database, which won&#8217;t be used.</p>
<p align="justify">Besides, external developers have now a clear view of what database has to be created and used directly, and what database stands has an external reference.</p>
<p align="justify">When lauching that task :</p>
<pre>$ symfony propel:build-all-load</pre>
<p align="justify">Only the main schema.xml will build and insert the corresponding sql code in your database.</p>
<h2>Using package names</h2>
<p align="justify">You can also define a name for each propel package that will specify the generated files output destination.</p>
<p align="justify">Default is &#8220;lib.model&#8221;, which referers to the lib/model directory.</p>
<p>Ex:</p>
<pre>&lt;database name=“external” package=“lib.model.external”&gt;</pre>
<p></p>
<p align="justify">Model files will be generated in the lib/model/external sub-folder.</p>
<pre>$ symfony propel:build-model</pre>
<pre>+<strong>lib</strong>
|+<strong>model</strong>
|~<strong>external</strong>
| |+<strong>om</strong>
| |+<strong>map</strong>
| |-Account.php
| `-AccountPeer.php
|+<strong>om</strong>
|+<strong>map</strong>
|-Article.php
`-ArticlePeer.php</pre>
<p align="justify">By declaring different package names, propel will build separate .sql files.</p>
<pre>$ symfony propel:build-sql</pre>
<p align="justify">will generate :</p>
<pre>lib.model.schema.sql (containing tables defined in schema.xml)
lib.model.external.schema.sql (containing the external database tables)</pre>
<h2>Using a blank package name</h2>
<p align="justify">You can also specify a &#8220;blank&#8221; name for a package. Model files will be generated under the default lib/model directory.</p>
<p align="justify">The pattern used for the .sql file generation is <code>&lt;package.name&gt;.schema.sql</code>. Therefore, a schema.sql will be created, even if every table of the schema are &#8216;sql skipped&#8217;.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/arpeggios.wordpress.com/12/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/arpeggios.wordpress.com/12/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/12/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=12&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/09/04/handling-several-propel-packages/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Creating an Ajax update-only form using the default validators</title>
		<link>http://arpeggios.wordpress.com/2008/08/20/creating-an-ajax-update-only-form-using-the-default-validators/</link>
		<comments>http://arpeggios.wordpress.com/2008/08/20/creating-an-ajax-update-only-form-using-the-default-validators/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 14:32:29 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Scales]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[validation]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=244</guid>
		<description><![CDATA[The new form system is very powerful and decoupled. It means that the form creation code and the validation code can be used independently. Here is the default generated code for an update action : public function executeUpdate($request) {   …   $this-&#62;form = new ProductForm(productPeer::retrieveByPk($request-&#62;getParameter(‘id‘)));   $this-&#62;form-&#62;bind($request-&#62;getParameter(‘product‘));   if ($this-&#62;form-&#62;isValid())   {     …   } } The action automatically binds the product request parameter which correspond [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=244&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">The new form system is very powerful and decoupled. It means that the form creation code and the validation code can be used independently.</p>
<p align="justify">Here is the default generated code for an update action :</p>
<pre><span class="Type">public</span> <span class="PreProc">function</span> executeUpdate<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Special">)</span>
<span class="Special">{</span>
  …
  <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form <span class="Statement">=</span> <span class="PreProc">new</span> ProductForm<span class="Special">(</span>productPeer<span class="Statement">::</span>retrieveByPk<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>getParameter<span class="Special">(</span>‘id‘<span class="Special">)))</span>;
  <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form<span class="Type">-&gt;</span>bind<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>getParameter<span class="Special">(</span>‘product‘<span class="Special">))</span>;
  <span class="Statement">if</span> <span class="Special">(</span><span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form<span class="Type">-&gt;</span>isValid<span class="Special">())</span>
  <span class="Special">{</span>
    …
  <span class="Special">}</span>
<span class="Special">}</span></pre>
<p align="justify">The action automatically binds the product request parameter which correspond to a entire product form.</p>
<p align="justify">What if you want to make a simple form for update purpose only ?  Like an Ajax simple edit-and-save for one field ?</p>
<p align="justify">By default, if you don&#8217;t pass all the required fields explicitly, the form will not be valid.</p>
<p align="justify">According to the book, you can unset some fields from the from to bypass validation and save:</p>
<pre><span class="Type">class</span> ProductForm <span class="Type">extends</span> BaseProductForm
<span class="Special">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> configure<span class="Special">()</span>
  <span class="Special">{</span>
    <span class="Statement">unset</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">this</span><span class="Special">[</span>'<span class="Constant">created_at</span>'<span class="Special">])</span>;
  <span class="Special">}</span>
<span class="Special">}</span></pre>
<p align="justify">Let&#8217;s create a custom product form for a simple Ajax edit-and-update. As we only want one field to be validate and saved, we have to unset all fields, except the ones we want:</p>
<p>in <code>/lib/form/ProductFormAjax.class.php</code> :</p>
<pre><span class="Type">class</span> ProductFormAjax <span class="Type">extends</span> BaseProductForm
<span class="Special">{</span>
  <span class="Comment">// Create the form only for these fields</span>
  <span class="Type">protected</span> <span class="Statement">$</span><span class="Identifier">enabled_fields</span> <span class="Statement">=</span> <span class="Type">array</span><span class="Special">(</span>‘id‘, ‘name‘<span class="Special">)</span>;
  <span class="Type">public</span> <span class="PreProc">function</span> configure<span class="Special">()</span>
  <span class="Special">{</span>
    <span class="Statement">foreach</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>getWidgetSchema<span class="Special">()</span><span class="Type">-&gt;</span>getFields<span class="Special">()</span> <span class="Statement">as</span> <span class="Statement">$</span><span class="Identifier">name</span> <span class="Statement">=</span><span class="Statement">&gt;</span> <span class="Statement">$</span><span class="Identifier">field</span><span class="Special">)</span>
    <span class="Special">{</span>
      <span class="Statement">if</span> <span class="Special">(</span><span class="Statement">!</span><span class="Identifier">in_array</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">name</span>, <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>enabled_fields<span class="Special">))</span>
      <span class="Special">{</span>
        <span class="Statement">unset</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">this</span><span class="Special">[</span><span class="Statement">$</span><span class="Identifier">name</span><span class="Special">])</span>;
      <span class="Special">}</span>
    <span class="Special">}</span>
  <span class="Special">}</span>
<span class="Special">}</span></pre>
<p align="justify">You now have a simplified update-only form that uses the same field validators defined in your <code>/lib/form/base/BaseProductForm.class.php</code>.</p>
<p align="justify">Now, in the actions class, you can choose between the default form and yours depending upon the context :</p>
<pre>
<span class="Type">class</span> ProductActions <span class="Type">extends</span> sfActions
<span class="Special">{</span>
  <span class="Type">public</span> <span class="PreProc">function</span> executeUpdate<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Special">)</span>
  <span class="Special">{</span>
    …
    <span class="Statement">if</span> <span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>isXmlHttpRequest<span class="Special">())</span>
    <span class="Special">{</span>
      <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form <span class="Statement">=</span> <span class="PreProc">new</span> InstallatorFormAjax<span class="Special">(
</span>InstallatorPeer<span class="Statement">::</span>retrieveByPk<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>getParameter<span class="Special">(</span>‘id‘<span class="Special">)))</span>;
    <span class="Special">}</span>
    <span class="Statement">else</span>
    <span class="Special">{</span>
      <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form <span class="Statement">=</span> <span class="PreProc">new</span> InstallatorForm<span class="Special">(</span>
InstallatorPeer<span class="Statement">::</span>retrieveByPk<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>getParameter<span class="Special">(</span>‘id‘<span class="Special">)))</span>;
    <span class="Special">}</span>
    …
  <span class="Special">}</span>
  …
  <span class="Type">public</span> <span class="PreProc">function</span> executeEditAjax<span class="Special">()</span>
  <span class="Special">{</span>
    <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>form <span class="Statement">=</span> <span class="PreProc">new</span> ProductFormAjax<span class="Special">(</span>
InstallatorPeer<span class="Statement">::</span>retrieveByPk<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">request</span><span class="Type">-&gt;</span>getParameter<span class="Special">(</span>‘id‘<span class="Special">)))</span>;
  <span class="Special">}</span>
<span class="Special">}</span></pre>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/arpeggios.wordpress.com/244/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/arpeggios.wordpress.com/244/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/244/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/244/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/244/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=244&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/08/20/creating-an-ajax-update-only-form-using-the-default-validators/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Extending the default module action</title>
		<link>http://arpeggios.wordpress.com/2008/08/20/extending-default-module-actions/</link>
		<comments>http://arpeggios.wordpress.com/2008/08/20/extending-default-module-actions/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 08:53:51 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Scales]]></category>
		<category><![CDATA[modules]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=32</guid>
		<description><![CDATA[Often in a project, module actions have to manage the same common kind of functionalities : paging sorting filtering any other general job You end up with actions that implements each functionality, maybe into separate methods : class&#160;articleActions extends&#160;sfActions { &#160;&#160;protected&#160;function&#160;processSort()&#160;{&#160;…&#160;&#160;} &#160;&#160;protected&#160;function&#160;processFilter()&#160;{&#160;…&#160;&#160;} &#160;&#160;public&#160;function&#160;executeIndex() &#160;&#160;{ &#160;&#160;&#160;&#160; $this-&#62;processSort(); &#160;&#160;&#160;&#160; $this-&#62;processFilter(); &#160;&#160;&#160;&#160; $this-&#62;pager&#160;=&#160;new&#160;sfPropelPager(‘Article‘, 20); &#160;&#160;&#160;&#160; … &#160;&#160;} }&#160; [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=32&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p align="justify">
Often in a project, module actions have to manage the same common kind of functionalities :</p>
<ul>
<li>paging</li>
<li>sorting</li>
<li>filtering</li>
<li>any other general job</li>
</ul>
<p>
</p>
<p align="justify">
You end up with actions that implements each functionality, maybe into separate methods :
</p>
<pre>
<span class="Type">class</span>&nbsp;articleActions <span class="Type">extends</span>&nbsp;sfActions
<span class="Special">{</span>
&nbsp;&nbsp;<span class="Type">protected</span>&nbsp;<span class="PreProc">function</span>&nbsp;processSort<span class="Special">()</span>&nbsp;<span class="Special">{</span>&nbsp;…&nbsp;&nbsp;<span class="Special">}</span>

&nbsp;&nbsp;<span class="Type">protected</span>&nbsp;<span class="PreProc">function</span>&nbsp;processFilter<span class="Special">()</span>&nbsp;<span class="Special">{</span>&nbsp;…&nbsp;&nbsp;<span class="Special">}</span>

&nbsp;&nbsp;<span class="Type">public</span>&nbsp;<span class="PreProc">function</span>&nbsp;executeIndex<span class="Special">()</span>
&nbsp;&nbsp;<span class="Special">{</span>
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>processSort<span class="Special">()</span>;
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>processFilter<span class="Special">()</span>;
&nbsp;&nbsp;&nbsp;&nbsp; <span class="Statement">$</span><span class="Identifier">this</span><span class="Type">-&gt;</span>pager&nbsp;<span class="Statement">=</span>&nbsp;<span class="PreProc">new</span>&nbsp;sfPropelPager<span class="Special">(</span>‘Article‘, <span class="Constant">20</span><span class="Special">)</span>;
&nbsp;&nbsp;&nbsp;&nbsp; …
&nbsp;&nbsp;<span class="Special">}</span>
<span class="Special">}</span>&nbsp;
</pre>
<p></p>
<p align="justify">
Let&#8217;s extract these jobs and use them in all your modules.
</p>
<h2>Extending sfActions</h2>
<p align="justify">
A Symfony action is a stack of extended classes, so you can easily add your own class to the stack and can put all the common code in it.
</p>
<p align="justify">
Let&#8217;s factorize all theses functionalities into a custom action class that extends sfActions.</p>
<p align="justify">
Let&#8217;s create the <code>/lib/myBaseActions.class.php</code> file :
</p>
<pre>
<span class="Type">class</span>&nbsp;myBaseActions <span class="Type">extends</span>&nbsp;sfActions
<span class="Special">{</span>
&nbsp;&nbsp;<span class="Comment">// Implement your general methods here</span>
&nbsp;&nbsp;<span class="Type">protected</span>&nbsp;<span class="PreProc">function</span>&nbsp;processSort<span class="Special">()</span>
&nbsp;&nbsp;<span class="Type">protected</span>&nbsp;<span class="PreProc">function</span>&nbsp;processFilter<span class="Special">()</span>
&nbsp;&nbsp;…
<span class="Special">}</span>&nbsp;
</pre>
<p></p>
<p align="justify">
Now, simply change the parent class in your module action class :
</p>
<pre>
<span class="Type">class</span>&nbsp;articleActions <span class="Type">extends</span>&nbsp;myBaseActions
<span class="Special">{</span>
&nbsp;&nbsp;<span class="Type">public</span>&nbsp;<span class="PreProc">function</span>&nbsp;executeIndex<span class="Special">()</span>
&nbsp;&nbsp;<span class="Special">{</span>
&nbsp;&nbsp;<span class="Special">}</span>
&nbsp;&nbsp;…
<span class="Special">}</span>&nbsp;
</pre>
<p></p>
<p align="justify">
The dirty job is now centralized and executed implicitly in all your modules.
</p>
<p align="justify">
Besides, extracting the logic that way forces you to write decoupled and cohesive code, as each method only do a specific job.
</p>
<h2>About auto-generated modules</h2>
<p align="justify">
You should take a look at how a module action generated by the sfAdminGenerator.
</p>
<ul>
<li>Simply init a module : </li>
<pre>
$ symfony propel:init-admin article_admin Article
</pre>
<p></p>
<li>Go to <code>http://yourapp/article_admin</code> to generate cache files</li>
</ul>
<p></p>
<p align="justify">
Check <code>/cache/prod/modules/autoArticle_admin/actions/actions.class.php</code>.
</p>
<p align="justify">
You can get inspired from it, specially from these design principles :</p>
<ul>
<li>sorting and filtering infos are stored in the session</li>
<li>Criteria modifications for both is split into separate methods</li>
</ul>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/arpeggios.wordpress.com/32/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/arpeggios.wordpress.com/32/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/32/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/32/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/32/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=32&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/08/20/extending-default-module-actions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
		<item>
		<title>Plugins unit testing</title>
		<link>http://arpeggios.wordpress.com/2008/08/19/arpeggio-2-plugin-functional-testing/</link>
		<comments>http://arpeggios.wordpress.com/2008/08/19/arpeggio-2-plugin-functional-testing/#comments</comments>
		<pubDate>Tue, 19 Aug 2008 08:40:53 +0000</pubDate>
		<dc:creator>nicolas.martin</dc:creator>
				<category><![CDATA[Scales]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://arpeggios.wordpress.com/?p=3</guid>
		<description><![CDATA[About unit testing From the Symfony book : Unit tests confirm that a unitary code component provides the correct output for a given input. They validate how functions and methods work in every particular case. Unit tests deal with one case at a time, so for instance a single method may need several unit tests [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=3&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h2>About unit testing</h2>
<p>From the <a href="http://www.symfony-project.org/book/1_1/15-Unit-and-Functional-Testing#Functional%20Tests">Symfony book</a> :</p>
<p align="justify">
<blockquote><p>Unit tests confirm that a unitary code component provides the correct output for a given input. They validate how functions and methods work in every particular case. Unit tests deal with one case at a time, so for instance a single method may need several unit tests if it works differently in certain situations.</p></blockquote>
<p align="justify">If you write a Symfony plugin that deals with models, say a behavior, you are also invited to write a functional test to make sure that your objects behave correctly.</p>
<p align="justify">In that test, you must be able to instantiate one or many objects in a real application context, call methods, save, and check that the final state matches your requirements.</p>
<h2>Unit test your plugin</h2>
<p align="justify">Just like an application unit test, let&#8217;s create this file structure:</p>
<pre>~plugins/
 `~sfPropelActAsSomethingBehaviorPlugin/
   |+config/
   |+lib/
   |~test/
   | |~bootstrap/
   | | |-<strong>fixtures.yml</strong>
   | | `-<strong>functional.php</strong>
   | `~unit/
   |   `-<strong>somethingTest.php</strong></pre>
<p align="justify">Put some sample data in fixtures.yml. Ex:</p>
<pre>Article:
  article_1:
    title: my first article
    body: blablabla
    author_id: 1
Author:
  author_1:
    name: nicolas</pre>
<p align="justify">bootstrap.php will do the following stuff:</p>
<ul>
<li>Set up the test database connection</li>
<li>Delete existing data</li>
<li>Load fresh new fixtures</li>
</ul>
<pre><span class="Statement">$</span><span class="Identifier">app</span> <span class="Statement">=</span> ’frontend‘;
<span class="PreProc">require_once</span> <span class="Identifier">dirname</span><span class="Special">(</span><span class="Constant">__FILE__</span><span class="Special">)</span><span class="Statement">.</span>‘<span class="Statement">/../../../../</span>config<span class="Statement">/</span>ProjectConfiguration<span class="Statement">.</span><span class="Type">class</span><span class="Statement">.</span>php‘;
<span class="Statement">$</span><span class="Identifier">configuration</span> <span class="Statement">=</span> ProjectConfiguration<span class="Statement">::</span>getApplicationConfiguration<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">app</span>, ‘test‘, <span class="Statement">isset</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">debug</span><span class="Special">)</span> <span class="Statement">?</span> <span class="Statement">$</span><span class="Identifier">debug</span> <span class="Statement">:</span> <span class="Constant">true</span><span class="Special">)</span>;
sfContext<span class="Statement">::</span>createInstance<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">configuration</span><span class="Special">)</span>;

<span class="Statement">$</span><span class="Identifier">fixtures</span> <span class="Statement">=</span> <span class="Identifier">dirname</span><span class="Special">(</span><span class="Constant">__FILE__</span><span class="Special">)</span><span class="Statement">.</span>‘<span class="Statement">/</span>fixtures<span class="Statement">.</span>yml‘;
<span class="Statement">$</span><span class="Identifier">databaseManager</span> <span class="Statement">=</span> <span class="PreProc">new</span> sfDatabaseManager<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">configuration</span><span class="Special">)</span>;
<span class="Statement">$</span><span class="Identifier">databaseManager</span><span class="Type">-&gt;</span>initialize<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">configuration</span><span class="Special">)</span>;
<span class="Statement">$</span><span class="Identifier">con</span> <span class="Statement">=</span> Propel<span class="Statement">::</span>getConnection<span class="Special">()</span>;

ArticlePeer<span class="Statement">::</span>doDeleteAll<span class="Special">()</span>;
AuthorPeer<span class="Statement">::</span>doDeleteAll<span class="Special">()</span>;

<span class="Statement">$</span><span class="Identifier">data</span> <span class="Statement">=</span> <span class="PreProc">new</span> sfPropelData<span class="Special">()</span>;
<span class="Statement">$</span><span class="Identifier">data</span><span class="Type">-&gt;</span>loadData<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">fixtures</span>, ‘propel‘<span class="Special">)</span>;</pre>
<p align="justify">Now, let&#8217;s write the test in somethingBehaviorTest.php, using the freshly initialized database with fixtures loaded :</p>
<pre><span class="PreProc">include</span><span class="Special">(</span><span class="Identifier">dirname</span><span class="Special">(</span><span class="Constant">__FILE__</span><span class="Special">)</span><span class="Statement">.</span>‘<span class="Statement">/../</span>bootstrap<span class="Statement">/</span>functional<span class="Statement">.</span>php‘<span class="Special">)</span>;
<span class="PreProc">include</span><span class="Special">(</span><span class="Statement">$</span><span class="Identifier">configuration</span><span class="Type">-&gt;</span>getSymfonyLibDir<span class="Special">()</span><span class="Statement">.</span>‘<span class="Statement">/</span>vendor<span class="Statement">/</span>lime<span class="Statement">/</span>lime<span class="Statement">.</span>php‘<span class="Special">)</span>;

<span class="Statement">$</span><span class="Identifier">t</span> <span class="Statement">=</span> <span class="PreProc">new</span> lime_test<span class="Special">(</span><span class="Constant">23</span>, <span class="PreProc">new</span> lime_output_color<span class="Special">())</span>;

<span class="Statement">$</span><span class="Identifier">c</span> <span class="Statement">=</span> <span class="PreProc">new</span> Criteria;
<span class="Statement">$</span><span class="Identifier">c</span><span class="Type">-&gt;</span><span class="Identifier">add</span><span class="Special">(</span>Author<span class="Statement">::</span>NAME, ‘nicolas‘<span class="Special">)</span>;
<span class="Statement">$</span><span class="Identifier">author</span> <span class="Statement">=</span> AuthorPeer<span class="Statement">::</span>doSelectOne<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">c</span><span class="Special">)</span>;

<span class="Statement">$</span><span class="Identifier">t</span><span class="Type">-&gt;</span>is<span class="Special">(</span><span class="Statement">$</span><span class="Identifier">author</span><span class="Type">-&gt;</span>countStuff<span class="Special">()</span>, <span class="Constant">3</span>, "<span class="Constant">author_1 should have \"3\" stuff</span>"<span class="Special">)</span>;
…</pre>
<h2>Test !</h2>
<pre>$ php plugins/sfActAsSomethingPlugin/test/unit/somethingTest.php
1..23
<span style="color:#00ff00;">ok 1</span> - Author_1 should have 3 stuff</pre>
<h2>Note</h2>
<p align="justify">foreign references must be respected when deleting data. Then, you must detete them in the correct order (ex: Articles before Authors).</p>
<p align="justify">Fixtures must be declared in the correct order as well (ex: Authors before Articles) as they will be inserted sequentially.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/arpeggios.wordpress.com/3/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/arpeggios.wordpress.com/3/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/arpeggios.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/arpeggios.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/arpeggios.wordpress.com/3/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=arpeggios.wordpress.com&amp;blog=4455742&amp;post=3&amp;subd=arpeggios&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://arpeggios.wordpress.com/2008/08/19/arpeggio-2-plugin-functional-testing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d7937c04d27d54d5337f07180b6a82c0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">nicolas.martin</media:title>
		</media:content>
	</item>
	</channel>
</rss>
