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

<channel>
	<title>Web Mozarts &#187; Bernhard</title>
	<atom:link href="http://webmozarts.com/author/bschussek/feed/" rel="self" type="application/rss+xml" />
	<link>http://webmozarts.com</link>
	<description>On The Art Of Web Development</description>
	<lastBuildDate>Tue, 07 Sep 2010 08:02:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Why Not To Want 100% Code Coverage</title>
		<link>http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/</link>
		<comments>http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 08:00:20 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Best Practices]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=484</guid>
		<description><![CDATA[Although most modern literature agrees that testing is essential for successful software projects, testing has to be done right. Several bad habits can be identified that not only negatively affect testing performance, but also reduce your development speed. One of the first mistakes people make when they first discover testing is trying to reach 100% [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Although most modern literature agrees that testing is essential for successful software projects, testing has to be done right. Several bad habits can be identified that not only negatively affect testing performance, but also reduce your development speed. One of the first mistakes people make when they first discover testing is trying to reach 100% code coverage. I was no exception.<span id="more-484"></span></p>
<h3>Test Balance</h3>
<p>The more tests you have for your application, the more difficult it becomes to introduce changes. Everytime you change an existing feature, you have to change <em>at least</em> one test. Everytime you make a refactoring of your project&#8217;s architecture (which you should do frequently), you most likely need to adapt <em>multiple</em> tests. As a rule of thumb you can say that the more tests you have, the more difficult it becomes to make changes in your code.</p>
<p>We know that not to write tests is not a solution. Lots of tests, on the other hand, are bad for maintainability. Instead, try to keep a certain test balance by testing only what is important. The following section shows you one possible approach for identifying important tests called <em>risk-based testing</em>.</p>
<h3>Risk-Based Testing</h3>
<p>The purpose of testing is to avoid regressions in your software resulting of its complexity. These potential regressions can be expressed as risks ranked by their probability and severity. The probability expresses how likely the regression is to occur. The severity expresses how severely the regression would affect the functionality of your application. Both can be expressed in numbers, for instance in a range of 1 to 10 with 10 being the highest severity/probability. Look at the following table for example:</p>
<table border="0">
<tbody>
<tr>
<th>Risk</th>
<th>Probability (<em>P</em>)</th>
<th>Severity (<em>S</em>)</th>
<th>Total (<em>P</em>x<em>S</em>)</th>
</tr>
<tr>
<td><code>getGroup()</code> returns a wrong object</td>
<td>1</td>
<td>3</td>
<td>3</td>
</tr>
<tr>
<td><code>calculatePrice($product)</code> uses a wrong algorithm</td>
<td>7</td>
<td>8</td>
<td>56</td>
</tr>
</tbody>
</table>
<p>The table contains risks for two fictitious methods <code>getGroup()</code> and <code>calculatePrice()</code>. Imagine that the first of these methods only returns an internal property <code>$group</code>. The probability of someone breaking this code by accident is near to non-existent. Assume further that the group is only used for display purposes, so the severity of a broken code is not very high either.</p>
<p>The second method, <code>calculatePrice()</code>, uses an internal algorithm to calculate the price of a product. Because it depends on an external object <code>$product</code>, and because the algorithm is non-trivial, the probability of breaking the code is rather high. Even higher though is the severity of a broken functionality &#8211; what could be worse than wrongly calculated prices.</p>
<p>Is it worth to unit-test <code>getGroup()</code>? Probably not. We calculated an overall total of 3, which (in our scale from 1 to 100) is really not that impressive. Is it, on the other hand, worth to test <code>calculatePrice()</code>? Judge for yourself.</p>
<p>Obviously I selected two extreme examples here. Also you will almost never calculate probabilities and severities for testing single methods like I did it here. But you should try to develop a feeling for what is worth to be tested and what is not.</p>
<h3>Test Complexity</h3>
<p>Now that you have identified which risks you should cover in your test suite, the question is to what extent you should do so. Look at the following to approaches for testing <code>calculatePrice()</code>:</p>
<p><strong>Approach 1: The fair-enough approach</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LimeTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: calculatePrice() multiplies the price with the amount</span>
&nbsp;
  <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>price <span style="color: #339933;">=</span> <span style="color: #cc66cc;">100</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>amount <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$calculator</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>calculatePrice<span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><strong>Approach 2: The safe approach</strong></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LimeTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Before</span>
&nbsp;
  <span style="color: #000088;">$product</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>price <span style="color: #339933;">=</span> <span style="color: #cc66cc;">100</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: calculatePrice() multiplies the price with the amount (amount == 1)</span>
&nbsp;
  <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>amount <span style="color: #339933;">=</span> <span style="color: #cc66cc;">1</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$calculator</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>calculatePrice<span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: calculatePrice() multiplies the price with the amount (amount == 2)</span>
&nbsp;
  <span style="color: #000088;">$product</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>amount <span style="color: #339933;">=</span> <span style="color: #cc66cc;">2</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$calculator</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>calculatePrice<span style="color: #009900;">&#40;</span><span style="color: #000088;">$product</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The first approach assumes that testing whether the result equals price multiplied by amount is enough. The test can obviously not check whether the developer has hard-coded a fixed return value of 200 or uses a fixed amount of 2. It expects the developer to be <em>reasonable</em>.</p>
<p>The second approach takes care of these eventualities by writing another test to make sure that changed amounts result in changed outputs. But even now, the developer could write a simple switch statement in <code>calculatePrice()</code> and return either 100 or 200, based on the amount. The test will not notice.</p>
<p>The conclusion is that you can never test your code for <em>all</em> eventualities. However complicated your test may be, there will always be a way to fake the implementation. But is it likely that developers will fake it? Probably not. This being said, the best approach in my opinion is approach 1 because it keeps effort required to adapt or change the test to a minimum.</p>
<h3>Conclusion</h3>
<p>Don&#8217;t try to achieve 100% test coverage. Identify the most important risks, and test for those. Don&#8217;t test for all eventualities either. Always keep in mind that the developers working on your code are somewhat reasonable people. If they aren&#8217;t, you are probably better off without them anyway.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Writing Efficient Tests</title>
		<link>http://webmozarts.com/2010/03/11/writing-efficient-tests/</link>
		<comments>http://webmozarts.com/2010/03/11/writing-efficient-tests/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 17:55:06 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Best Practices]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=469</guid>
		<description><![CDATA[Unit testing can be a blessing and curse at the same time. Once you start doing it on a regular basis, it can become an addiction. You test everything, you feel the satisfaction of 110% test coverage giving you confidence in your code. But after a while, testing suddenly seems to slow you down. Everytime [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Unit testing can be a blessing and curse at the same time. Once you start doing it on a regular basis, it can become an addiction. You test everything, you feel the satisfaction of 110% test coverage giving you confidence in your code. But after a while, testing suddenly seems to slow you down. Everytime you make a change in your code you have to adapt several unrelated tests. Adding a <code>&lt;ul&gt;</code>-tag to your template becomes a matter of minutes, rather than seconds. And, worst of all, your test suite is <em>slow</em>.</p>
<p>What happened?<span id="more-469"></span></p>
<h3>Unit vs. System Tests</h3>
<p>To begin with, you need to understand the difference between unit and system tests and the impact both have on testing performance.</p>
<p>Unit tests are <em>atomic</em>. They test classes and components in isolation from any other service they depend on. Such services can be external services, like mailing systems, databases or webservices, and internal services, like a calculator, a data store or similar service classes. Running these tests in isolation gives you several advantages:</p>
<ul>
<li>Speed of execution</li>
<li>Speed of development</li>
<li>Test confidence</li>
</ul>
<p>Speed of execution, because the test doesn&#8217;t need to wait for the related service to process its internal logic. Speed of development, because you (hopefully) don&#8217;t have to adapt the test when you refactor the internals of the related service class or add new features to it. And test confidence, because the test will only fail when the tested class is erroneous, not if any of the related services provide wrong data.</p>
<p>System tests (acceptance or functional tests are a kind of system tests) test whether all the classes in your application collaborate correctly. Because you unit tested these classes in isolation, you had to <em>assume</em> how collaborating services should behave. If this assumption is wrong, no unit test will tell you. And that&#8217;s the space that system tests fill. The big, big disadavantage of system tests is that they are slow. They have to initialize the application, read its configuration files, initialize its database with fresh data (it doesn&#8217;t make a lot of sense to disconnect system tests from the real database) and more. All this takes time.</p>
<p>The conclusion from the last paragraphs is that <em>features</em> of your application should <em>always</em> be tested in unit tests. These tests are fast and guide you to the error if things go wrong. There is nothing more harmful to test performance than testing whether a form works correctly by means of a system test. If the form is a class, write a unit test. If the form is no class, make it one.</p>
<h3 style="font-size: 1,17em;">Decouple Your Code</h3>
<p>If you reach the point that you have lots of unit tests and few system tests, you made the first step towards becoming a test speed king. The second step is to decouple your classes.</p>
<p>Highly coupled code negatively affects your development in several ways. Because your code depends on other classes, these other classes (the dependent-on components or DOCs) all have to be instantiated during testing. Depending on their nature, this process may take time and slow your test down. Introducing new features becomes difficult because it results in lot of test code that needs to be adapted. If one of your classes breaks, not only the test of the class fails, but also several other tests of dependent classes. Shortly spoken: Extending and maintaining the application becomes a nightmare.</p>
<p>To decouple your code, get a clear picture of the responsibilities inside of your application. If a class does too much, tear it apart like a wild monkey smelling a banana in a big pile of waste paper.</p>
<p class="note">The following code samples are based on the PHP5 frameworks <a href="http://www.symfony-project.com" title="The symfony framework" target="_blank" class="liexternal">symfony</a>, <a href="http://www-doctrine-project.org" title="Doctrine Object-Relational Mapping for PHP5" target="_blank" class="liexternal">Doctrine</a> and <a href="http://github.com/bschussek/lime" title="Lime 2. A usable testing framework for PHP5." target="_blank" class="liexternal">Lime 2</a>. The same concepts can be applied to other frameworks and languages just as well.</p>
<p>Let&#8217;s look at a (slightly modified) example I recently saw in a code review:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> sfValidatorUsername
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> clean<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> Doctrine_Query<span style="color: #339933;">::</span><span style="color: #004000;">create</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
      <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>from<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User u'</span><span style="color: #009900;">&#41;</span>
      <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>where<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'u.name = ? AND u.active = 1'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
      <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>fetchOne<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'invalid'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>It should be pretty obvious what this code is doing. What is the problem? The validator depends on the database. This is not a problem per se, but querying the database for <code>User</code> objects is beyond the validator&#8217;s responsibilities. This task should rather be done by your data acccess objects (DAOs), entity stores, tables or whatever you call them. And these objects can easily be injected into the validator using <em>Dependency Injection</em>.</p>
<p>Happy that we have identified this code smell, we can already start removing it:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> sfValidatorUsername
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$table</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>UserTable <span style="color: #000088;">$table</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>table <span style="color: #339933;">=</span> <span style="color: #000088;">$table</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> clean<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_null</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>table<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>findActive<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'invalid'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>We removed the database code and instead inject the table object into the constructor. The responsibility for fetching an active user by its name was outsourced to the table.</p>
<p class="info">An even faster solution is to only count the matching user objects in the database instead of querying and hydrating them. But that&#8217;s not in the scope of this article.</p>
<p>So, mummy, is our test faster already? Is it?</p>
<h3>Replace Dependencies During Testing</h3>
<p>No, kid. We are still using the <code>UserTable</code> when testing the validator &#8211; of course, because we need it. So what can we do?</p>
<p>Now that the validator only depends on the <code>UserTable</code>, and not on some mystical database query magic, we can replace the <code>UserTable</code> &#8211; which is tested somewhere else and assumed to be working &#8211; with a fake implementation. This is usually called <em>stubbing</em> (because you are replacing it with a non-functional <em>stub</em>). With Lime 2, you can do it like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LimeTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: clean() returns the cleaned value if the user is found</span>
&nbsp;
  <span style="color: #000088;">$table</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>stub<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'UserTable'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$table</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>findActive<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bob'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>returns<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$table</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>replay<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$validator</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorUsername<span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>clean<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bob'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'bob'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The stub acts <em>as if</em> it was the real <code>UserTable</code> object, but in reality it has no internal logic at all. So compared to the real table, the stub is very fast.</p>
<p class="info">More documentation about Lime 2 and its stubbing/mocking capabilities can currently be found on the <a href="http://github.com/bschussek/lime/tree/master/doc/" target="_blank" class="liexternal">Lime 2 GitHub repository</a>.</p>
<p>A word of caution shall be spoken. You should only replace <em>services</em> (classes that process some data and return a result) with stubs, not <em>entities</em> (classes that simply contain data). Otherwise changing your domain model (the entities) will soon become a nightmare.</p>
<h3>Testing With Databases</h3>
<p>Hurray! The validator test is so fast, I can execute it 10 times in a row and it&#8217;s still fun. One more time! Nice.</p>
<p>But wait &#8211; we can&#8217;t decouple everything from the database, can we? Of course, we can&#8217;t. Code that is responsible for collaborating with the database, like the above <code>UserTable</code>, needs to access the database. In order for that test to work, the database has to be bootstrapped and filled with data. Because tests should run in isolation from each other, the database further needs to be reset <em>before every single test</em>.</p>
<p>Now a common mistake that severely affects testing performance can often be seen in <em>symfony</em> projects. Many developers use a test database on their development DBMS, like a MySQL server. This database is filled with the content of <em>fixtures.yml</em>, which usually contains all fixture data commonly used to test the application in the browser. And for good reasons this is very slow:</p>
<ul>
<li>Most DBMS store data on the file system. Hard disk access is an expensive operation.</li>
<li>Filling the database with all the test data takes a lot of time</li>
<li>Parsing YAML files is slow</li>
</ul>
<p>So ideally we don&#8217;t use the database and don&#8217;t use any test data. Obviously, that&#8217;s not possible.</p>
<h3>In-Memory Databases</h3>
<p>What <em>is</em> possible is to use an in-memory database. While CPU access on the hard disk usually takes around 4 170 000 ns (nano seconds) for 7200 RPM drives, memory access only takes around 14 ns! Thus, using an in-memory database is a very cheap way to increase your testing performance immensely. Unfortunately not all database vendors offer in-memory alternatives for their file-based DBMS (such as MySQL). In such cases I use SQLite in-memory databases, because SQLite supports most of the SQL92 standard, which is generally sufficient for testing purposes.</p>
<p>If you use <em>symfony</em> with <em>Doctrine</em>, you can place the following code snippet into your <em>bootstrap/unit.php</em> file which initializes the SQLite in-memory database:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// initialize Doctrine</span>
<span style="color: #000088;">$cacheFile</span> <span style="color: #339933;">=</span> <span style="color: #990000;">sprintf</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_autoload_unit_doctrine_%s.data'</span><span style="color: #339933;">,</span> <span style="color: #990000;">md5</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">__FILE__</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoload</span> <span style="color: #339933;">=</span> sfSimpleAutoload<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">sys_get_temp_dir</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$cacheFile</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoload</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addDirectory<span style="color: #009900;">&#40;</span>ROOT_DIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'/lib/model'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoload</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addDirectory<span style="color: #009900;">&#40;</span>ROOT_DIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'/lib/form'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoload</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addDirectory<span style="color: #009900;">&#40;</span>ROOT_DIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'/lib/filter'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$autoload</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>register<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$database</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfDoctrineDatabase<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'doctrine'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'dsn'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'sqlite::memory:'</span>
<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// load all missing model files</span>
Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">loadModels</span><span style="color: #009900;">&#40;</span>ROOT_DIR<span style="color: #339933;">.</span><span style="color: #0000ff;">'/lib/model'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 * Reloads the database.
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> reload<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">// close the connection to the in-memory database to recreate the database</span>
  Doctrine_Manager<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getCurrentConnection<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>close<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// create the database tables from the loaded models</span>
  Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">createTablesFromModels</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// clear the Doctrine cache</span>
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span>Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getLoadedModels</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>clear<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p class="info">Make sure the constant <code>ROOT_DIR</code> is defined and points to the root of the tested project (your real project or the fixture project).</p>
<p class="note">You might wonder why the <code>$cacheFile</code> is required. This parameter allows us to run multiple tests in parallel while still leveraging autoloading performance by using a cache.</p>
<p>The real interesting piece of code is the <code>reload()</code> function. It allows you to recreate the database on demand. Whenever you write a test that requires a fresh database, call <code>reload()</code> and you are good to go.</p>
<h3>Fixture Management</h3>
<p>As described above, it is important to keep an eye on the test data that is loaded into your database. The more data you load, the more time it takes. Loading the whole <em>fixtures.yml</em> is a recipe for slow (not only because it contains a lot of data, but also because the YAML file must be parsed).</p>
<p>A much more efficient solution is to programmatively create and load test data on-the-fly. Only create what you need, and nothing more. Below you can find a sample test for our above method <code>UserTable::findActive()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LimeTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: findActive() returns an active user by username</span>
&nbsp;
  reload<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>username <span style="color: #339933;">=</span> <span style="color: #0000ff;">'bob'</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>active <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$table</span> <span style="color: #339933;">=</span> Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>findActive<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bob'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>This test is really fast now. The database is created in-memory, exactly one single <code>User</code> object is inserted and that&#8217;s it. The downside is that creating all the fixture data inline becomes a little messy, especially if you have to fill a lot of properties only because they are defined as <code>NOT NULL</code> in the database.</p>
<h3>Creation Methods</h3>
<p>To work around this issue, I prefer the <em>Creation Method</em> pattern by Gerard Meszaros[1]:</p>
<blockquote><p>We should use a <em>Creation Method</em> whenever consructing a <em>Fresh Fixture</em> requires significant complexity and we value <em>Tests as Documentation</em>.</p></blockquote>
<p>The pattern is very simple. Encapsulate the code required to create an object within a utility function that can be reused across your project. My rule of thumb is to write creation methods for all tested Doctrine records and initialize all <code>NOT NULL</code> fields and relations with default values so that the object can be saved without further modification. Because this leads to a lot of code duplication, I also use a base function <code>createObject()</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> createUser<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span> <span style="color: #000088;">$properties</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">return</span> createObject<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$properties</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #666666; font-style: italic;">// NOT NULL properties</span>
    <span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'francis'</span><span style="color: #339933;">,</span>
    <span style="color: #339933;">...</span>
    <span style="color: #666666; font-style: italic;">// NOT NULL relations</span>
    <span style="color: #0000ff;">'Group'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> createGroup<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> createObject<span style="color: #009900;">&#40;</span><span style="color: #000088;">$class</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$properties</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$defaultProperties</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$properties</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$defaultProperties</span><span style="color: #339933;">,</span> <span style="color: #000088;">$properties</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$object</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000088;">$class</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$properties</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$property</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$object</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>set<span style="color: #009900;">&#40;</span><span style="color: #000088;">$property</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #000088;">$object</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now you can call <code>createUser()</code> everytime you need to create and save a new <code>User</code> object. Optionally, you can inject property values into the constructor.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> LimeTest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: findActive() returns an active user by username</span>
&nbsp;
  reload<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> createUser<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'username'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'bob'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'active'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$user</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$table</span> <span style="color: #339933;">=</span> Doctrine<span style="color: #339933;">::</span><span style="color: #004000;">getTable</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'User'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$table</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>findActive<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'bob'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<div class="info">
<h4>A Few More Utility Methods</h4>
<p>In the following snippet you can find some more utility methods that I find very useful when dealing with fresh fixtures. Put them into your <em>bootstrap/unit.php</em> file or where ever they suit you best.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #009933; font-style: italic;">/**
 * Saves all objects passed as arguments.
 * @param Doctrine_Record $object1
 * @param Doctrine_Record ...
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">func_get_args</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$object</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$object</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 * Creates a collection containing the passed objects.
 * @param Doctrine_Record $object1
 * @param Doctrine_Record ...
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> collection<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">func_num_args</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> LogicException<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'You must pass at least one object'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000088;">$objects</span> <span style="color: #339933;">=</span> <span style="color: #990000;">func_get_args</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$collection</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Doctrine_Collection<span style="color: #009900;">&#40;</span><span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$objects</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$objects</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$object</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$collection</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>add<span style="color: #009900;">&#40;</span><span style="color: #000088;">$object</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #000088;">$collection</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The functions can be used like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$user1</span> <span style="color: #339933;">=</span> createUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$user2</span> <span style="color: #339933;">=</span> createUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$user3</span> <span style="color: #339933;">=</span> createUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
save<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user2</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$coll</span> <span style="color: #339933;">=</span> collection<span style="color: #009900;">&#40;</span><span style="color: #000088;">$user1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$user3</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// etc.</span></pre></div></div>

</div>
<h3>Pulling All Levers</h3>
<p>Now that we have optimized our test code to the highest degree, there is one last thing we can do: Increase the hardware power of the test computers and optimize the test suite to utilize its power.</p>
<p>Because most CPUs nowadays feature multiple cores, you should design your test suite for parallel processing. Make sure that no two tests are using the same resources (another benefit of the in-memory databases) and use a testing framework of your choice that supports multiprocessing.</p>
<p>Lime 2, for example, supports multiprocessing by adding the <code>--processes</code> option:</p>
<pre class="code">$ php lime --processes=16</pre>
<p>While most of my CPU cores are pretty bored when running the test suite in one process, using multiple processes sparks a sudden increase in activity. Not only that, I could record speed increases of over 300% (15 minutes in one process, 4.5 minutes in 16 processes).</p>
<h3>Conclusion</h3>
<p>As I have tried to portray in this article, writing tests alone is not enough to improve your development. If tests are slow or prevent change, your developers won&#8217;t run and use them. Fortunately there are several ways to make changes easier and to increase test speed.</p>
<p>To summarize:</p>
<ol>
<li>Test single features in unit tests. System tests should only be used to verify whether the classes collaborate correctly within different processes.</li>
<li>Decouple your classes. This allows introduction of changes without having to adapt multiple tests.</li>
<li>Only classes that really need to should deal with remote services. Replace these classes with stubs in all other tests.</li>
<li>Choose the fastest version of a remote service available. When you test database classes, use in-memory databases.</li>
<li>Only create databases during testing when you really need them</li>
<li>Only load data into the database that you really need. Do so programmatively without taking the overhead of parsing XML or YAML files.</li>
<li>Make use of multiprocessing, if supported by your testing framework.</li>
</ol>
<p>How is your testing experience? Are you satisfied with the performance of your tests?</p>
<h3>References</h3>
<p>[1] Gerard Meszaros: <em>xUnit Test Patterns. Refactoring Test Code</em>. Addison-Wesley, 2007. Page 415</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2010/03/11/writing-efficient-tests/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Thank You</title>
		<link>http://webmozarts.com/2009/09/06/thank-you/</link>
		<comments>http://webmozarts.com/2009/09/06/thank-you/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 07:32:57 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Community]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=449</guid>
		<description><![CDATA[Yesterday I returned back to Vienna from Symfony Day Cologne 2009. The conference was amazingly well organized and many people deserve credits for making it such a great experience. Thank you Andreas and Dennis for putting uncounted hours into planning the event, guiding us around the city, spending the night before fixing the wireless connection [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Yesterday I returned back to Vienna from <a href="http://www.symfonyday.com" title="Symfony Day Cologne 2009. Official Website." target="_blank" class="liexternal">Symfony Day Cologne 2009</a>. The conference was amazingly well organized and many people deserve credits for making it such a great experience.</p>
<div id="attachment_461" class="wp-caption aligncenter" style="width: 692px"><img class="size-full wp-image-461" title="Symfony Day Cologne 2009" src="http://webmozarts.com/wp-content/uploads/2009/09/3885868975_c9a286802c_b.jpg" alt="Symfony Day Cologne 2009" width="682" height="455" /><p class="wp-caption-text">© Nicolas Perriault</p></div>
<p>Thank you Andreas and Dennis for putting uncounted hours into planning the event, guiding us around the city, spending the night before fixing the wireless connection and for taking care of all the other small things that usually go by unnoticed. Thank you Isabelle for your Cologne crash course and for organizing our flights and the perfect accommodation. Thank you Nicolas for your many thoughtful advices, I really appreciate them. Thank you Xavier, Stefan, Jon and Sebastian for your refreshing company; I really enjoyed the lengthy walks around the city, even though my foot complained somewhat. Thank you all the attendees who gave me feedback about my work and my presentation. Thank you Interlution for letting us take part in your 10 year anniversary party. And thank you all the other people involved in making this event a success.</p>
<p>Events like this one are really important for the community. They put faces behind names, make friends, open up new opportunities and spread ideas. They are what open source truly is about.</p>
<p>As another result of the conference, this blog features a new page <a href="http://webmozarts.com/talks/" class="liinternal">Talks</a> where I included the slides of my presentation <strong>Best Practice Testing with Lime 2.</strong> And to those who annoyed me about Twitter &#8211; apparently some new account <a href="http://twitter.com/webmozart" title="@webmozart at Twitter" target="_blank" class="liexternal">@webmozart</a> has been created over there. Don&#8217;t know who it is, but don&#8217;t expect him to tweet too much.</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/09/06/thank-you/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Symfony Day Cologne 2009</title>
		<link>http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/</link>
		<comments>http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 09:21:34 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Community]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=413</guid>
		<description><![CDATA[Today, I will take the plane to Cologne to attend the first german Symfony Day. The one-day conference is going to take place on friday on the 28th floor of the Köln Triangle, the second highest building in Cologne. Located directly at the bank of the Rhine, the tower offers a magnificient view over the [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Today, I will take the plane to Cologne to attend the first german <a href="http://www.symfonyday.com/de/" title="Symfony Day Cologne 2009. Official Website." target="_blank" class="liexternal">Symfony Day</a>. The one-day conference is going to take place on friday on the 28th floor of the <a href="http://www.koelntriangle.de/index_eng.html" title="Köln Triangle. High-rise office block at the bank of the Rhine." target="_blank" class="liexternal">Köln Triangle</a>, the second highest building in Cologne. Located directly at the bank of the Rhine, the tower offers a magnificient view over the city. <a href="http://www.interlutions.de/" title="Interlutions. The company organizing the Symfony Day Cologne 2009." target="_blank" class="liexternal">Interlutions</a>, the company organizing the event seems to have done a very good job.</p>
<p style="text-align: center;">
<div id="attachment_429" class="wp-caption aligncenter" style="width: 683px"><img class="size-full wp-image-429" title="View from the Köln Triangle" src="http://webmozarts.com/wp-content/uploads/2009/09/triangle02.jpg" alt="View from the Köln Triangle" width="673" height="450" /><p class="wp-caption-text">Image Courtesy of KoelnTriangle.de</p></div>
<p>The conference will offer a full-day workshop held by Stefan Koopmanschap for those who are just getting started with symfony. Advanced symfony users can attend five promising speeches by <a href="http://prendreuncafe.com" title="Personal Blog of Nicolas Perriault" target="_blank" class="liexternal">Nicolas Perriault</a>, <a href="http://lacot.org" title="Personal Blog of Xavier Lacot." target="_blank" class="liexternal">Xavier Lacot</a>, Rob Bors and <a href="http://www.jwage.com" title="Website of Jonathan Wage." target="_blank" class="liexternal">Jonathan Wage</a>, who is accountable for two presentations. I had the pleasure to be invited as the fifth speaker, and I am going to talk about unit testing.</p>
<p>Automated software testing, when applied in a real context, is not always as easy as it may sometimes be portrayed. You need experience to design your software in a testable fashion, discipline to keep writing tests when pressure keeps increasing, tools to support your testing needs in the best way possible and knowledge to employ these tools efficiently. If any of these aspects is lacking, your team may very quickly end up not writing any tests at all. Even if you fight your way through the battle and manage to keep test coverage high, chances are that your tests become very slow. A bad test performance, in turn, prevents people from running them frequently enough &#8211; and turns all your testing efforts into a waste of time.</p>
<p>In my presentation I want to give you a deeper insight on what testing is all about. Not only do I want to present you best practices that worked for me, I also want you to <em>understand</em> the testing process so that you can go on developing best practices for yourself. I will try to focus on pratical examples; nevertheless I expect you to have a fair knowledge of writing and reading unit and functional tests with lime. For all those who won&#8217;t be able to join, the slides will be uploaded on this blog as soon as I probably can.</p>
<p>The presentation will also give you the opportunity to get a first glance of what <a href="http://trac.symfony-project.org/browser/tools/lime/branches/2.0" title="Lime 2. The successor of symfony's testing framework lime." target="_blank" class="liexternal">Lime 2</a> is going to offer you. I have been busy developing the successor of lime over the last months and am happy to see that it is steadily approaching alpha release. The detailed release plan is soon to be published on the <a href="http://www.symfony-project.org/blog/" title="Official blog of the symfony project." target="_blank" class="liexternal">symfony blog</a>.</p>
<p>I am already excitedly looking forward to meeting you all!</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Why sfContext::getInstance() Is Bad</title>
		<link>http://webmozarts.com/2009/07/01/why-sfcontextgetinstance-is-bad/</link>
		<comments>http://webmozarts.com/2009/07/01/why-sfcontextgetinstance-is-bad/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 07:24:31 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Best Practices]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=380</guid>
		<description><![CDATA[The &#8220;default&#8221; context does not exist. Is there any symfony developer out there who never stumbled upon this dreadful error message? I doubt it. Recently, a lot of posts have been made on the user mailing list asking for explanations and fixes. A quick search on Google for the exact phrase even returns 480 results! [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<blockquote><p>The &#8220;default&#8221; context does not exist.</p></blockquote>
<p>Is there any symfony developer out there who never stumbled upon this dreadful error message? I doubt it. Recently, a lot of posts have been made on the <a href="http://groups.google.com/group/symfony-users" title="Symfony users Google Group" target="_blank" class="liexternal">user mailing list</a> asking for explanations and fixes. A quick search on Google for the exact phrase even returns 480 results!</p>
<p>The reason for this error is quite simple though: It&#8217;s because you used <code>sfContext::getInstance()</code>. And you should never do that.<span id="more-380"></span></p>
<h3>MVC and the Context</h3>
<p>The class <code>sfContext</code> is the glue of the <em>controller layer</em> in symfony. It keeps all the relevant controller classes together: <code>sfUser</code>, <code>sfResponse</code>, <code>sfRequest</code>, <code>sfController</code> as well as some others. The reason for its existence is simplicity. These classes now only need a reference to the context to access each other. The class <code>sfController</code>, for instance, contains a protected member variable <code>$context</code>, by which it can access all the other objects without having to store seperate references.</p>
<p><code>sfContext</code> implements the <a href="http://en.wikipedia.org/wiki/Singleton_pattern" title="The Singleton pattern at Wikipedia" target="_blank" rel="nofollow" class="liwikipedia">Singleton</a> design pattern. Thus you can retrieve one of the few context instances by calling <code>sfContext::getInstance()</code> with an optional first parameter: The name of the context. If the first parameter is not given, the name is assumed to be &#8220;default&#8221;. But <code>sfContext</code> is no real Singleton. No new instance will ever be created when you call <code>sfContext::getInstance()</code>. Instead, you need to call <code>sfContext::createInstance()</code> first. If you miss to do that, you will receive exactly the error at the introduction of my post.</p>
<h3>Why to Avoid Singletons</h3>
<p>The Singleton pattern is actually one of the worst design patterns by the Gang-of-Four[1]. Because you hard-code the name of the singleton class, you create a dependency that is hard and partially impossible to substitute from outside. As a result, your class becomes unflexible and very hard to unit-test. Let&#8217;s look at a common mistake:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Product
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>sfContext<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foobar'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// do something</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><em>Listing 1</em></p>
<p>This implementation bears the following problems:</p>
<h4>Problem #1: Flexibility</h4>
<p>If you have multiple <code>sfUser</code> instances, you are not able to tell the product on which instance it should depend. The product always fetches the instance registered in the context. Also, if the context is not available (for instance in console tasks), the <code>save()</code> method fails.</p>
<h4>Problem #2: Testability</h4>
<p>For testing the <code>Product</code> class, you have to create the context including all of its dependencies. That means parsing <code>factories.yml</code>, reading the configuration files, instantiating <code>sfController</code>, <code>sfRequest</code> and many more classes. Doing so adds substantial overhead to your tests and makes them slow and prone to errors. If any of the operations during the context instantiation fails, your <code>Product</code> test will suddenly fail, even if the class <code>Product</code> is perfectly fine!</p>
<h3>How to Avoid Singletons</h3>
<p>Instead of hard-coding the call to <code>sfContext::getInstance()</code>, you should pass the context object directly to the object that needs it. If you don&#8217;t even need the context, but only one of its references like the user, pass that object instead.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Product
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> setUser<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user instanceof sfUser <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;&amp;</span>amp<span style="color: #339933;">;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'foobar'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #666666; font-style: italic;">// do something</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><em>Listing 2</em></p>
<p>This technique is called <em>Dependency Injection</em>. If you are not familiar with Dependency Injection, I recommend you to read Fabien Potencier&#8217;s <a href="http://fabien.potencier.org/article/11/what-is-dependency-injection" title="What Is Dependency Injection by Fabien Potencier" target="_blank" class="liexternal">introduction to Dependency Injection</a>. Basically there are two ways two inject dependencies into an object:</p>
<h4>Constructor Injection</h4>
<p>This type of Dependency Injection is used when a dependency is <em>required</em>. Because the dependency needs to be passed in the constructor, no object can ever be created when this dependency is not fulfilled.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Product
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><em>Listing 3</em></p>
<h4>Setter Injection</h4>
<p>This type of Dependency Injection is used when a dependency is <em>optional</em>. Because you can never be sure whether the setter has been called, you always have to verify whether the object exists before accessing its operations and properties, as we did in Listing 2.</p>
<p>Alternatively, you can also use setter injection for required dependencies if you can not override the constructor without breaking the class (this is the case for Doctrine records). In that case, you simply throw an exception if the dependency is not available.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Product
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user instanceof sfUser<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> LogicException<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'The user must be set before saving'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p><em>Listing 4</em></p>
<h3>What You Gained</h3>
<p>Because you can now inject any user object into your class, you can test the <code>Product</code> class very easily:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> StubUser <span style="color: #000000; font-weight: bold;">extends</span> sfUser
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> hasAttribute<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$name</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'foobar'</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>comment<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Products with the attribute &quot;foobar&quot; do something special upon saving'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000088;">$p</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Product<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$p</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setUser<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> StubUser<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$p</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>save<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #339933;">...</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><em>Listing 5</em></p>
<h3>Exceptions</h3>
<p>In very few cases, you cannot avoid accessing the context by using <code>sfContext::getInstance()</code>. This is almost always the case when symfony manages the construction of an object. If you configure symfony to use a custom object by modifying <code>factories.yml</code>, you still won&#8217;t be able to inject custom objects.</p>
<p class="info">This will change as soon as symfony uses the new <a href="http://components.symfony-project.org/dependency-injection/" title="Website of the Symfony Dependency Injection Component" target="_blank" class="liexternal">Dependency Injection container</a> for the construction of the core classes.</p>
<p>An example for this problem is extending <code>sfResponse</code>. You can tell symfony to use a custom response, but you cannot tell symfony to inject the context or other objects into it (except for if you write a custom <code>sfFactoryConfigHandler</code>). In this case, and because <code>sfResponse</code> is part of the <em>controller layer</em>, you should be pragmatic and just use <code>sfContext::getInstance()</code>.</p>
<h3>Conclusion</h3>
<p>Always try to avoid calling <code>sfContext::getInstance()</code>. Many of symfony&#8217;s classes in the <em>controller layer</em> already store a reference to the context, so you can use that one instead. If no reference is available, inject the reference to the context or to whichever class you need.</p>
<h3>References</h3>
<p>[1] E. Gamma, R. Helm, R. Johnson, J. Vlissides: <em>Design Patterns. Elements of Reusable Object-Oriented Software</em>. Addison-Wesley, 1995</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/07/01/why-sfcontextgetinstance-is-bad/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
		<item>
		<title>Easy Unit Testing</title>
		<link>http://webmozarts.com/2009/06/30/easy-unit-testing/</link>
		<comments>http://webmozarts.com/2009/06/30/easy-unit-testing/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 09:06:41 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=334</guid>
		<description><![CDATA[Unit testing is a very important task of professional, scalable software development. Many tools exist to support unit testing in one or another way. All tools come with advantages and drawbacks. One of the best known test frameworks in the PHP world is PHPUnit. With the release of symfony, Fabien Potencier released another new testing [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Unit testing is a very important task of professional, scalable software development. Many tools exist to support unit testing in one or another way. All tools come with advantages and drawbacks. One of the best known test frameworks in the PHP world is <a href="http://www.phpunit.de" title="Website of the test framework PHPUnit" target="_blank" class="liexternal">PHPUnit</a>. With the release of <a href="http://www.symfony-project.org" title="Official website of the web PHP framework &quot;symfony&quot;" target="_blank" class="liexternal">symfony</a>, <a href="http://fabien.potencier.org" title="Fabien Potencier's blog" target="_blank" class="liexternal">Fabien Potencier</a> released another new testing framework for PHP: <a href="http://trac.symfony-project.org/browser/tools/lime/trunk/lib/lime.php" title="Source code of the test framework &quot;lime&quot;" target="_blank" class="liexternal">lime</a>. The biggest advantage of <em>lime</em> over <em>PHPUnit</em> surely is the conciseness of the written test code. There are several disadvantages as well, which include bad test encapsulation due to the lack of support for fixture setup and teardown, and missing support for mock object generation.</p>
<p>Today I will briefly speak about the advantages of both frameworks, and how they can be combined to result in a slicker, powerful testing framework. I will show you how easy testing really can be! And you will be able to try it out, because all the required code has already been released in  <a href="http://www.symfony-project.org/plugins/sfLimeExtraPlugin" title="The symfony plugin sfLimeExtraPlugin" target="_blank" class="liexternal">sfLimeExtraPlugin</a>.</p>
<p><span id="more-334"></span></p>
<h3>Introduction</h3>
<p>In the following sections, I will refer to a set of example classes that I will briefly describe here for your better understanding:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> User
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$storage</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> User<span style="color: #009900;">&#40;</span>SessionStorageInterface <span style="color: #000088;">$storage</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>storage <span style="color: #339933;">=</span> <span style="color: #000088;">$storage</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setAttribute<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>storage<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getAttribute<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>storage<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>The <strong>user</strong> class offers methods to store data of a user in a <strong>session storage</strong> that you need to pass to its constructor.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">interface</span> SessionStorageInterface
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> write<span style="color: #009900;">&#40;</span><span style="color: #000088;">$key</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Let&#8217;s assume that <code>SessionStorageInterface</code> specifies how session storages have to look like. They need methods to write values into the underlying layer, be it the file system or database, and methods to read values.</p>
<p>We will be writing unit tests for the <code>User</code> class. We don&#8217;t want to use a real session storage class though, because we don&#8217;t want the test to rely on the file system or a database. Thus we will create a <em>fake implementation</em> of <code>SessionStorageInterface</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> StubSessionStorage implements SessionStorageInterface
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> write<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>name <span style="color: #339933;">=</span> <span style="color: #000088;">$name</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>value <span style="color: #339933;">=</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #000088;">$name</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$name</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>name ? <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>value <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p class="note">Fake implementations like this are called &#8220;Stubs&#8221;. Obviously, they would never make sense in a production environment. Their sole purpose is to help us testing, as in our case, the <code>User</code> class.</p>
<h3>PHPUnit and the xUnit Family</h3>
<p>Back in 1999, <a href="http://www.threeriversinstitute.org/Kent%20Beck.htm" title="Kent Beck's page at the Three Rivers Institute" target="_blank" class="liexternal">Kent Beck</a> wrote &#8220;the mother of all unit          testing frameworks&#8221;; it was called &#8220;SUnit&#8221; and supported unit testing for <a href="http://en.wikipedia.org/wiki/Smalltalk" title="Smalltalk at Wikipedia" target="_blank" rel="nofollow" class="liwikipedia">Smalltalk</a>[1]. <a href="http://sunit.sourceforge.net" title="Unit testing framework for Smalltalk" target="_blank" class="liexternal">SUnit</a> lead to a further testing framework, that Beck wrote in cooperation with Erich Gamma: <a href="http://www.junit.org" title="Unit testing framework for Java" target="_blank" class="liexternal">jUnit</a>, for Java. Today, <em>jUnit</em> is the most popular and widely-used unit testing framework for Java and hence it was ported to many other languages: <em>CppUnit</em> for C++, <em>NUnit</em> for C# or <em>PHPUnit</em> for PHP. All those frameworks together are often referred to as the<strong> xUnit family</strong>[2].</p>
<p><a href="http://www.phpunit.de/" title="Website of the test framework PHPUnit" target="_blank" class="liexternal">PHPUnit</a> is a high-quality port of <em>jUnit</em> to PHP written by <a href="http://sebastian-bergmann.de" title="Sebastian Bergmann's personal website" target="_blank" class="liexternal">Sebastian Bergmann</a>, currently available in stable version 3.3. A typical test case with <em>PHPUnit</em> looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> UserTest <span style="color: #000000; font-weight: bold;">extends</span> PHPUnit_Framework_TestCase
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$sessionStorage</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> setUp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>sessionStorage <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StubSessionStorage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>sessionStorage<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testAttributesAreReadFromTheSession<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// fixture setup</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>sessionStorage<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// execute test</span>
    <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #666666; font-style: italic;">// verify results</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>assertEquals<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'The value was read from the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> testAttributesAreWrittenToTheSession<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
  <span style="color: #666666; font-style: italic;">// ...</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>What does this code do? First of all, we see that the test code is organized within a <em>test class</em>. This means that you can use all the power of object-orientation for testing, but it also implies that a certain amount of code overhead is required for defining the class&#8217;s structure.</p>
<p>All methods prefixed with &#8220;test&#8221; are <em>test methods</em>. These methods test that a certain requirement is successfully fulfilled by the tested class. Because most of the test methods need a common set of objects (the &#8220;fixture&#8221;), these objects are created in the method <code>setUp()</code>, which is executed once before every test method. As a result, each test method works with fresh objects; influences of the previously executed test methods are largely prevented.</p>
<p>We also notice that test methods have descriptive names (which, to be honest, tend to look very weird). The purpose is to allow the reader to quickly scan the method names of a test class to receive an impression of the tested class&#8217;s abilities.</p>
<p>In our single, exemplary test method, we first set up the fixture; we tell the fake session storage, which has been instantiated in <code>setUp()</code>, to return the value &#8220;Bar&#8221; when the method <code>read("Foo")</code> is called. Then we call <code>getAttribute("Foo")</code> on the user, which we expect to read from the session. In the last line of code, we assert that the returned value has indeed been read from the session.</p>
<h3>Lime</h3>
<p><em>Lime</em> is a testing framework created by <a href="http://fabien.potencier.org/" title="Fabien Potencier's blog" target="_blank" class="liexternal">Fabien Potencier</a> for testing the source code of the web framework <a href="http://www.symfony-project.org/" title="Official website of the web PHP framework &quot;symfony&quot;" target="_blank" class="liexternal">symfony</a>. It is based on the <em>Test::More</em> Perl library and aims for a very concise and readable test code. The above test in <em>lime</em> looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> lime_test<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>comment<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Attributes are read from the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// fixture</span>
  <span style="color: #000088;">$s</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StubSessionStorage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$u</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000088;">$s</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$s</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// test</span>
  <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$u</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// assertions</span>
  <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'The value was read from the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>comment<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Attributes are written to the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// ...</span></pre></div></div>

<p>Contrary to <em>PHPUnit</em>, <em>lime</em> tests are written in a procedural way. Thus the code is more concise, because you don&#8217;t need to write down structural information of the code.</p>
<p>Initially a <code>lime_test</code> object is created, which tracks the number of expected, successful and failing tests and offers several methods to make testing easier. Each test case is, by convention, introduced by a comment that explains the tests purpose. Therefore the method <code>comment()</code> is called, which does also print the comment on the console when executing the test.</p>
<p>The test fixture has to be created manually for each test case. This is very prone to errors, because you can easily forget to reassign a variable once in a while. Then you&#8217;ll suddenly deal with an object left over from a previous test, which may lead to strange and unexpected test results.</p>
<h3>Pro and Contra</h3>
<p>Let us roughly sum up the advantages and disadvantages of both frameworks:</p>
<p><strong>PHPUnit&#8230;</strong></p>
<ul>
<li>&#8230; is verbose</li>
<li>&#8230; offers magic methods like <code>setUp()</code>, which initiates your test fixture before every test</li>
<li>&#8230; offers other convenient tools not covered in this blog post, like mocking support</li>
</ul>
<p><strong>lime&#8230;</strong></p>
<ul>
<li>&#8230; is concise and readable</li>
<li>&#8230; requires code repetition</li>
<li>&#8230; requires you to initiate your fixture manually</li>
</ul>
<p>sfLimeExtraPlugin extends <em>lime</em> and tries to introduce concepts of the xUnit family without making tests more verbose. Quite the opposite, because sfLimeExtraPlugin supports <em>annotations</em>, the written tests are even more concise than without this plugin.</p>
<h3>Annotation-Driven Tests</h3>
<p>The above test case, written with support of sfLimeExtraPlugin, looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> lime_test_simple<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Before</span>
<span style="color: #000088;">$s</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> StubSessionStorage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$u</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000088;">$s</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: Attributes are read from the session</span>
<span style="color: #666666; font-style: italic;">// fixture</span>
<span style="color: #000088;">$s</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// test</span>
<span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$u</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// assertions</span>
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'The value was read from the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: Attributes are written to the session</span>
<span style="color: #666666; font-style: italic;">// ...</span></pre></div></div>

<p class="info">This test leads to <em>exactly the same</em> test results and console output as the test written with plain <em>lime</em> earlier in this post.</p>
<p>sfLimeExtraPlugin introduces the new class <code>lime_test_simple</code>. When you use that test class, you can mark sections of your code with so-called <a href="http://en.wikipedia.org/wiki/Java_annotation" title="Java annotations at Wikipedia" target="_blank" rel="nofollow" class="liwikipedia">annotations</a>. The test class knows, for example, that code annotated with <code>@Before</code> must be executed before every test case.</p>
<p>Single test cases are annotated with <code>@Test</code>. You can also add a comment about the purpose of the test. Note that the comment now really is a <em>PHP comment</em>, which is usually highlighted in a different color by code editors and thus disturbs the eye much less than the call to the method <code>comment()</code>.</p>
<p>Several other annotations are available. I&#8217;ll shortly list all of them:</p>
<dl>
<dt>@Test</dt>
<dd>A test case</dd>
<dt>@Before</dt>
<dd>Executed before each test case</dd>
<dt>@After</dt>
<dd>Executed after each test case</dd>
<dt>@BeforeAll</dt>
<dd>Executed once before all test cases</dd>
<dt>@AfterAll</dt>
<dd>Executed once after all test cases</dd>
</dl>
<p>With these annotations, you can easily structure your test code and avoid code duplication while making your tests easier to read.</p>
<h3>Testing for Exceptions</h3>
<p>Contrary to plain <code>lime_test</code>, <code>lime_test_simple</code> allows you to automatically test whether exceptions are thrown. With plain <code>lime_test</code>, such a test would look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>comment<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'setAttribute() throws an exception if the data contains &amp;lt;script&amp;gt; tags'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #666666; font-style: italic;">// fixture</span>
  <span style="color: #000088;">$u</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> StubSessionStorage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #666666; font-style: italic;">// test</span>
  try
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$u</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&amp;lt;script&amp;gt;alert(&quot;Evil!&quot;)&amp;lt;/script&amp;gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>fail<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'setAttribute() throws an &quot;InvalidArgumentException&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  catch <span style="color: #009900;">&#40;</span>InvalidArgumentException <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>pass<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'setAttribute() throws an &quot;InvalidArgumentException&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>In this test, we try to catch the expected exception. If the exception is caught, we mark  the test as passed, otherwise as failed.</p>
<p>With <code>lime_test_simple</code>, this is much easier:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// @Before</span>
<span style="color: #000088;">$u</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> StubSessionStorage<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: setAttribute() throws an exception if the data contains &amp;lt;script&amp;gt; tags</span>
<span style="color: #666666; font-style: italic;">// fixture</span>
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>expect<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'InvalidArgumentException'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// test</span>
<span style="color: #000088;">$u</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'&amp;lt;script&amp;gt;alert(&quot;Evil!&quot;)&amp;lt;/script&amp;gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3>Mock and Stub Objects</h3>
<p>Like <em>PHPUnit</em>, sfLimeExtraPlugin allows you to automatically generate fake objects, which are referred to as &#8220;Mocks&#8221; and &#8220;Stubs&#8221;. So far, we had to write our fake <code>StubSessionStorage</code> class by hand. With sfLimeExtraPlugin this is not needed anymore. The component <code>lime_mock</code> will generate such a class automatically:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// @Before</span>
<span style="color: #000088;">$s</span> <span style="color: #339933;">=</span> lime_mock<span style="color: #339933;">::</span><span style="color: #004000;">create</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'SessionStorageInterface'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$u</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> User<span style="color: #009900;">&#40;</span><span style="color: #000088;">$s</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// @Test: Attributes are read from the session</span>
<span style="color: #666666; font-style: italic;">// fixture</span>
<span style="color: #000088;">$s</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>returns<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Bar'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$s</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>replay<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// test</span>
<span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$u</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getAttribute<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Foo'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// assertions</span>
<span style="color: #000088;">$t</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>is<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Bar'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'The value was read from the session'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Before the execution of each test case, we tell <code>lime_mock</code> to generate a new fake instance of <code>SessionStorageInterface</code>. In the test itself, we teach the fake object which methods can be called with what parameters and which value should be returned. We can also specify other constraints, such as how often a method may be called or which exception it should throw.</p>
<p>Then we switch the fake object into &#8220;replay&#8221; mode. In this mode, the fake object will behave just the way that we configured it before.</p>
<p class="note">You can create stubs for interfaces, classes or abstract classes. You can even create stubs for non-existing classes, which is very convenient if you develop test-driven.</p>
<p>Because this topic deserves a whole blog post of its own, I won&#8217;t go into more detail here. For more information about Mocks and Stubs in general and their usage in sfLimeExtraPlugin in specific can be found on the <a href="http://www.symfony-project.org/plugins/sfLimeExtraPlugin/0_2_0?tab=plugin_readme" title="Readme page of sfLimeExtraPlugin" target="_blank" class="liexternal">readme page</a> of sfLimeExtraPlugin.</p>
<h3>Final Words</h3>
<p>I personally think that tests can be written in a much more concise and readable way with sfLimeExtraPlugin. Because it also introduces other powerful features of the xUnit-family, the plugin aims to be an essential tool of every symfony developer who wants to seriously unit test his or her application.</p>
<p>Currently the plugin is available in version 0.2.0alpha. That means that the API may change before the final release (though this is unlikely) and that the code is not being considered 100% stable. I recommend you to try it out nevertheless and give me feedback about its usefulness or shortcomings, report bugs etc.</p>
<p>What do you think about sfLimeExtraPlugin? Do you think you may ever use it?</p>
<h3>References</h3>
<p>[1] Kent Beck, Donald G. Firesmith: <em>Kent Beck&#8217;s Guide to Better Smalltalk</em>. Cambridge University Press, 1998. Page 408</p>
<p>[2] Gerard Meszaros: <em>xUnit Test Patterns. Refactoring Test Code</em>. Addison-Wesley, 2007. Page 75</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/06/30/easy-unit-testing/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Improving the Forms: Layouts and Formatters</title>
		<link>http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/</link>
		<comments>http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 12:01:40 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Thinking Ahead]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=230</guid>
		<description><![CDATA[Keeping all parts of a website consistent is one of the most time consuming tasks of a web designer. Spending this time is worth doing, because the more consistent the look and feel of your website is, the more professional it appears to its users. I will show you today how symfony could help you [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Keeping all parts of a website consistent is one of the most time consuming tasks of a web designer. Spending this time is worth doing, because the more consistent the look and feel of your website is, the more professional it appears to its users.</p>
<p>I will show you today how symfony could help you keeping all of your forms consistent with very little work left for you to do.<span id="more-230"></span></p>
<div class="note">
<p>The concept presented in this article series is not implemented in symfony. It has been developed together with a few other people in the community. With these articles, I would like to receive feedback about how you like the concept and how it can be improved.</p>
<ol>
<li><a href="http://webmozarts.com/2009/04/12/improving-the-forms/" title="Improving the Symfony Forms Framework" class="liinternal">Improving the Forms</a></li>
<li><a href="http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/" title="Adding Field Groups to the Symfony Forms Framework" class="liinternal">Improving the Forms: Field Groups</a></li>
<li>Improving the Forms: Layouts and Formatters</li>
</ol>
</div>
<h3>A Quick Look Back</h3>
<p>In my last post I <a href="http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/" title="Improving the Forms: Field Groups" class="liinternal">introduced you to the concept of field groups</a>. Field groups are similar to embedded forms in that they group a set of form fields together and enable combined data binding and validation. They differ from embedded forms in that they can combine multiple fields to enter one single value. I showed you the example of a password field with two fields, that is used to enter one single value: The password.</p>
<p>Here is the code for the user profile form that we have developed in the course of this article series:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfTextField<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Your full name, f.i. &quot;John Travolta&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfEmailField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'A valid email address, f.i. &quot;john.travolta@gmail.com&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> VerifiedPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Must not be &quot;pulpfiction&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setEditable<span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>I invite you to compare this form with the <a href="http://webmozarts.com/2009/04/12/improving-the-forms/" title="Improving the Forms" class="liinternal">original symfony implementation of the same functionality</a> shown in my first post.</p>
<h3>Form Layouts</h3>
<p>Today I want to present you another advantage of the field groups. You can use &#8220;layouts&#8221; on them to automate the generation of HTML code in a very flexible way.</p>
<p>Right now, symfony offers two alternatives to create the HTML code of your forms.</p>
<ol>
<li>Use one of the built-in form formatters &#8220;list&#8221; and &#8220;table&#8221;. These formatters are very unflexible because the whole form will be rendered in the same way. You cannot modify the formatters to render some parts as fieldsets, others as multi-column fields etc.</li>
<li>Code the HTML by hand in your templates. This way gives the most power to web designers. Unfortunately it also leads to a lot of code duplication in your templates that cannot be easily resolved by using partials. Maintaining this duplicate code is <a href="http://fabien.potencier.org" title="Fabien Potenciers favourite quote" target="_blank" class="liexternal">quite repetitive, tedious, and error prone</a>™ <img src='http://webmozarts.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </li>
</ol>
<p>Layouts help you to solve this problem. But what exactly are layouts?</p>
<p>In general, a layout is a set of different classes (the &#8220;formatters&#8221;) that specify how different parts of a form should be rendered. Look at the following sketch to get an idea of what layouts can do for you:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-234" title="Layout examples" src="http://webmozarts.com/wp-content/uploads/2009/04/layouts.gif" alt="Layout examples" width="606" height="139" /></p>
<p>Usually, layouts render the individual fields in rows with the label to the left and the field to the right. You can change individual fields or field groups to be rendered in a different way: As fieldset (useful for field groups), with the label to the right (useful for checkboxes), with no label at all or with your very own custom formatter.</p>
<p>But layouts can do much more than formatting the individual rows: They also know how the formatted fields should be visually organized. You can, for example, display all fields in a horizontal row or organize them in a grid with multiple columns.</p>
<p>Each field group (the form is also a field group) has exactly one layout assigned that is used to organize the fields in this group. Because field groups can be nested within each other, you can also nest different layouts. Let&#8217;s look at a basic example that can be achieved very easily:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-235" title="Profile form with layouts" src="http://webmozarts.com/wp-content/uploads/2009/04/profile-form-layouts.png" alt="Profile form with layouts" width="525" height="324" /></p>
<p>The password field and the permissions field group are configured to be formatted as fieldset. The permissions field group itself has a multi-column layout applied. Later in this post I will show you how little PHP code is necessary to achieve this result.</p>
<p>Apart from the visual aspect, layouts specify which HTML code will be used to render the form. <code>sfListLayout</code> renders the form in an <code>ul</code> tag, <code>sfTableLayout</code> renders the form in a &#8230; guess what .. right, in a <code>table</code> tag. Of course you can also implement your own layout that renders the whole form in a combination of <code>address</code> and <code>blockquote</code> tags, if that makes sense to you (tag misuse at its best!).</p>
<h3>Multi-Column Layouts</h3>
<p>Layouts with multiple columns are especially interesting. They help you to display a lot of information in little, well-organized space.</p>
<p>If you use <code>ul</code>-tags to render your form, a multi-column layout can be achieved very easily. You just need to change the CSS of the <code>li</code>-tags to make them floating. By giving them a fixed width, you can control how many form fields are displayed in a row.</p>
<p>There is a big problem with this solution though: Fields are first rendered from left to right, then from top to bottom.</p>
<p>This can be a problem if your fields are sorted in a specific order. A good example are large lists of checkboxes. If the labels of these fields are sorted alphabetically, users expect them to be sorted from top to bottom, then from left to right.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-237" title="Layouts with multiple columns" src="http://webmozarts.com/wp-content/uploads/2009/04/multi-column-layouts.gif" alt="Layouts with multiple columns" width="401" height="138" /></p>
<p>Layouts are able to deal with this problem easily. You can configure the number of columns and the order of the fields (&#8220;horizontal&#8221; or &#8220;vertical&#8221;) simply by passing these options to the layout&#8217;s constructor.</p>
<h3>Show Me the Code</h3>
<p>Configuring layouts in your form is easy. Every class inheriting from <code>sfFormFieldGroup</code> (thus also <code>sfForm</code>) offers the method <code>setLayout()</code>. To this method you can pass an instance of the layout you want to use.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfListLayout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>The different layout classes allow different options that you can pass to their constructor. Two such options are the number of columns and the order in which the fields are put into these columns.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfListLayout<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'columns'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'order'</span>   <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> sfLayout<span style="color: #339933;">::</span><span style="color: #004000;">VERTICAL</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>With as little code as this you have configured your form to organize all fields in 3 columns in a vertical order using <code>ul</code> and <code>li</code>-tags. You can achieve the same result using an HTML table by passing an instance of <code>sfTableLayout</code> instead of <code>sfListLayout</code>.</p>
<p>The format of the individual form fields can be modified by calling the method <code>setFormat()</code> on the field. To this method you pass the name of the format you want to use. The names of the different formats are declared in the layout class, as you will see later.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> VerifiedPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFormat<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fieldset'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>After this simple definition, the password fields are rendered as in the picture above. Depending on the layout, there can be many more formats like &#8220;leftlabel&#8221; (the default), &#8220;nolabel&#8221; or &#8220;rightlabel&#8221;. Look at the first sketch in this post to see what these look like.</p>
<h3>A More Complex Example</h3>
<p>Now that we have learned about the basics, we can look at how to configure our user profile form to be displayed like in the above picture.</p>
<p>First, we tell our form to be rendered as HTML list.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfListLayout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Now we add the fields as we did before. Note the format that we have set on the password field to render it as a fieldset.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfTextField<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Your full name, f.i. &quot;John Travolta&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfEmailField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'A valid email address, f.i. &quot;john.travolta@gmail.com&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> VerifiedPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Must not be &quot;pulpfiction&quot;'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFormat<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fieldset'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Just for fun, we&#8217;ll add a few checkboxes to our form to demonstrate how a multigrid layout is integrated.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #000088;">$permissions</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'admin'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'blog-editor'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'content-editor'</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'publisher'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'file-editor'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comment-editor'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'permissions'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfCheckboxList<span style="color: #009900;">&#40;</span><span style="color: #000088;">$permissions</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Choose one or more permissions for this user'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFormat<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fieldset'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfListLayout<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'columns'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The last thing left is to declare the final validator and the user credential check again, but this code has not changed.</p>
<p>Let&#8217;s sum up what we have learned:</p>
<ol>
<li>A <strong>format</strong> is the definition of how a <em>single field</em> is rendered</li>
<li>A <strong>layout</strong> is the definition of how a <em>group of fields</em> is organized</li>
</ol>
<h3>But What About the Web Designers?</h3>
<p>I can hear voices screaming that I am violating the MVC separation with this proposal. But honestly, I am not. <img src='http://webmozarts.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  We still have one specific component that is responsible for generating the output of our form: The <code>sfLayout</code> instance. You can simply modify the way your form is rendered by exchanging its layout, which is what MVC is all about.</p>
<p class="info">Many people misunderstand the MVC concept as it is applied in symfony. Although the view layer consists mostly of templates, it is not restricted to that. MVC simply requires you to program separate decoupled layers that can be easily exchanged. Whether you put the code of these layers in templates, classes or coke cans does not matter.</p>
<p>The good news is that you can do all the configuration from within your templates, if you don&#8217;t like to do it in your <code>configure()</code> method. All of the above methods are accessible using <code>sfForm</code>&#8216;s array access syntax. Together with a set of easy convenience methods, even web designers could configure the form&#8217;s format.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php <span style="color: #000088;">$form</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'list'</span><span style="color: #009900;">&#41;</span> ?<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span>
<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php <span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFormat<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fieldset'</span><span style="color: #009900;">&#41;</span> ?<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span>
<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php <span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'permissions'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFormat<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'fieldset'</span><span style="color: #009900;">&#41;</span> ?<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span>
<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php <span style="color: #000088;">$form</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'permissions'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLayout<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'list'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'columns'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> ?<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span>?php <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$form</span> ?<span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span></pre></div></div>

<p class="note">For small projects with one or only very few forms, I recommend you to not use layouts and formatters, if that eases the life of your web designers. You can still output the form the oldfashioned way and write all the HTML by hand.</p>
<h3>sfLayout Internals</h3>
<p>In the last part of our travel to the magic layout wonderland, I want to explain some of the internals of <code>sfLayout</code> to you.</p>
<p class="note">
The information in this section is only relevant when you create your own layout. You hardly ever need this information to simply configure your form.
</p>
<p>All layouts must implement <code>sfLayoutInterface</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">interface</span> sfLayoutInterface
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> createFieldFormatter<span style="color: #009900;">&#40;</span><span style="color: #000088;">$format</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> createFieldGroupFormatter<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Layouts follow the <em>Abstract Factory Pattern</em>. That means that any class implementing <code>sfLayoutInterface</code> simply creates instances of other classes that are connected in some way.</p>
<p>Let&#8217;s visualize this very technical definition with a simple example: <code>sfListLayout</code> is able to create new <code>sfFieldFormatter</code> instances as well as <code>sfFieldGroupFormatter</code> instances. Because both instances must know that the form is rendered as <code>ul</code>-list, they structurally belong together. If you use a different layout, you get a different set of formatters that again know about each other. That&#8217;s what this pattern is about.</p>
<p class="info">It is the responsibility of <code>sfFieldFormatter</code> and <code>sfFieldGroupFormatter</code> instances to turn the fields/field groups into HTML code.</p>
<p><code>sfLayoutInterface::createFieldFormatter()</code> has one single parameter &#8220;format&#8221;. This format is exactly the format string that you have set on the form fields earlier using <code>setFormat()</code>. For each given format, the layout knows which object to return.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$layout</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfListLayout<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$formatter</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$layout</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>createFieldFormatter<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'rightlabel'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$formatter</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// returns &quot;sfRightLabelListFieldFormatter&quot;</span></pre></div></div>

<p>The great thing is that you never need to know about these long class names, because the layout you use hides them from you. All returned objects share the same interface: <code>sfFieldFormatterInterface</code>. You only ever need to know about this interface and never about the concrete class you receive.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">interface</span> sfFieldFormatterInterface
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> render<span style="color: #009900;">&#40;</span><span style="color: #000088;">$id</span><span style="color: #339933;">,</span> <span style="color: #000088;">$label</span><span style="color: #339933;">,</span> <span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #000088;">$help</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$attributes</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Conclusion</h3>
<p>Enough theory for today. I hope I was able to give you an idea of what power layouts can give to you. As you have seen, they can reduce code duplication in large applications with many forms and simplify the presentation of forms. There is much more to tell about layouts, but this post has grown long enough.</p>
<p>How do you like the layouts? Is this idea worth the time following?</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Improving the Forms: Field Groups</title>
		<link>http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/</link>
		<comments>http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/#comments</comments>
		<pubDate>Sun, 19 Apr 2009 10:56:41 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Thinking Ahead]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=195</guid>
		<description><![CDATA[Today I want to follow up on my last post about improving the forms in symfony. David Hermann wrote a quite interesting reply on his blog. I want to take some of his ideas and enhance them even further. The goal is to be able to reuse as much code as possible when creating applications [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Today I want to follow up on my <a href="http://webmozarts.com/2009/04/12/improving-the-forms/" title="Improving the Forms" class="liinternal">last post about improving the forms</a> in symfony. David Hermann wrote <a href="http://blog.vworld.at/2009/04/14/improving-the-forms-even-more/" title="Improving the forms even more. David's virtual world. A blog about symfony and software in general." target="_blank" class="liexternal">a quite interesting reply on his blog</a>. I want to take some of his ideas and enhance them even further. The goal is to be able to reuse as much code as possible when creating applications with lots of different forms.</p>
<p>This post will be different though. While I only made assumptions in my last post without any code verifying that my ideas are implementable, I do have a prototype implementation now.<span id="more-195"></span></p>
<div class="note">
<p>The concept presented in this article series is not implemented in symfony. It has been developed together with a few other people in the community. With these articles, I would like to receive feedback about how you like the concept and how it can be improved.</p>
<ol>
<li><a href="http://webmozarts.com/2009/04/12/improving-the-forms/" title="Improving the Symfony Forms Framework" class="liinternal">Improving the Forms</a></li>
<li>Improving the Forms: Field Groups</li>
<li><a href="http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/" title="Using Layouts to Easily Generate the HTML Code of Symfony Forms" class="liinternal">Improving the Forms: Layouts and Formatters</a></li>
</ol>
</div>
<h3>Where Did We Stop?</h3>
<p>In my last post, we left with the following form:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-202" title="Basic Profile Form" src="http://webmozarts.com/wp-content/uploads/2009/04/profile-form-basic.png" alt="Basic Profile Form" width="442" height="180" /></p>
<p>The idea was to have a user profile form where we can enter the name of the user, his email address and his password and are able to validate a few special conditions. I added a few help texts to enhance the look and usability of the form. Here is the code for the form:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgetAttributes<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidatorOptions<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Your full name, f.i. &quot;John Travolta&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'A valid email address, f.i. &quot;john.travolta@gmail.com&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Must not be &quot;pulpfiction&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The passwords must be equal'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setEditable<span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>I introduced you to the concept of form fields that bundle a widget and a validator. If you have not read <a href="http://webmozarts.com/2009/04/12/improving-the-forms/" title="Improving the Forms" class="liinternal">the post explaining this concept</a>, I recommend you to read it now, because I will build up on it today.</p>
<h3>Convention Over Configuration</h3>
<p>Many forms in symfony applications share the same type of fields. An email address, for example, is in 95% of the cases a normal input widget with an email validator. Redefining this definition in different forms leads to code duplication, so we should extract it into a separate field type. If we do this for the most common field types, we come up with a nice little collection of fields that should be bundled with symfony by default:</p>
<ul>
<li><code>sfTextField</code> (<code>sfWidgetInput</code>, <code>sfValidatorString</code>)</li>
<li><code>sfTextareaField</code> (<code>sfWidgetTextarea</code>, <code>sfValidatorString</code>)</li>
<li><code>sfPasswordField</code> (<code>sfWidgetInputPassword</code>, <code>sfValidatorString</code>)</li>
<li><code>sfEmailField</code> (<code>sfWidgetInput</code>, <code>sfValidatorEmail</code>)</li>
<li><code>sfCheckboxField</code> (<code>sfWidgetCheckbox</code>, <code>sfValidatorBoolean</code>)</li>
<li><code>sfCountryField</code> (<code>sfWidgetI18nSelectCountry</code>, <code>sfValidatorI18nSelectCountry</code>)</li>
<li><code>sfLanguageField</code> (<code>sfWidgetI18nSelectLanguage</code>, <code>sfValidatorI18nSelectLanguage</code>)</li>
<li><code>sfSelectField</code> (<code>sfWidgetSelect</code>, <code>sfValidatorChoice</code>)</li>
</ul>
<p>I might have forgotten quite a few now, but you see where I am heading. With a decent collection of predefined fields you will only need to manually define widgets and validators in edge cases. This is especially great for beginners who do not have to learn about widgets and validators to create simple forms!</p>
<p>Let&#8217;s look at how we can reduce the above form definition even more by using these predefined fields:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfTextField<span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Your full name, f.i. &quot;John Travolta&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfEmailField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'A valid email address, f.i. &quot;john.travolta@gmail.com&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Must not be &quot;pulpfiction&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The passwords must be equal'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3>Field Groups</h3>
<p>So far, I have left the question open about how we can bundle the two password fields together, so you can just drop them into any form. The idea to solve this problem is to create field groups <a href="http://blog.vworld.at/2009/04/14/improving-the-forms-even-more/" title="Improving the forms even more. David's virtual world. A blog about symfony and software in general." target="_blank" class="liexternal">as proposed by David</a>.</p>
<p>A field group is simply a collection of fields that logically belong together. These fields may share a common initial and final validator, a common label, a common help text and a few other things. You will see that field groups are very similar to embedded form as they exist right now.</p>
<p class="info">In fact, a form <em>is</em> a field group with a few extra abilities such as CSRF protection, form tag generation etc.</p>
<p>Normal fields and field groups share a common interface. In practice, this means that you can simply add groups by calling <code>addField()</code> and nest groups inside each other. It does also mean that the developer doesn&#8217;t necessarily need to know whether a field is a &#8220;normal&#8221; field or a field group, which is exactly what we will do with the password field.</p>
<p>To understand the implementation, we will look at the common interface <code>sfFormFieldInterface</code> first:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">interface</span> sfFormFieldInterface
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> bind<span style="color: #009900;">&#40;</span><span style="color: #000088;">$taintedValue</span><span style="color: #339933;">,</span> <span style="color: #000088;">$taintedFile</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getId<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getLabel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getHelp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> render<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #339933;">...</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p class="info">You may wonder what the methods <code>bind()</code> and <code>getData()</code> do in a form field. To use the real power of object orientation, the bound values are delegated from the form to all nested fields and field groups, where they are validated. The form can collect the cleaned values again by calling <code>getData()</code> on all fields and field groups. Because embedded forms are nothing more than field groups, this implementation also solves the common problem that <code>bind()</code> is not called on embedded forms.</p>
<p>Now we can finally implement our combined password field. The combined field extends <code>sfFormFieldGroup</code> which already implements <code>sfFormFieldInterface</code>, so we only need to configure the field:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> VerifiedPasswordField <span style="color: #000000; font-weight: bold;">extends</span> sfFormFieldGroup
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'first'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'second'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'second'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'first'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The passwords must be equal'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now we can simply drop our password field into the form:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> VerifiedPasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Must not be &quot;pulpfiction&quot;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Alert readers might have noticed that the password fields are now named &#8220;first&#8221; and &#8220;second&#8221;. Do you wonder how that will be translated into form field names? It works just the same way as it does now for embedded forms: The name of the internal field is appended to the name of the external field in squared brackets (f.i. &#8220;password[first]&#8220;).</p>
<p>Now you probably think that this implementation makes things harder than they were! When processing the values after a successful validation, we need to know that the password is stored in &#8220;password[first]&#8221; instead of simply &#8220;password&#8221;!</p>
<p>Calm down old boy, help is on the way. To find our solution, let&#8217;s look at the output of the method <code>VerifiedPasswordField::getData()</code>, which returns the cleaned values of the field group:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// VerifiedPasswordField::getData()</span>
<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'first'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The password'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'second'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The password'</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span></pre></div></div>

<p>Hm, any idea? Let&#8217;s also look at the output of <code>ProfileForm::getData()</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// ProfileForm::getData()</span>
<span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
  <span style="color: #0000ff;">'name'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The name'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'email'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'thename@gmail.com'</span><span style="color: #339933;">,</span>
  <span style="color: #0000ff;">'password'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
    <span style="color: #0000ff;">'first'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The password'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'second'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The password'</span><span style="color: #339933;">,</span>
  <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
<span style="color: #009900;">&#41;</span></pre></div></div>

<p>Did you already find the solution? I&#8217;ll tell you: It&#8217;s fairly easy. We just need to modify <code>getData()</code> in <code>VerifiedPasswordField</code> to just return a single password instead of an array.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$data</span> <span style="color: #339933;">=</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">getData</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$data</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'first'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p class="info">Now you probably understand why <code>getData()</code> isn&#8217;t named <code>getValues()</code>, like it is in the forms framework right now. The problem is that <code>getData()</code> can return single values (in simple fields) or arrays (in field groups). Naming the method <code>getValues()</code> would implicate that it always returns an array.</p>
<h3>Time To Relax</h3>
<p>If you made it until here, the hardest part of this post is over. Field groups allow us to easily implement and reuse a set of fields. As you have seen, we can even use field groups as if they were a single field. Especially in large applications, this architecture can hugely simplify your form definitions and reduce duplicate code.</p>
<p>You can, of course, create field groups on the fly, if you want to logically group fields together:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$group</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addGroup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'personal'</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Personal Information'</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setHelp<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Please enter your personal information here so we can sell it'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$group</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'first_name'</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'First name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$group</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'surname'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<div class="info">Calling</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$form</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addGroup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'groupname'</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>without explicitly passing an <code>sfFormFieldGroup</code> instance has the same effect as calling</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$form</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addGroup<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'groupname'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfFormFieldGroup<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>or</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$form</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'groupname'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfFormFieldGroup<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span></pre></div></div>

</div>
<p>In my next post, I will speak about how formatters and group layouts can help you to reduce duplicate code in your form templates and help you to sustain a uniform look in applications with many forms. You will learn that the structural information stored in field groups can easily be used to generate a visually appealing presentation.</p>
<p>How do you like the field groups? Are there any use cases that cannot be implemented with this architecture?</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Improving the Forms</title>
		<link>http://webmozarts.com/2009/04/12/improving-the-forms/</link>
		<comments>http://webmozarts.com/2009/04/12/improving-the-forms/#comments</comments>
		<pubDate>Sun, 12 Apr 2009 10:25:21 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Thinking Ahead]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=161</guid>
		<description><![CDATA[After my last post about simplifying symfony and especially the forms framework, I started diving into the forms framework to find out how we could improve it. I tried to find ways to improve the usability of this framework without reducing its mighty possibilities. Quite the contrary, I think that the forms can be made [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>After my last <a href="http://webmozarts.com/2009/04/07/no-piece-of-cake/" title="No Piece of Cake" class="liinternal">post about simplifying symfony</a> and especially the forms framework, I started diving into the forms framework to find out how we could improve it. I tried to find ways to improve the usability of this framework without reducing its mighty possibilities. Quite the contrary, I think that the forms can be made even mightier than they are now.<span id="more-161"></span></p>
<div class="note">
<p>The concept presented in this article series is not implemented in symfony. It has been developed together with a few other people in the community. With these articles, I would like to receive feedback about how you like the concept and how it can be improved.</p>
<ol>
<li>Improving the Forms</li>
<li><a href="http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/" title="Adding Field Groups to the Symfony Forms Framework" class="liinternal">Improving the Forms: Field Groups</a></li>
<li><a href="http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/" title="Using Layouts to Easily Generate the HTML Code of Symfony Forms" class="liinternal">Improving the Forms: Layouts and Formatters</a></li>
</ol>
</div>
<h3>The Situation</h3>
<p>In my last post I introduced you to the following situation: A form should allow to edit a user’s name, email address and password. The name should only be editable by administrators, while the password should be entered twice to make sure it was entered correctly. The maximum length of the name is 15 characters and the password should not be the same as the name.</p>
<p>We came up with the following class:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgets<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'name'</span>           <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>widgetSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidators<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'name'</span>           <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The name must be 15 characters or longer'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter a password'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// implement custom validation logic</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>validatorSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setPostValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorSchemaCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'invalid'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The passwords must be equal'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'callback'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// only administrators may enter the user name</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// if the field &quot;name&quot; is not editable, it does not exist in $values</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;&amp;</span>amp<span style="color: #339933;">;</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$error</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #666666; font-style: italic;">// throw an error schema so the error appears at the field &quot;password&quot;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$error</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>The Issues</h3>
<p>The above form definition bears several issues:</p>
<ul>
<li>It is not possible to abstract form fields that combine a widget, a validator and possible other settings. You might want to use a password field in several forms so it should be possible to extract that definition into a separate class.</li>
<li>To configure the form, you need to know about the widget schema and the validator schema. You also need to know where to call which method. For instance, you need to call <code>setWidgets()</code> on the form, <code>setLabels()</code> on the widget schema and <code>setPostValidator()</code> on the validator schema.</li>
<li>Nearly none of the default validator error messages like &#8220;Invalid.&#8221; or &#8220;Required.&#8221; are useful in production, thus we always have to configure them. Validators should provide sensible defaults for these errors to reduce the amount of configuration.</li>
<li>Some of the used classes have complex constructor signatures that are hard to remember. <code>sfValidatorCallback</code>, for instance is always called with a callback. It should be possible to pass the callback directly to its constructor without having to create addtional arrays.</li>
<li>If the user is not administrator, the field &#8220;name&#8221; is not available. Because of that we must implement additional checks everytime we access the form values to find out whether the name has been set. But, in fact, the name value should always be there. It just is not always editable.</li>
<li>Throwing a custom validation error and binding it to a specific field is tedious.</li>
</ul>
<p>I was searching for ways to improve these issues and will explain them in more detail below.</p>
<h3>Form Field Abstraction</h3>
<p>It was very useful if you could abstract form fields in symfony that combine a validator, a widget and possible other settings. Let&#8217;s just imagine for this post that <code>sfField</code> is a class that allows bundling a widget and a validator.</p>
<p class="note">I don&#8217;t think that including the &#8220;form&#8221; in the name is necessary (f.i. <code>sfFormField</code>). The &#8220;sf&#8221; prefix is reserved to symfony core classes and I can&#8217;t think of any other context in the core where an <code>sfField</code> class could serve useful. KISS.</p>
<p>To create our custom password field, we would just extend <code>sfField</code> and combine the logic inside.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/fields/PasswordField.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> PasswordField <span style="color: #000000; font-weight: bold;">extends</span> sfField
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter a password'</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Great! A neatly decoupled definition of a password field. But how should we add this field to a form? Probably with the most obvious method name there is for this task: <code>addField()</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Can it be easier?</p>
<p class="info">You may ask yourself whether we can&#8217;t just bundle the second field for repeating our password as well. We certainly could, but I&#8217;ll leave the answer for this question to another post.</p>
<h3>Widgets and Validators</h3>
<p>As said before, we currently need to know a lot about the form&#8217;s internals to configure it successfully. We need to know about <code>sfWidgetFormSchema</code>, <code>sfValidatorSchema</code> and <code>sfForm</code> and their respective methods. Couldn&#8217;t we simplify that somewhat?</p>
<p>Let&#8217;s wait for a moment. In the previous section we introduced a new class <code>sfField</code> that bundles a widget, a validator and possible other settings. We also introduced a method <code>addField()</code> that adds a form field to the form.</p>
<p>Now we could <em>return</em> the added field from <code>addField()</code> and allow a modification of its widget, validator, label and other properties in a fluent coding style!</p>
<p>Let&#8217;s look at how the form&#8217;s <code>configure()</code> method looks like with these modifications:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetInput<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Doesn&#8217;t look too bad. To reduce the amount of code, <code>addField()</code> could always add an instance of <code>sfField</code>, if no field is given, and preconfigure it with <code>sfWidgetInput</code> and <code>sfValidatorString</code>. Then we could introduce new methods <code>sfField::setWidgetOptions()</code>, <code>sfField::setWidgetAttributes()</code> and <code>sfField::setValidatorOptions()</code> that allow a fluent modification of these properties.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// implicitly sfWidgetInput and sfValidatorString</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgetAttributes<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidatorOptions<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span> <span style="color: #666666; font-style: italic;">// implicitly sfWidgetInput</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
           <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
         <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Again our code became a bit easier to read and write. For reference, here is how the configuration of these settings was like before:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #666666; font-style: italic;">// before</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgets<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'name'</span>           <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>widgetSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidators<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'name'</span>           <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The name must be 15 characters or longer'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter a password'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Sensible Default Error Messages</h3>
<p>Nearly all default error messages of the validators are absolutely unusable in a production environment. If you listen to the big usability gurus like Jakob Nielsen (see his <a href="http://www.useit.com/alertbox/20010624.html" title="Jakob Nielsen's Error Messages Guidelines" target="_blank" class="liexternal">Error Messages Guidelines</a>), error messages should give &#8220;Constructive advice on how to fix the problem&#8221;. &#8220;Required.&#8221; and &#8220;Invalid.&#8221;, unfortunately, do not.</p>
<p>I think that all validators should be preconfigured with sensible error messages. Examples for the &#8220;required&#8221; and &#8220;invalid&#8221; errors of <code>sfValidatorEmail</code> are &#8220;Please enter an email address&#8221; and &#8220;The given email address is not valid&#8221;.</p>
<p>With sensible default messages, we can yet again reduce the complexity of our code:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #339933;">...</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Compared to before:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #666666; font-style: italic;">// before</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #339933;">...</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
           <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
         <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #339933;">...</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<h3>The Post Validator</h3>
<p>Now I&#8217;ll look at how to improve the post validator of our profile form. Basically I think the name is a bit weird. I am familiar with the latin expression &#8220;post&#8221;, but wouldn&#8217;t the english expression &#8220;final&#8221; fit in better?</p>
<p>Let&#8217;s imagine we live in an ideal world where <code>setPostValidator()</code> can be moved to <code>sfForm</code> and renamed to <code>setFinalValidator()</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span><span style="color: #339933;">...</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Okay. Next step: <code>sfValidatorAnd</code> and its contained validators. First of all, I think we could extend <code>sfValidatorAnd</code> to accept an infinite number of arguments <em>or</em> an array containing these arguments. In Java we would achieve this by overloading the method. In PHP we cannot overload methods, but due to the weak typing we can still simulate this behaviour with one method.</p>
<p>There&#8217;s another candidate for simplification: <code>sfValidatorCallback</code>. Let&#8217;s just recall the current usage of this class:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'callback'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Why is this so complicated? It&#8217;s obvious that we want to pass a callback to this class. A callback can be either a single string or an array with two entries. We can again &#8220;overload&#8221; the constructor to accept either a single argument (a function name) or two arguments (a class or object method).</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Much better. Last step: <code>sfValidatorSchemaCompare</code>. I think the usage of its constructor is pretty straight-forward. Because I can never remember its name, this validator should be renamed to <code>sfValidatorCompare</code> (KISS). Furthermore it is always necessary to pass an error message to this class, so why not make it the fourth argument?</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_repeat'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span>
    <span style="color: #0000ff;">'The passwords must match'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Now we can draw the whole picture of our final validator:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_repeat'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The passwords must match'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Isn&#8217;t this much nicer to read? Here&#8217;s the old definition again:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #666666; font-style: italic;">// before</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>validatorSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setPostValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorSchemaCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'invalid'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The passwords must be equal'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'callback'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h3>Editable vs. Non-Editable</h3>
<p>In forms it is very common to display some fields as editable and some fields as non-editable depending on the user&#8217;s rights. Just think of a common article form. The administrator may be able to change the author of an article, while the editor may only be allowed to see the author.</p>
<p>In the past, I have read several times that people would like to set fields to read-only in the admin generator. One such situation was the <a href="http://trac.symfony-project.org/wiki/Symfony12AdminGenerator#SomenotesfromKlemensUllmannklemens_u" title="Discussion in the symfony wiki about new features of the admin generator in symfony 1.2" target="_blank" class="liexternal">discussion about the admin generator for symfony 1.2</a>. Since the admin generator is now based on the forms framework, this would be essentially the same feature.</p>
<p>The idea is to extend the current <code>sfWidgetForm</code> class to have two different states: &#8220;editable&#8221; and &#8220;non-editable&#8221;. Dependent on the state, each widget renders different HTML. Let&#8217;s look at <code>sfWidgetFormInputDate</code> for example. If this widget is editable, it displays the three select fields that we all know. But if the widget is not editable, it renders the date as plain text in the configured culture.</p>
<p class="info">Do you notice something? If such a widget is implemented, it is essentially not a form widget anymore, but just &#8220;a widget&#8221;. In this case we could remove the &#8220;Form&#8221; from its name and reuse the widget in other components, such as <code>sfGrid</code> <img src='http://webmozarts.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .</p>
<p>Let&#8217;s look at the configuration of our &#8220;name&#8221; field with this new widget concept. Instead of removing the field when the user is not an administrator, we just disable it.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setEditable<span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>That&#8217;s all! Compared to before:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #666666; font-style: italic;">// before</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p class="note">The form should still populate the &#8220;name&#8221; value after submitting so that we do not have to care about whether the field was editable or not. The submitted value should just be ignored then.</p>
<h3>Throwing Custom Validation Errors</h3>
<p>Let&#8217;s be honest. Throwing custom validation errors is a pain in the ass. You must remember to pass the validator itself to the error, and then you need to construct an <code>sfValidatorErrorSchema</code> just to associate the error with a field.</p>
<p>In my opinion this should be much easier. The only reason why <code>sfValidatorError</code> requires a passed validator is to populate the error message internally. Why don&#8217;t we just pass the error message?</p>
<p>Second, <code>sfValidatorError</code>&#8216;s constructor could simply accept an optional parameter that specifies the field the validator belongs to.</p>
<p>How does that all look like? Let&#8217;s look at our refactored method <code>comparePasswordAndName()</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Now that was easy! Here&#8217;s the old definition:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #666666; font-style: italic;">// before</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// if the field &quot;name&quot; is not editable, it does not exist in $values</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;&amp;</span>amp<span style="color: #339933;">;</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$error</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #666666; font-style: italic;">// throw an error schema so the error appears at the field &quot;password&quot;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$error</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Conclusion</h3>
<p>I think we don&#8217;t need to drop object oriented concepts to facilitate the use of the forms. The interface of this framework can be easy while remaining completely well-designed and flexible.</p>
<p>Here you can see the complete new form definition. Especially note the shorter widget names.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgetAttributes<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidatorOptions<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'email'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> PasswordField<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>addField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfWidgetPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
         <span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setFinalValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The passwords must be equal'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>getField<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setEditable<span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p class="note">The above ideas are only very rough and conceptual. I was thinking about how the interface would be ideal from the user&#8217;s point of view without verifying whether it is implementable and, if yes, how. But that&#8217;s a whole different story anyway. Usually, usability should drive implementation, not the other way round.</p>
<p>I did focus this post on this specific <code>ProfileForm</code>. There are several issues with the form framework that remain to be discussed. One example is how to bundle the two password fields and their post validator to be able to just drop them into any form. Another example is the internal processing of embedded forms. But these topics belong entirely to a new post.</p>
<p>How do you like this interface? Has it flaws and how can it be improved?</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/04/12/improving-the-forms/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>No Piece of Cake</title>
		<link>http://webmozarts.com/2009/04/07/no-piece-of-cake/</link>
		<comments>http://webmozarts.com/2009/04/07/no-piece-of-cake/#comments</comments>
		<pubDate>Tue, 07 Apr 2009 20:51:25 +0000</pubDate>
		<dc:creator>Bernhard</dc:creator>
				<category><![CDATA[Thinking Ahead]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=33</guid>
		<description><![CDATA[Welcome to all of you on webmozarts.com! Whether you are a PHP developer, a symfony power user or just getting started in object-oriented web application development &#8211; this blog is for you. With our first post, I want to talk about symfony and where this blog is heading. And I don&#8217;t mean &#8220;symphony&#8221; as in [...]
No related posts.]]></description>
			<content:encoded><![CDATA[<p>Welcome to all of you on webmozarts.com! Whether you are a PHP developer, a symfony power user or just getting started in object-oriented web application development &#8211; this blog is for you.</p>
<p>With our first post, I want to talk about symfony and where this blog is heading. And I don&#8217;t mean &#8220;symphony&#8221; as in music &#8211; no! Scrap that &#8220;ph&#8221;. It&#8217;s &#8220;symfony&#8221;, one of the greatest web frameworks that has been developed in PHP5 so far. (If you ever <a href="http://devzone.zend.com/article/4383-What-is-Dependency-Injection" title="How can they write &quot;symphony&quot;? Poor kittens." target="_blank" class="liexternal">dare to write symfony with &#8220;ph&#8221;</a>, tiny kittens will suffer!)</p>
<p>Symfony is by a large part a product of <a href="http://fabien.potencier.org/" title="Fabien Potencier's blog" target="_blank" class="liexternal">Fabien Potencier&#8217;s</a> ingenuity and dedication. I want to deeply express my respect for his work at this point. The framework is a very well-thought piece of work and can immensely boost your productivity.</p>
<p>The amount of features and the complexity come with a drawback though: It takes a lot of time to learn how to develop efficiently with symfony. Many PHP developers are overwhelmed by the object-oriented concepts applied in the framework. Many <a href="http://groups.google.com/group/symfony-users/browse_thread/thread/1b9a1871f3619bbc" title="Could Symfony be easier to use?, Google Groups Discussion" target="_blank" class="liexternal">call for a simplified version</a> and I must agree that symfony suffers some usability problems lately. But why is that and how can we improve the current situation?<span id="more-33"></span></p>
<h3>The Average Developer</h3>
<p>Let&#8217;s face it. The average PHP developer knows nothing about &#8220;Design Patterns&#8221;, &#8220;Unit Tests&#8221; or &#8220;Refactoring&#8221;. In the course of my job I had to interview a lot of potential employees. Not only once I faced total ignorance when I talked about these or similar topics. Even basic understanding of PHP could not be taken for granted! What struck me most was that many of these people programmed PHP applications for a living, some of them for more than a decade.</p>
<p>What happens when you confront these developers with symfony? It&#8217;s like when my grandma got a computer. It took so much time to teach her using the mouse that telling her about how to write a letter would just have made no sense.</p>
<p>In my opinion, every PHP developer who is familiar enough with the language itself should be able to learn symfony.  If we want to raise the general quality and standards of PHP applications, we must reach these developers. Lowering the burdens for them to learn the framework is crucial for its future community.</p>
<h3>Back To Basics</h3>
<p>The excellent documentation of symfony obviously is a great help. I remember when I read the symfony documentation for the first time. Its great writing, the presented simplicity of powerful features really struck me. Every couple of pages I was astonished  by the fact that programming in PHP could be so easy! I was torn apart, because I <em>had to read on</em> while I just felt the urgent desire to start programming. <em>Anything.</em></p>
<p>Unfortunately, this feeling of simplicity quickly fades away when you get started. Questions over questions arise. Where do I put that code? What method again should I use? Is it better to write it this or that way?</p>
<p>Now this is the case for every major programming library. You can&#8217;t expect to read a little of the documentation and be an expert (in this case it probably wouldn&#8217;t even be worth to use the library). What you <em>can</em> do is look at the code of others, extract the common ideas and find out for yourself how to best organize your code.</p>
<p>What you are searching for is generally referred to as &#8220;Best Practices&#8221;. The <a href="http://www.symfony-project.org/jobeet/1_2/" title="The symfony advent calendar tutorial Jobeet" target="_blank" class="liexternal">Jobeet tutorial</a> did a great job at presenting such best practices. But further than just being documented, the described concepts must be <em>simple enough</em> for you to remember them next time you need them. And this, partly, is symfony&#8217;s weak point.</p>
<h3>Forms By Example</h3>
<p>To demonstrate my argument, let&#8217;s look at how to create a basic profile form in symfony. This form should allow to edit a user&#8217;s name, email address and password. The name should only be editable by administrators, while the password should be entered twice to make sure it was entered correctly. The maximum length of the name is 15 characters and the password should not be the same as the name.</p>
<p>Let&#8217;s start with the constructor. We need to alter the form depending on the authentication of the current user session, thus we pass the user object to the form.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// lib/form/doctrine/ProfileForm.class.php</span>
<span style="color: #000000; font-weight: bold;">class</span> ProfileForm <span style="color: #000000; font-weight: bold;">extends</span> sfFormDoctrine
<span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000088;">$user</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span>sfUser <span style="color: #000088;">$user</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user <span style="color: #339933;">=</span> <span style="color: #000088;">$user</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>So far so good. Now let&#8217;s configure the form&#8217;s appearance and validation logic.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> configure<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidgets<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInputPassword<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>widgetSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setLabel<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Password (again)'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidators<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #0000ff;">'email'</span>          <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorEmail<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter your email address'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password'</span>       <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'required'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'Please enter a password'</span><span style="color: #339933;">,</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #0000ff;">'password_again'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorPass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// implement custom validation logic</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>validatorSchema<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setPostValidator<span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> sfValidatorAnd<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorSchemaCompare<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password_again'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'=='</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'invalid'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The passwords must be equal'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
      <span style="color: #000000; font-weight: bold;">new</span> sfValidatorCallback<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'callback'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'comparePasswordAndName'</span><span style="color: #009900;">&#41;</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
    <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// administrators may enter the user name</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>user<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>hasCredential<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'admin'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setWidget<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfWidgetFormInput<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>setValidator<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorString<span style="color: #009900;">&#40;</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #cc66cc;">15</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'max_length'</span> <span style="color: #339933;">=&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #0000ff;">'The name must be 15 characters or longer'</span>
      <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span></pre></div></div>

<p>Phew, there&#8217;s already a lot going on. We need to know about the widget schema and the validator schema. These are tricky, because for example <code>setWidgets()</code> is called on the form directly, while <code>setLabel()</code> is called on the widget schema. Don&#8217;t get that wrong.</p>
<p>Then you need to pass the error messages that are displayed when the fields are not filled out, because the default &#8220;Required.&#8221; is not really usable for a customer.</p>
<p>The post validator is especially tricky. Once you understood the concept, you need to remember to set it on the validator schema, use <code>sfValidatorAnd</code> with a couple of braces thrown in and mix it with <code>sfValidatorSchemaCompare</code> and <code>sfValidatorCallback</code>. Not easy.</p>
<p>The last thing is to add the &#8220;name&#8221; field and validator only when the user is administrator. This especially causes complications, because then the field &#8220;name&#8221; is not always present in the form values, which requires extra checks and template customizations from you. We need to configure the &#8220;max_length&#8221; constraint twice, once on the input field and once on the validator.  Again we override the error message, because the default is not usable.</p>
<p>What is missing now is the method that checks that the password and name differ:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> comparePasswordAndName<span style="color: #009900;">&#40;</span>sfValidator <span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span>
  <span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// if the field &quot;name&quot; is not editable, it does not exist in $values</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'name'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>amp<span style="color: #339933;">;&amp;</span>amp<span style="color: #339933;">;</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'name'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'password'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$error</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorError<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span>
          <span style="color: #0000ff;">'The password must not be the same as the name'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
      <span style="color: #666666; font-style: italic;">// throw an error schema so the error appears at the field &quot;password&quot;</span>
      <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> sfValidatorErrorSchema<span style="color: #009900;">&#40;</span><span style="color: #000088;">$validator</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'password'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$error</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>If you want to set an error for the form, you basically need to throw an <code>sfValidatorError</code>, which behaves like an exception. Because the error should be displayed at the password field, we need to wrap it with an <code>sfValidatorErrorSchema</code> instance and associate it with the fieldname &#8220;password&#8221;.</p>
<p class="note">
This form is not yet complete. The logic to save the profile is still missing, but the above implementation pretty well demonstrates what I want to show.
</p>
<h3>Tying It All Together</h3>
<p>If you go back and re-read the form requirements, you will see that these requirements are not uncommon even for very basic websites. Still the implementation requires you to know many different concepts. Altering the form based on the authentication status, modifying field labels, limiting field lengths, implementing custom validation logic, all of this is so common that it should be far easier. The default error messages should only need to be overridden in edge cases. Don&#8217;t expect that the average developers that I spoke about will get that right.</p>
<p>In my opinion, <em>symfony must strive for absolute simplicity</em>. The easier it is to explain its use, the quicker new developers will grasp the real power that lies under the hood of this framework. Together with a well-defined set of recommendations and best practices we will be able to teach new developers and expand the community. And we will be able to help those &#8220;average PHP developers&#8221; to step into the world of powerful object-oriented concepts.</p>
<p>This is the goal of this blog. We want to analyze our work and present best practices to improve your development. We want to speak about symfony&#8217;s strengths and learn about symfony&#8217;s flaws to point out possible solutions. We want to teach object oriented concepts in PHP5. We want to investigate what the community needs and try to find answers. Of course, we also want to present our own work. And last but not least, we do want to hear your feedback.</p>
<p>In the coming weeks I will think about possible solutions to the above problems with the Forms framework and post them on this blog. I would also appreciate to hear your ideas.</p>
<p>What is your experience with this new component? Is symfony simple enough for you?</p>
<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/04/07/no-piece-of-cake/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>

