<?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</title>
	<atom:link href="http://webmozarts.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://webmozarts.com</link>
	<description>On The Art Of Web Development</description>
	<lastBuildDate>Sun, 06 Sep 2009 07:43:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<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 and [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol>]]></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>Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol></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 [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/09/06/thank-you/' rel='bookmark' title='Permanent Link: Thank You'>Thank You</a> <small>Yesterday I returned back to Vienna from Symfony Day Cologne...</small></li><li><a href='http://webmozarts.com/2009/05/01/speedup-performance-profiling-for-your-symfony-app/' rel='bookmark' title='Permanent Link: Speedup: Profile your symfony app using Xdebug'>Speedup: Profile your symfony app using Xdebug</a> <small>Hi! A warm welcome to Web Mozarts also from my...</small></li><li><a href='http://webmozarts.com/2009/06/30/easy-unit-testing/' rel='bookmark' title='Permanent Link: Easy Unit Testing'>Easy Unit Testing</a> <small>Unit testing is a very important task of professional, scalable...</small></li></ol>]]></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>Related posts:<ol><li><a href='http://webmozarts.com/2009/09/06/thank-you/' rel='bookmark' title='Permanent Link: Thank You'>Thank You</a> <small>Yesterday I returned back to Vienna from Symfony Day Cologne...</small></li><li><a href='http://webmozarts.com/2009/05/01/speedup-performance-profiling-for-your-symfony-app/' rel='bookmark' title='Permanent Link: Speedup: Profile your symfony app using Xdebug'>Speedup: Profile your symfony app using Xdebug</a> <small>Hi! A warm welcome to Web Mozarts also from my...</small></li><li><a href='http://webmozarts.com/2009/06/30/easy-unit-testing/' rel='bookmark' title='Permanent Link: Easy Unit Testing'>Easy Unit Testing</a> <small>Unit testing is a very important task of professional, scalable...</small></li></ol></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!
The reason [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol>]]></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>
<pre lang="php">class Product
{
  public function save()
  {
    if (sfContext::getInstance()-&gt;getUser()-&gt;hasAttribute('foobar'))
    {
      // do something
    }
  }
}</pre>
<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>
<pre lang="php">class Product
{
  protected $user = null;

  protected function setUser(sfUser $user)
  {
    $this-&gt;user = $user;
  }

  public function save()
  {
    if ($this-&gt;user instanceof sfUser &amp;&amp; $this-&gt;user-&gt;hasAttribute('foobar'))
    {
      // do something
    }
  }
}</pre>
<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>
<pre lang="php">class Product
{
  protected $user = null;

  protected function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }
}</pre>
<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>
<pre lang="php">class Product
{
  public function save()
  {
    if (!$this-&gt;user instanceof sfUser)
    {
      throw new LogicException('The user must be set before saving');
    }
  }
}</pre>
<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>
<pre lang="php">class StubUser extends sfUser
{
  public function hasAttribute($name)
  {
    return $name == 'foobar';
  }
}

$t-&gt;comment('Products with the attribute "foobar" do something special upon saving');

  $p = new Product();
  $p-&gt;setUser(new StubUser());
  $p-&gt;save();
  $t-&gt;is(...);</pre>
<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>Related posts:<ol><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/07/01/why-sfcontextgetinstance-is-bad/feed/</wfw:commentRss>
		<slash:comments>17</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, 


Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol>]]></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>
<pre lang="php">class User
{
  protected $storage;

  public function User(SessionStorageInterface $storage)
  {
    $this-&gt;storage = $storage;
  }

  public function setAttribute($name, $value)
  {
    $this-&gt;storage-&gt;write($name, $value);
  }

  public function getAttribute($name)
  {
    return $this-&gt;storage-&gt;read($name);
  }
}</pre>
<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>
<pre lang="php">interface SessionStorageInterface
{
  public function write($key, $value);
  public function read($key);
}</pre>
<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>
<pre lang="php">class StubSessionStorage implements SessionStorageInterface
{
  private $name;
  private $value;

  public function write($name, $value)
  {
    $this-&gt;name = $name;
    $this-&gt;value = $value;
  }

  public function read($name)
  {
    return $name == $this-&gt;name ? $this-&gt;value : null;
  }
}</pre>
<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>
<pre lang="php">class UserTest extends PHPUnit_Framework_TestCase
{
  private $sessionStorage;
  private $user;

  public function setUp()
  {
    $this-&gt;sessionStorage = new StubSessionStorage();
    $this-&gt;user = new User($this-&gt;sessionStorage);
  }

  public function testAttributesAreReadFromTheSession()
  {
    // fixture setup
    $this-&gt;sessionStorage-&gt;write('Foo', 'Bar');
    // execute test
    $value = $this-&gt;user-&gt;getAttribute('Foo');
    // verify results
    $this-&gt;assertEquals($value, 'Bar', 'The value was read from the session');
  }

  public function testAttributesAreWrittenToTheSession()
  {
  // ...
  }
}</pre>
<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>
<pre lang="php">$t = new lime_test(1);

$t-&gt;comment('Attributes are read from the session');

  // fixture
  $s = new StubSessionStorage();
  $u = new User($s);
  $s-&gt;write('Foo', 'Bar');
  // test
  $value = $u-&gt;getAttribute('Foo');
  // assertions
  $t-&gt;is($value, 'Bar', 'The value was read from the session');

$t-&gt;comment('Attributes are written to the session');

  // ...</pre>
<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>
<pre lang="php">$t = new lime_test_simple(1);

// @Before
$s = new StubSessionStorage();
$u = new User($s);

// @Test: Attributes are read from the session
// fixture
$s-&gt;write('Foo', 'Bar');
// test
$value = $u-&gt;getAttribute('Foo');
// assertions
$t-&gt;is($value, 'Bar', 'The value was read from the session');

// @Test: Attributes are written to the session
// ...</pre>
<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>
<pre lang="php">$t-&gt;comment('setAttribute() throws an exception if the data contains &lt;script&gt; tags');

  // fixture
  $u = new User(new StubSessionStorage());
  // test
  try
  {
    $u-&gt;setAttribute('&lt;script&gt;alert("Evil!")&lt;/script&gt;');
    $t-&gt;fail('setAttribute() throws an "InvalidArgumentException"');
  }
  catch (InvalidArgumentException $e)
  {
    $t-&gt;pass('setAttribute() throws an "InvalidArgumentException"');
  }</pre>
<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>
<pre lang="php">// @Before
$u = new User(new StubSessionStorage());

// @Test: setAttribute() throws an exception if the data contains &lt;script&gt; tags
// fixture
$t-&gt;expect('InvalidArgumentException');
// test
$u-&gt;setAttribute('&lt;script&gt;alert("Evil!")&lt;/script&gt;');</pre>
<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>
<pre lang="php">// @Before
$s = lime_mock::create('SessionStorageInterface');
$u = new User($s);

// @Test: Attributes are read from the session
// fixture
$s-&gt;read('Foo')-&gt;returns('Bar');
$s-&gt;replay();
// test
$value = $u-&gt;getAttribute('Foo');
// assertions
$t-&gt;is($value, 'Bar', 'The value was read from the session');</pre>
<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>Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol></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>Speedup: Profile your symfony app using Xdebug</title>
		<link>http://webmozarts.com/2009/05/01/speedup-performance-profiling-for-your-symfony-app/</link>
		<comments>http://webmozarts.com/2009/05/01/speedup-performance-profiling-for-your-symfony-app/#comments</comments>
		<pubDate>Fri, 01 May 2009 10:17:09 +0000</pubDate>
		<dc:creator>Klemens</dc:creator>
				<category><![CDATA[Tips & Tricks]]></category>

		<guid isPermaLink="false">http://webmozarts.com/?p=276</guid>
		<description><![CDATA[Hi! A warm welcome to Web Mozarts also from my side. It took some time to write my first post, but here it is!
Your app is slow? If the symfony web debug toolbar doesn&#8217;t give you the details you want, you can take a real deep look into your application using the profiling options of [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol>]]></description>
			<content:encoded><![CDATA[<p>Hi! A warm welcome to Web Mozarts also from my side. It took some time to write my first post, but here it is!</p>
<p>Your app is slow? If the symfony <a href="http://www.symfony-project.org/book/1_2/16-Application-Management-Tools#chapter_16_sub_web_debug_toolbar" title="symfony web debug toolbar" target="_blank" class="liexternal">web debug</a> toolbar doesn&#8217;t give you the details you want, you can take a real deep look into your application using the profiling options of <a href="http://www.xdebug.org/" title="Xdebug homepage" target="_blank" class="liexternal">Xdebug</a>.</p>
<p>In this tutorial we will set up Xdebug to profile your application and then we&#8217;ll analyse the output with <a href="http://kcachegrind.sourceforge.net/html/Home.html" target="_blank" class="liexternal">KCachegrind</a>.</p>
<p class="note">By the way: Xdebug has a lot of other useful features. One that comes automatically is the nicely formated php debugging output in case of errors including the full call stack. KCachegrind on the other hand has very interesting graphical output features like the call graph. In the case of symfony the call graph can be like an interesting expedition into the functionality of the framework.</p>
<p><span id="more-276"></span></p>
<h3>Installation</h3>
<p>We&#8217;ll do the installation using Ubuntu Linux, but it works similar for other unixes or even Windows with a WAMP stack. Ah yes &#8211; we assume you have the correct environment for symfony installed (Apache, PHP5, &#8230;).</p>
<p class="note">KCachegrind is not available for Windows. You can use <a href="http://sourceforge.net/projects/wincachegrind/" target="_blank" class="liexternal">WinCacheGrind</a> instead although it doesn&#8217;t provide the graphical goodies.</p>
<p>Download and install:</p>
<pre lang="php">sudo aptitude install php5-xdebug kcachegrind</pre>
<p>Ubuntu automatically inserts the Xdebug module in the php ini files:</p>
<pre lang="php"># /etc/php5/conf.d/xdebug.ini
zend_extension=/usr/lib/php5/20060613+lfs/xdebug.so</pre>
<p>Now let&#8217;s restart apache to load the new configuration:</p>
<pre lang="php">sudo apache2ctl restart</pre>
<p>Let&#8217;s provoke an error and let us see if Xdebug works. I put an invalid function call into a php script:</p>
<pre lang="php">// apps/frontend/modules/myModule/actions.class.php
class myModuleActions extends sfActions
{
  public function executeIndex()
  {
    invalid_function();
  }
}</pre>
<p>Now we get the typical Xdebug output including the call stack in the browser, so we know it works:<br />
<a href="http://webmozarts.com/wp-content/uploads/2009/04/xdebug_trace.png" ><img class="alignnone size-medium wp-image-296" src="http://webmozarts.com/wp-content/uploads/2009/04/xdebug_trace-300x215.png" alt="xdebug_trace" width="300" height="215" /></a></p>
<h3>Enable profiling</h3>
<p>The profiling capability of Xdebug has to be explictly enabled because it produces A LOT of output and slows down the application serverely.</p>
<p>If you use .htaccess for your symfony project this is the easiest way to enable the profiling:</p>
<pre lang="php"># web/.htaccess

# append at the end of the file:
php_value xdebug.profiler_enable 1
php_value xdebug.profiler_output_dir /tmp</pre>
<p>If you don&#8217;t use .htaccess, or if you want to profile a cli php script, you have to enable the profiling in your php.ini (cli stands for command line interface). Example for the cli:</p>
<pre lang="php"># /etc/php5/cli/conf.d/xdebug.ini

# append at the end of the file:
xdebug.profiler_output_dir = "/tmp"
xdebug.profiler_enable = 1</pre>
<p>Don&#8217;t forget to restart apache if you changed the php.ini config!</p>
<h3>Data galore&#8230;</h3>
<p>Ok, let&#8217;s profile something! Just fire up your webbrowser and load any page of your local symfony project.<br />
Xdebug now creates a &#8220;cachegrind&#8221; file like &#8220;cachegrind.out.22076 in your /tmp/ directory.</p>
<p>Here&#8217;s how a cachgrind file looks like:</p>
<pre lang="php">version: 0.9.6
cmd: /var/www/ullright/web/index.php
part: 1

events: Time

fl=php:internal
fn=php::realpath
38 98

fl=/var/www/ullright/plugins/ullCorePlugin/lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php
fn=sfCoreAutoload-&gt;__construct
50 93
cfn=php::dirname
calls=1 0 0
38 2
cfn=php::realpath
calls=1 0 0
38 98</pre>
<p>It basically records which function was called from which script file, how many times it was called and how long the execution took.</p>
<p>Now that isn&#8217;t really human readable, is it?</p>
<p>So let&#8217;s open the cachegrind file with KCachegrind. It looks something like this:</p>
<p><a href="http://webmozarts.com/wp-content/uploads/2009/05/kcachegrind-overview.png" ><img class="alignnone size-medium wp-image-309" src="http://webmozarts.com/wp-content/uploads/2009/05/kcachegrind-overview-300x187.png" alt="kcachegrind-overview" width="300" height="187" /></a></p>
<p>So what have we got here? On the left side you see the &#8220;Flat Profile&#8221;. A list of all function and method calls. From left to right:</p>
<ul>
<li>Incl. &#8211; The cost of the function including all child functions</li>
<li>Self &#8211; The cost of the function itself</li>
<li>Called &#8211; How many times a function was called</li>
<li>Function &#8211; Which function</li>
<li>Location &#8211; Script file</li>
</ul>
<p>A good starting point is to click on &#8220;Called&#8221; to see which functions are called the most often. It&#8217;s also interesting to order by &#8220;Self&#8221; to see which method itself took the most time.</p>
<p>On the right side I selected the tab &#8220;Call Graph&#8221; which shows the sequence of the function calls starting with &#8220;{main}&#8221;. For symfony it&#8217;s usually &#8220;web/index.php&#8221;.</p>
<p>The number of nodes in the call graph is limited by the relative percentage of the execution time. Per default only functions that take more than 5% of the execution time are displayed. Get a more detailed graph by right clicking into the call graph and selecting &#8220;Graph -&gt; Min. node cost -&gt; 1%&#8221;. You can also doube click on any node to see a more detailed child-graph.</p>
<p><a href="http://webmozarts.com/wp-content/uploads/2009/05/kcachegrind-doctrine.png" ><img class="alignnone size-medium wp-image-314" src="http://webmozarts.com/wp-content/uploads/2009/05/kcachegrind-doctrine-300x187.png" alt="kcachegrind-doctrine" width="300" height="187" /></a></p>
<p>Here is a nice detailed graph showing the internals of a doctrine query.  I&#8217;d like to invite you to explore your symfony app using the call graph &#8211; it surely is an interesting journey and you can learn a lot about the architecture of symfony.</p>
<p>Coming to an end I&#8217;d like to hear about your experiences and findings about performance profiling:</p>
<ul>
<li>What tools do you use?</li>
<li>What are your best practices?</li>
</ul>
<p>Looking forward to interesting discussions &#8211; have a nice day!</p>


<p>Related posts:<ol><li><a href='http://webmozarts.com/2009/09/03/symfony-day-cologne-2009/' rel='bookmark' title='Permanent Link: Symfony Day Cologne 2009'>Symfony Day Cologne 2009</a> <small>Today, I will take the plane to Cologne to attend...</small></li></ol></p>]]></content:encoded>
			<wfw:commentRss>http://webmozarts.com/2009/05/01/speedup-performance-profiling-for-your-symfony-app/feed/</wfw:commentRss>
		<slash:comments>5</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 keeping [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol>]]></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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm extends sfFormDoctrine
{
  protected $user = null;

  public function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }

  public function configure()
  {
    $this-&gt;addField('name', new sfTextField(15))
         -&gt;setHelp('Your full name, f.i. "John Travolta"');
    $this-&gt;addField('email', new sfEmailField())
         -&gt;setHelp('A valid email address, f.i. "john.travolta@gmail.com"');
    $this-&gt;addField('password', new VerifiedPasswordField())
         -&gt;setHelp('Must not be "pulpfiction"');

    $this-&gt;setFinalValidator(
      new sfValidatorCallback($this, 'comparePasswordAndName')
    );

    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      $this-&gt;getField('name')-&gt;setEditable(false);
    }
  }

  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    if ($values['name'] == $values['password'])
    {
      throw new sfValidatorError('The password must not be the same as the name',
          'password');
    }
  }
}</pre>
<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 (&#8221;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>
<pre lang="php">  public function configure()
  {
    $this-&gt;setLayout(new sfListLayout());
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;setLayout(new sfListLayout(array(
      'columns' =&gt; 3,
      'order'   =&gt; sfLayout::VERTICAL,
    )));
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;addField('password', new VerifiedPasswordField())
         -&gt;setFormat('fieldset');
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;setLayout(new sfListLayout());</pre>
<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>
<pre lang="php">    $this-&gt;addField('name', new sfTextField(15))
         -&gt;setHelp('Your full name, f.i. "John Travolta"');
    $this-&gt;addField('email', new sfEmailField())
         -&gt;setHelp('A valid email address, f.i. "john.travolta@gmail.com"');
    $this-&gt;addField('password', new VerifiedPasswordField())
         -&gt;setHelp('Must not be "pulpfiction"')
         -&gt;setFormat('fieldset');</pre>
<p>Just for fun, we&#8217;ll add a few checkboxes to our form to demonstrate how a multigrid layout is integrated.</p>
<pre lang="php">    $permissions = array(
      'admin', 'blog-editor', 'content-editor',
      'publisher', 'file-editor', 'comment-editor',
    );
    $this-&gt;addField('permissions', new sfCheckboxList($permissions))
         -&gt;setHelp('Choose one or more permissions for this user')
         -&gt;setFormat('fieldset')
         -&gt;setLayout(new sfListLayout(array('columns' =&gt; 3));</pre>
<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>&#8217;s array access syntax. Together with a set of easy convenience methods, even web designers could configure the form&#8217;s format.</p>
<pre lang="php">&lt;?php $form-&gt;setLayout('list') ?&gt;
&lt;?php $form['password']-&gt;setFormat('fieldset') ?&gt;
&lt;?php $form['permissions']-&gt;setFormat('fieldset') ?&gt;
&lt;?php $form['permissions']-&gt;setLayout('list', array('columns' =&gt; 2)) ?&gt;

&lt;?php echo $form ?&gt;</pre>
<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>
<pre lang="php">interface sfLayoutInterface
{
  public function createFieldFormatter($format = null);
  public function createFieldGroupFormatter();
}</pre>
<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>
<pre lang="php">$layout = new sfListLayout();
$formatter = $layout-&gt;createFieldFormatter('rightlabel');
echo get_class($formatter);

// returns "sfRightLabelListFieldFormatter"</pre>
<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>
<pre lang="php">interface sfFieldFormatterInterface
{
  public function render($id, $label, $value, $help, array $attributes = array());
}</pre>
<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>Related posts:<ol><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol></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 


Related posts:<ol><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol>]]></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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm extends sfFormDoctrine
{
  protected $user = null;

  public function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }

  public function configure()
  {
    $this-&gt;addField('name')
         -&gt;setWidgetAttributes(array('max_length' =&gt; 15))
         -&gt;setValidatorOptions(array('max_length' =&gt; 15))
         -&gt;setHelp('Your full name, f.i. "John Travolta"');

    $this-&gt;addField('email')
         -&gt;setValidator(new sfValidatorEmail())
         -&gt;setHelp('A valid email address, f.i. "john.travolta@gmail.com"');

    $this-&gt;addField('password', new PasswordField())
         -&gt;setHelp('Must not be "pulpfiction"');

    $this-&gt;addField('password_again')
         -&gt;setWidget(new sfWidgetPassword())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');

    $this-&gt;setFinalValidator(new sfValidatorAnd(
      new sfValidatorCompare('password_again', '==', 'password',
          'The passwords must be equal'),
      new sfValidatorCallback($this, 'comparePasswordAndName')
    ));

    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      $this-&gt;getField('name')-&gt;setEditable(false);
    }
  }

  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    if ($values['name'] == $values['password'])
    {
      throw new sfValidatorError('The password must not be the same as the name',
          'password');
    }
  }
}</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;addField('name', new sfTextField(15))
         -&gt;setHelp('Your full name, f.i. "John Travolta"');
    $this-&gt;addField('email', new sfEmailField())
         -&gt;setHelp('A valid email address, f.i. "john.travolta@gmail.com"');
    $this-&gt;addField('password', new sfPasswordField())
         -&gt;setHelp('Must not be "pulpfiction"');
    $this-&gt;addField('password_again', new sfPasswordField())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');

    $this-&gt;setFinalValidator(new sfValidatorAnd(
      new sfValidatorCompare('password_again', '==', 'password',
          'The passwords must be equal'),
      new sfValidatorCallback($this, 'comparePasswordAndName')
    ));</pre>
<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>
<pre lang="php">interface sfFormFieldInterface
{
  public function bind($taintedValue, $taintedFile);
  public function getData();
  public function getId();
  public function getLabel();
  public function getHelp();
  public function render();
  ...
}</pre>
<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>
<pre lang="php">class VerifiedPasswordField extends sfFormFieldGroup
{
  public function configure()
  {
    $this-&gt;addField('first', new sfPasswordField());
    $this-&gt;addField('second', new sfPasswordField())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');

    $this-&gt;setFinalValidator(
      new sfValidatorCompare('second', '==', 'first',
          'The passwords must be equal')
    );
  }
}</pre>
<p>Now we can simply drop our password field into the form:</p>
<pre lang="php">  public function configure()
  {
    $this-&gt;addField('password', new VerifiedPasswordField())
         -&gt;setHelp('Must not be "pulpfiction"');
  }</pre>
<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>
<pre lang="php">// VerifiedPasswordField::getData()
array(
  'first' =&gt; 'The password',
  'second' =&gt; 'The password',
)</pre>
<p>Hm, any idea? Let&#8217;s also look at the output of <code>ProfileForm::getData()</code>.</p>
<pre lang="php">// ProfileForm::getData()
array(
  'name' =&gt; 'The name',
  'email' =&gt; 'thename@gmail.com',
  'password' =&gt; array(
    'first' =&gt; 'The password',
    'second' =&gt; 'The password',
  ),
)</pre>
<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>
<pre lang="php">  public function getData()
  {
    $data = parent::getData();

    return $data['first'];
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    $group = $this-&gt;addGroup('personal')
          -&gt;setLabel('Personal Information')
          -&gt;setHelp('Please enter your personal information here so we can sell it');
    $group-&gt;addField('first_name')
          -&gt;setLabel('First name');
    $group-&gt;addField('surname');
  }</pre>
<div class="info">Calling</p>
<pre lang="php">$form-&gt;addGroup('groupname')</pre>
<p>without explicitly passing an <code>sfFormFieldGroup</code> instance has the same effect as calling</p>
<pre lang="php">$form-&gt;addGroup('groupname', new sfFormFieldGroup())</pre>
<p>or</p>
<pre lang="php">$form-&gt;addField('groupname', new sfFormFieldGroup())</pre>
</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>Related posts:<ol><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol></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 [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol>]]></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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm extends sfFormDoctrine
{
  protected $user = null;

  public function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }

  public function configure()
  {
    $this-&gt;setWidgets(array(
      'name'           =&gt; new sfWidgetFormInput(array(), array(
        'max_length' =&gt; 15
      ),
      'email'          =&gt; new sfWidgetFormInput(),
      'password'       =&gt; new sfWidgetFormInputPassword(),
      'password_again' =&gt; new sfWidgetFormInputPassword(),
    ));
    $this-&gt;widgetSchema-&gt;setLabel('password_again', 'Password (again)');

    $this-&gt;setValidators(array(
      'name'           =&gt; new sfValidatorString(array(
        'max_length' =&gt; 15
      ), array(
        'max_length' =&gt; 'The name must be 15 characters or longer'
      ),
      'email'          =&gt; new sfValidatorEmail(array(), array(
        'required' =&gt; 'Please enter your email address',
      )),
      'password'       =&gt; new sfValidatorString(array(), array(
        'required' =&gt; 'Please enter a password',
      )),
      'password_again' =&gt; new sfValidatorPass(),
    ));

    // implement custom validation logic
    $this-&gt;validatorSchema-&gt;setPostValidator(new sfValidatorAnd(array(
      new sfValidatorSchemaCompare('password_again', '==', 'password', array(
        'invalid' =&gt; 'The passwords must be equal'
      )),
      new sfValidatorCallback(array(
        'callback' =&gt; array($this, 'comparePasswordAndName')
      )),
    )));

    // only administrators may enter the user name
    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      unset($this['name']);
    }
  }

  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    // if the field "name" is not editable, it does not exist in $values
    if (array_key_exists('name', $values) &amp;&amp; $values['name'] == $values['password'])
    {
      $error = new sfValidatorError($validator,
          'The password must not be the same as the name');

      // throw an error schema so the error appears at the field "password"
      throw new sfValidatorErrorSchema($validator, array('password', $error));
    }
  }
}</pre>
<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>
<pre lang="php">// lib/form/fields/PasswordField.class.php
class PasswordField extends sfField
{
  public function configure()
  {
    $this-&gt;setWidget(new sfWidgetInputPassword());
    $this-&gt;setValidator(new sfValidatorString(array(), array(
      'required' =&gt; 'Please enter a password',
    ));
  }
}</pre>
<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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm
{
  public function configure()
  {
    $this-&gt;addField('password', new PasswordField());
    ...
  }
}</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;addField('name', new sfField())
         -&gt;setWidget(new sfWidgetInput(array(), array('max_length' =&gt; 15)))
         -&gt;setValidator(new sfValidatorString(array('max_length' =&gt; 15)));

    $this-&gt;addField('email', new sfField())
         -&gt;setWidget(new sfWidgetInput())
         -&gt;setValidator(new sfValidatorEmail());

    $this-&gt;addField('password', new PasswordField());

    $this-&gt;addField('password_again', new sfField())
         -&gt;setWidget(new sfWidgetInputPassword())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');
    ...
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    $this-&gt;addField('name') // implicitly sfWidgetInput and sfValidatorString
         -&gt;setWidgetAttributes(array('max_length' =&gt; 15))
         -&gt;setValidatorOptions(array('max_length' =&gt; 15));

    $this-&gt;addField('email') // implicitly sfWidgetInput
         -&gt;setValidator(new sfValidatorEmail(array(), array(
           'required' =&gt; 'Please enter your email address',
         )));

    $this-&gt;addField('password', new PasswordField());

    $this-&gt;addField('password_again')
         -&gt;setWidget(new sfWidgetInputPassword())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');
    ...
  }</pre>
<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>
<pre lang="php">  // before
  public function configure()
  {
    $this-&gt;setWidgets(array(
      'name'           =&gt; new sfWidgetFormInput(array(), array(
        'max_length' =&gt; 15
      ),
      'email'          =&gt; new sfWidgetFormInput(),
      'password'       =&gt; new sfWidgetFormInputPassword(),
      'password_again' =&gt; new sfWidgetFormInputPassword(),
    ));
    $this-&gt;widgetSchema-&gt;setLabel('password_again', 'Password (again)');

    $this-&gt;setValidators(array(
      'name'           =&gt; new sfValidatorString(array(
        'max_length' =&gt; 15
      ), array(
        'max_length' =&gt; 'The name must be 15 characters or longer'
      ),
      'email'          =&gt; new sfValidatorEmail(array(), array(
        'required' =&gt; 'Please enter your email address',
      )),
      'password'       =&gt; new sfValidatorString(array(), array(
        'required' =&gt; 'Please enter a password',
      )),
      'password_again' =&gt; new sfValidatorPass(),
    ));
    ...
  }</pre>
<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>
<pre lang="php">  public function configure()
  {
    ...
    $this-&gt;addField('email')
         -&gt;setValidator(new sfValidatorEmail());
    ...
  }</pre>
<p>Compared to before:</p>
<pre lang="php">  // before
  public function configure()
  {
    ...
    $this-&gt;addField('email')
         -&gt;setValidator(new sfValidatorEmail(array(), array(
           'required' =&gt; 'Please enter your email address',
         )));
    ...
  }</pre>
<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>
<pre lang="php">$this-&gt;setFinalValidator(...);</pre>
<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>
<pre lang="php">new sfValidatorCallback(array('callback' =&gt; array($this, 'comparePasswordAndName')));</pre>
<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>
<pre lang="php">new sfValidatorCallback($this, 'comparePasswordAndName');</pre>
<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>
<pre lang="php">new sfValidatorCompare('password_repeat', '==', 'password',
    'The passwords must match');</pre>
<p>Now we can draw the whole picture of our final validator:</p>
<pre lang="php">    $this-&gt;setFinalValidator(new sfValidatorAnd(
      new sfValidatorCompare('password_repeat', '==', 'password',
          'The passwords must match'),
      new sfValidatorCallback($this, 'comparePasswordAndName')
    ));</pre>
<p>Isn&#8217;t this much nicer to read? Here&#8217;s the old definition again:</p>
<pre lang="php">    // before
    $this-&gt;validatorSchema-&gt;setPostValidator(new sfValidatorAnd(array(
      new sfValidatorSchemaCompare('password_again', '==', 'password', array(
        'invalid' =&gt; 'The passwords must be equal'
      )),
      new sfValidatorCallback(array(
        'callback' =&gt; array($this, 'comparePasswordAndName')
      )),
    )));</pre>
<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>
<pre lang="php">    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      $this-&gt;getField('name')-&gt;setEditable(false);
    }</pre>
<p>That&#8217;s all! Compared to before:</p>
<pre lang="php">    // before
    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      unset($this['name']);
    }</pre>
<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>&#8217;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>
<pre lang="php">  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    if ($values['name'] == $values['password'])
    {
      throw new sfValidatorError('The password must not be the same as the name',
          'password');
    }
  }</pre>
<p>Now that was easy! Here&#8217;s the old definition:</p>
<pre lang="php">  // before
  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    // if the field "name" is not editable, it does not exist in $values
    if (array_key_exists('name', $values) &amp;&amp; $values['name'] == $values['password'])
    {
      $error = new sfValidatorError($validator,
          'The password must not be the same as the name');

      // throw an error schema so the error appears at the field "password"
      throw new sfValidatorErrorSchema($validator, array('password', $error));
    }
  }</pre>
<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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm extends sfFormDoctrine
{
  protected $user = null;

  public function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }

  public function configure()
  {
    $this-&gt;addField('name')
         -&gt;setWidgetAttributes(array('max_length' =&gt; 15))
         -&gt;setValidatorOptions(array('max_length' =&gt; 15));

    $this-&gt;addField('email')
         -&gt;setValidator(new sfValidatorEmail());

    $this-&gt;addField('password', new PasswordField());

    $this-&gt;addField('password_again')
         -&gt;setWidget(new sfWidgetPassword())
         -&gt;setValidator(new sfValidatorPass())
         -&gt;setLabel('Password (again)');

    $this-&gt;setFinalValidator(new sfValidatorAnd(
      new sfValidatorCompare('password_again', '==', 'password',
          'The passwords must be equal'),
      new sfValidatorCallback($this, 'comparePasswordAndName')
    ));

    if (!$this-&gt;user-&gt;hasCredential('admin'))
    {
      $this-&gt;getField('name')-&gt;setEditable(false);
    }
  }

  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    if ($values['name'] == $values['password'])
    {
      throw new sfValidatorError('The password must not be the same as the name',
          'password');
    }
  }
}</pre>
<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>Related posts:<ol><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/07/no-piece-of-cake/' rel='bookmark' title='Permanent Link: No Piece of Cake'>No Piece of Cake</a> <small>Welcome to all of you on webmozarts.com! Whether you are...</small></li></ol></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 music [...]


Related posts:<ol><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li></ol>]]></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>
<pre lang="php">// lib/form/doctrine/ProfileForm.class.php
class ProfileForm extends sfFormDoctrine
{
  protected $user = null;

  public function __construct(sfUser $user)
  {
    $this-&gt;user = $user;
  }</pre>
<p>So far so good. Now let&#8217;s configure the form&#8217;s appearance and validation logic.</p>
<pre lang="php">  public function configure()
  {
    $this-&gt;setWidgets(array(
      'email'          =&gt; new sfWidgetFormInput(),
      'password'       =&gt; new sfWidgetFormInputPassword(),
      'password_again' =&gt; new sfWidgetFormInputPassword(),
    ));
    $this-&gt;widgetSchema-&gt;setLabel('password_again', 'Password (again)');

    $this-&gt;setValidators(array(
      'email'          =&gt; new sfValidatorEmail(array(), array(
        'required' =&gt; 'Please enter your email address',
      )),
      'password'       =&gt; new sfValidatorString(array(), array(
        'required' =&gt; 'Please enter a password',
      )),
      'password_again' =&gt; new sfValidatorPass(),
    ));

    // implement custom validation logic
    $this-&gt;validatorSchema-&gt;setPostValidator(new sfValidatorAnd(array(
      new sfValidatorSchemaCompare('password_again', '==', 'password', array(
        'invalid' =&gt; 'The passwords must be equal'
      )),
      new sfValidatorCallback(array(
        'callback' =&gt; array($this, 'comparePasswordAndName')
      )),
    )));

    // administrators may enter the user name
    if ($this-&gt;user-&gt;hasCredential('admin'))
    {
      $this-&gt;setWidget('name', new sfWidgetFormInput(array(), array(
        'max_length' =&gt; 15
      ));
      $this-&gt;setValidator('name', new sfValidatorString(array(
        'max_length' =&gt; 15
      ), array(
        'max_length' =&gt; 'The name must be 15 characters or longer'
      );
    }
  }</pre>
<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>
<pre lang="php">  public function comparePasswordAndName(sfValidator $validator, array $values)
  {
    // if the field "name" is not editable, it does not exist in $values
    if (array_key_exists('name', $values) &amp;&amp; $values['name'] == $values['password'])
    {
      $error = new sfValidatorError($validator,
          'The password must not be the same as the name');

      // throw an error schema so the error appears at the field "password"
      throw new sfValidatorErrorSchema($validator, array('password', $error));
    }
  }
}</pre>
<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>Related posts:<ol><li><a href='http://webmozarts.com/2009/04/23/improving-the-forms-layouts-and-formatters/' rel='bookmark' title='Permanent Link: Improving the Forms: Layouts and Formatters'>Improving the Forms: Layouts and Formatters</a> <small>Keeping all parts of a website consistent is one of...</small></li><li><a href='http://webmozarts.com/2009/04/19/improving-the-forms-field-groups/' rel='bookmark' title='Permanent Link: Improving the Forms: Field Groups'>Improving the Forms: Field Groups</a> <small>Today I want to follow up on my last post...</small></li><li><a href='http://webmozarts.com/2009/04/12/improving-the-forms/' rel='bookmark' title='Permanent Link: Improving the Forms'>Improving the Forms</a> <small>After my last post about simplifying symfony and especially the...</small></li></ol></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>
