<?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>Miximum &#187; forms</title>
	<atom:link href="http://www.miximum.fr/tag/forms/feed" rel="self" type="application/rss+xml" />
	<link>http://www.miximum.fr</link>
	<description>Le blog d&#039;un ingénieur web freelance</description>
	<lastBuildDate>Wed, 16 Nov 2011 16:25:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Symfony form : pick or create</title>
		<link>http://www.miximum.fr/tutos/466-symfony-form-pick-or-create</link>
		<comments>http://www.miximum.fr/tutos/466-symfony-form-pick-or-create#comments</comments>
		<pubDate>Tue, 02 Feb 2010 14:40:29 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Tutos]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=466</guid>
		<description><![CDATA[Here&#8217;s an other tutorial about the Symfony form framework. Last time, we managed to make embedded i18n forms optionals. In today&#8217;s howto, we will talk about embedded forms again. In the last tutorials, we created a form to edit news. Today we will create another form to write interviews. An interview is just an article [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s an other tutorial about the Symfony form framework. Last time, <a href="http://www.miximum.fr/tutos/449-optional-translation-form-for-i18n-objects-with-symfony-and-doctrine">we managed to make embedded i18n forms optionals</a>. In today&#8217;s howto, we will talk about embedded forms again.</p>
<p>In the last tutorials, we created a form to edit news. Today we will create another form to write interviews. An interview is just an article about a celebrity. So our Interview class will inherit from our Article one, so we can reuse our last time work.</p>
<p>Here&#8217;s the complete schema we will work with&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">Article:
  actAs:
    Timestampable: ~
    I18n:
      fields: [ title, body ]
      actAs:
        Sluggable: { fields: [ title ], uniqueBy: [ lang, title ] }
&nbsp;
  columns:
    title: { type: string(255), notnull: true }
    body: { type: clob, notnull: true }
    author: { type: string(255), notnull: false }
&nbsp;
News:
  inheritance:
    extends: Article
    type: concrete
&nbsp;
Celebrity:
  actAs:
    Sluggable:
      fields: [ firstname, lastname ]
  columns:
    firstname: { type: string(255), notnull: true }
    lastname: { type: string(255), notnull: true }
&nbsp;
Interview:
  inheritance:
    extends: Article
    type: concrete
&nbsp;
  columns:
    celebrity_id: { type: integer, notnull: true }
&nbsp;
  relations:
&nbsp;
    Celebrity:
      local: celebrity_id
      foreign: id
      type: one
      foreignType: one
      foreignAlias: Interviews</pre></div></div>

<p>And the fixtures&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">Interview:
  i1:
    Author: 'Thibault J.'
    Celebrity:
      firstname: Thibault
      lastname: Jouannic
    Translation:
      fr:
        title: Auto-interview
        body: |
          Bla bla bla question et réponses</pre></div></div>

<p>As usual&hellip;</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">php symfony build <span class="re5">--all</span> <span class="re5">--and-load</span>
php symfony doctrine:generate-admin backend Interview</pre></div></div>

<h2>Before we start</h2>
<p>Before we start, let&#8217;s stop and think a few seconds. How do we want to manage our celebrity relation into our form<span class="fine">&nbsp;</span>? Take a look at the default form, without any modification&nbsp;:</p>
<div class="postimg"><a href="http://www.flickr.com/photos/24469297@N05/4324656195/" title="01_celebrity" target="_blank"><img src="http://farm3.static.flickr.com/2687/4324656195_1f90822fc6.jpg" alt="01_celebrity" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> </small></div>
<p>Quite bad, isn&#8217;t it<span class="fine">&nbsp;</span>? We could make a little better by adding a toString method.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/model/doctrine/Celebrity.class.php</span>
&nbsp;
<span class="kw2">class</span> Celebrity <span class="kw2">extends</span> BaseCelebrity
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> __toString<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">return</span> <a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">&#40;</span><span class="st_h">'%s %s'</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getFirstname</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getLastname</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<div class="postimg"><a href="http://www.flickr.com/photos/24469297@N05/4325392592/" title="02_celebrity" target="_blank"><img src="http://farm5.static.flickr.com/4066/4325392592_dc60d3e13d.jpg" alt="02_celebrity" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a></small></div>
<p>That&#8217;s a bit better. The problem with this form is that you cannot add a new celebrity. If you want to create a new interview, you&#8217;ll have to chose among the existing celebrities. Of course, you could create an other admin module to manage celebrities, but a good programmer is a lazy one. And that would be great if we could create a new celebrity directly in the interview form.</p>
<p>In fact, that&#8217;s quite easy, <a href="http://prendreuncafe.com/blog/post/2009/11/29/Embedding-Relations-in-Forms-with-Symfony-1.3-and-Doctrine">using the embedRelation function</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/InterviewForm.class.php</span>
<span class="kw2">class</span> InterviewForm <span class="kw2">extends</span> BaseInterviewForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * @see ArticleForm
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">configure</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedRelation</span><span class="br0">&#40;</span><span class="st_h">'Celebrity'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<div class="postimg"><a href="http://www.flickr.com/photos/24469297@N05/4325392638/" title="03_celebrity" target="_blank"><img src="http://farm5.static.flickr.com/4015/4325392638_ecf4e66bb4.jpg" alt="03_celebrity" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a></small></div>
<p>Here&#8217;s the result, which is quite relevant to what we wanted. But<span class="fine">&nbsp;</span>!? Wait<span class="fine">&nbsp;</span>! There is a regression. What if we want to choose among existing celebrities, the way we used to do<span class="fine">&nbsp;</span>? What we really need is a way to combine both methods actually. We need to be able to choose an existing celebrity OR to create a new one.</p>
<h2>Pick or create</h2>
<p>We will have to use an intermediate form.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/InterviewForm.class.php</span>
<span class="kw2">class</span> InterviewForm <span class="kw2">extends</span> BaseInterviewForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * @see ArticleForm
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">configure</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$celebrityId</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">isNew</span><span class="br0">&#40;</span><span class="br0">&#41;</span> ? <span class="kw4">NULL</span> <span class="sy0">:</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getCelebrity</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$form</span> <span class="sy0">=</span> <span class="kw2">new</span> InterviewCelebrityForm<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'celebrity_id'</span> <span class="sy0">=&gt;</span> <span class="re0">$celebrityId</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedForm</span><span class="br0">&#40;</span><span class="st_h">'Celebrity'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co1">// lib/form/doctrine/InterviewCelebrityForm.class.php</span>
<span class="kw2">class</span> InterviewCelebrityForm <span class="kw2">extends</span> sfForm
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfWidgetFormDoctrineChoice<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'model'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Celebrity'</span><span class="sy0">,</span>
      <span class="st_h">'add_empty'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">setDefault</span><span class="br0">&#40;</span><span class="st_h">'celebrity_id'</span><span class="sy0">,</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getOption</span><span class="br0">&#40;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$form</span> <span class="sy0">=</span> <span class="kw2">new</span> CelebrityForm<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedForm</span><span class="br0">&#40;</span><span class="st_h">'new_celebrity'</span><span class="sy0">,</span> <span class="re0">$form</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="sy0">-&gt;</span><span class="me1">setLabel</span><span class="br0">&#40;</span><span class="st_h">'celebrity_id'</span><span class="sy0">,</span> <span class="st_h">'Choose one…'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="sy0">-&gt;</span><span class="me1">setLabel</span><span class="br0">&#40;</span><span class="st_h">'new_celebrity'</span><span class="sy0">,</span> <span class="st_h">'or create a new.'</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<div class="postimg"><a href="http://www.flickr.com/photos/24469297@N05/4325392696/" title="04_celebrity" target="_blank"><img src="http://farm3.static.flickr.com/2702/4325392696_aa940a7fb8.jpg" alt="04_celebrity" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a></small></div>
<p>Try to edit the existing interview, and look at the nice result. However, if you try to save the form, you&#8217;ll have a lot of validations errors. There is still some work to do before we can get rid of all those red alerts.</p>
<div class="postimg"><a href="http://www.flickr.com/photos/24469297@N05/4324656371/" title="05_celebrity" target="_blank"><img src="http://farm5.static.flickr.com/4034/4324656371_64d6c5eb2f.jpg" alt="05_celebrity" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by-sa/2.0/" title="Attribution-ShareAlike License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a></small></div>
<h2>Form validation</h2>
<p>The form validation strategy is quite simple. If an existing celebrity is chosen with the drop down list, the firstname and lastname should be ignored. If the list is empty, we must validate the firstname and lastname. At last, we must throw an error if all the fields are empty.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/InterviewCelebrityForm.class.php</span>
&nbsp;
    <span class="co1">// add this  at the end of the configure() function</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">validatorSchema</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfValidatorPass<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$celebrityValidatorSchema</span> <span class="sy0">=</span> clone <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">validatorSchema</span><span class="br0">&#91;</span><span class="st_h">'new_celebrity'</span><span class="br0">&#93;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">validatorSchema</span><span class="br0">&#91;</span><span class="st_h">'new_celebrity'</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw2">new</span> sfValidatorPass<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">validatorSchema</span><span class="sy0">-&gt;</span><span class="me1">setPostValidator</span><span class="br0">&#40;</span>
      <span class="kw2">new</span> sfValidatorAnd<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
        <span class="kw2">new</span> sfValidatorOr<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
          <span class="kw2">new</span> sfValidatorSchemaFilter<span class="br0">&#40;</span><span class="st_h">'celebrity_id'</span><span class="sy0">,</span> <span class="kw2">new</span> sfValidatorDoctrineChoice<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
            <span class="st_h">'model'</span> <span class="sy0">=&gt;</span> <span class="st_h">'Celebrity'</span><span class="sy0">,</span>
            <span class="st_h">'required'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span>
          <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span>
          <span class="kw2">new</span> sfValidatorSchemaFilter<span class="br0">&#40;</span><span class="st_h">'new_celebrity'</span><span class="sy0">,</span> <span class="re0">$celebrityValidatorSchema</span><span class="br0">&#41;</span>
        <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span>
        <span class="kw2">new</span> sfValidatorCallback<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
          <span class="st_h">'callback'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">,</span> <span class="st_h">'checkCelebrity'</span><span class="br0">&#41;</span>
        <span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="co1">// add this function into the class</span>
  <span class="co4">/**
   * Either who choose an existing celebrity, either we create a new one
   *
   * Unset values according to the choice we made
   **/</span>
  <span class="kw2">public</span> <span class="kw2">function</span> checkCelebrity<span class="br0">&#40;</span><span class="re0">$validator</span><span class="sy0">,</span> <span class="re0">$values</span><span class="sy0">,</span> <span class="re0">$argument</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span><a href="http://www.php.net/empty"><span class="kw3">empty</span></a><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span>
        <span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'new_celebrity'</span><span class="br0">&#93;</span><span class="sy0">,</span>
        <span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'new_celebrity'</span><span class="br0">&#93;</span>
      <span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">else</span>
    <span class="br0">&#123;</span>
      <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span>
        <span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="sy0">,</span>
        <span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span>
      <span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw1">return</span> <span class="re0">$values</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div>

<p>Try differents combinations to submit your form. The validation should behave correctly now.</p>
<h2>Saving your form</h2>
<p>You may have noticed that our interview isn&#8217;t updated correctly after we submit the form. We will have to override the doUpdateObject method in order to update the object correctly on form validation.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/InterviewForm.class.php</span>
  <span class="kw2">public</span> <span class="kw2">function</span> doUpdateObject<span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span><a href="http://www.php.net/empty"><span class="kw3">empty</span></a><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'Celebrity'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">setCelebrityId</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'Celebrity'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'celebrity_id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">else</span>
    <span class="br0">&#123;</span>
      <span class="re0">$celebrity</span> <span class="sy0">=</span> <span class="kw2">new</span> Celebrity<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">fromArray</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'Celebrity'</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st_h">'new_celebrity'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">getObject</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">Celebrity</span> <span class="sy0">=</span> <span class="re0">$celebrity</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span>
      <span class="re0">$values</span><span class="br0">&#91;</span><span class="st_h">'Celebrity'</span><span class="br0">&#93;</span><span class="sy0">,</span>
      <span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'Celebrity'</span><span class="br0">&#93;</span>
    <span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    parent<span class="sy0">::</span><span class="me2">doUpdateObject</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span></pre></div></div>

<p>That&#8217;s it<span class="fine">&nbsp;</span>! Everything should be alright now. But just to make sure, here&#8217;s a few tests.</p>
<h2>Test your forms</h2>
<p>We are reusing some code from the last day, so I just will output the new part here.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">// test/function/backend/interviewActions.class.php
&nbsp;
<span class="kw2">&lt;?php</span>
&nbsp;
<span class="kw1">include</span><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><span class="kw4">__FILE__</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'/../../bootstrap/functional.php'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$browser</span> <span class="sy0">=</span> <span class="kw2">new</span> sfBackendTestFunctional<span class="br0">&#40;</span><span class="kw2">new</span> sfBrowser<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">loadData</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">setTester</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="sy0">,</span> <span class="st_h">'sfTesterDoctrine'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$interview</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st_h">'Interview'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">createQuery</span><span class="br0">&#40;</span><span class="st_h">'i'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">leftJoin</span><span class="br0">&#40;</span><span class="st_h">'i.Translation t'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">andWhere</span><span class="br0">&#40;</span><span class="st_h">'t.lang = ?'</span><span class="sy0">,</span> <span class="st_h">'fr'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">orderBy</span><span class="br0">&#40;</span><span class="st_h">'i.id'</span><span class="sy0">,</span> <span class="st_h">'asc'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">fetchOne</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$celebrity</span> <span class="sy0">=</span> <span class="kw2">new</span> Celebrity<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">setFirstname</span><span class="br0">&#40;</span><span class="st_h">'toto'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">setLastname</span><span class="br0">&#40;</span><span class="st_h">'tutu'</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">save</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$editUrl</span> <span class="sy0">=</span> <a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">&#40;</span><span class="st_h">'/interview/%s/edit'</span><span class="sy0">,</span> <span class="re0">$interview</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$browser</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'/interview'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">isStatusCode</span><span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'1 - Interview list'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'h1'</span><span class="sy0">,</span> <span class="st_h">'/Interview List/'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'body'</span><span class="sy0">,</span> <span class="st_h">'/Thibault Jouannic/'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
<span class="co1">// …</span>
&nbsp;
   info<span class="br0">&#40;</span><span class="st_h">'  2.8 - The current celebrity is already selected'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'#interview_Celebrity_celebrity_id option[selected=&quot;selected&quot;]'</span><span class="sy0">,</span> <a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">&#40;</span><span class="st_h">'/%s/'</span><span class="sy0">,</span> <span class="re0">$interview</span><span class="sy0">-&gt;</span><span class="me1">getCelebrity</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.9 - The current celebrity can be updated'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'interview'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'Celebrity'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'celebrity_id'</span> <span class="sy0">=&gt;</span> <span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
      <span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'Interview'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$interview</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'celebrity_id'</span> <span class="sy0">=&gt;</span> <span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.10 - Updating the celebrity does not create empty records'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'Celebrity'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">4</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.11 - A new celebrity can be created'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'interview'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'Celebrity'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'celebrity_id'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span>
      <span class="st_h">'NewCelebrity'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
        <span class="st_h">'firstname'</span> <span class="sy0">=&gt;</span> <span class="st_h">'oncle'</span><span class="sy0">,</span>
        <span class="st_h">'lastname'</span> <span class="sy0">=&gt;</span> <span class="st_h">'picsou'</span>
      <span class="br0">&#41;</span>
    <span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'Celebrity'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="nu0">5</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'Interview'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$interview</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'celebrity_id'</span> <span class="sy0">=&gt;</span> <span class="re0">$celebrity</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">+</span> <span class="nu0">1</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="sy0">;</span></pre></div></div>

<p>That&#8217;s all folks<span class="fine">&nbsp;</span>! See you soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/tutos/466-symfony-form-pick-or-create/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Optional translation form for I18n objects with Symfony and Doctrine</title>
		<link>http://www.miximum.fr/tutos/449-optional-translation-form-for-i18n-objects-with-symfony-and-doctrine</link>
		<comments>http://www.miximum.fr/tutos/449-optional-translation-form-for-i18n-objects-with-symfony-and-doctrine#comments</comments>
		<pubDate>Fri, 29 Jan 2010 14:23:20 +0000</pubDate>
		<dc:creator>thibault</dc:creator>
				<category><![CDATA[Tutos]]></category>
		<category><![CDATA[doctrine]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[I18n]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[symfony]]></category>

		<guid isPermaLink="false">http://www.miximum.fr/?p=449</guid>
		<description><![CDATA[photo credit&#160;: kevindooley There are people around here claiming that the Symfony form framework is a gift from the gods. One might say that this statement is a bit exaggerated, but it&#8217;s true that the release of the 1.3/1.4 version of the Symfony brought many improvements, and yes, the form framework can save you a [...]]]></description>
			<content:encoded><![CDATA[<div class="postimg alignleft"><a href="http://www.flickr.com/photos/12836528@N00/2201791390/" title="Scaffolding: Not just for construction workers anymore" target="_blank"><img src="http://farm3.static.flickr.com/2037/2201791390_7bc614e27c_m.jpg" alt="Scaffolding: Not just for construction workers anymore" border="0" /></a><br /><small><a href="http://creativecommons.org/licenses/by/2.0/" title="Attribution License" target="_blank"><img src="http://www.miximum.fr/wp-content/plugins/photo-dropper/images/cc.png" alt="Creative Commons License" border="0" width="16" height="16" align="absmiddle" /></a> <a href="http://www.photodropper.com/photos/" target="_blank">photo</a> credit&nbsp;: <a href="http://www.flickr.com/photos/12836528@N00/2201791390/" title="kevindooley" target="_blank">kevindooley</a></small></div>
<p>There are people around here claiming that the <a href="http://www.symfony-project.org/forms/1_4/">Symfony form framework</a> is a gift from the gods. One might say that this statement is a bit exaggerated, but it&#8217;s true that the release of the 1.3/1.4 version of the Symfony brought many improvements, and yes, the form framework can save you a lot of time.</p>
<p>In one of my current project, I had to developp some basic CMS-like features. In a back-office, an admin should be able to writes different kind of articles (news, interviews&hellip;). Hey<span class="fine">&nbsp;</span>! <a href="http://www.symfony-project.org/more-with-symfony/1_4/en/09-Doctrine-Form-Inheritance">That&#8217;s a job for inheritance<span class="fine">&nbsp;</span>!</a> But wait, there&#8217;s more. Articles can be translated in several languages. <a href="http://www.doctrine-project.org/documentation/manual/1_2/en/behaviors#core-behaviors:i18n">Easy, with the Doctrine I18n behavior</a>.</p>
<p>One last requirement&nbsp;: article translations are optional. One might publish an article in english, an other in french, and a third in both languages. This is a little more tricky, so let&#8217;s see how to do this.</p>
<h2>Some references</h2>
<p>Before we start, here are the wonderful ressources I read to get my way out&nbsp;:</p>
<p><a href="http://prendreuncafe.com/blog/post/2009/11/29/Embedding-Relations-in-Forms-with-Symfony-1.3-and-Doctrine"> http://prendreuncafe.com/blog/post/2009/11/29/Embedding-Relations-in-Forms-with-Symfony-1.3-and-Doctrine</a><br />
<a href="http://symfonyguide.wordpress.com/2009/09/28/symfony-forms-saving-process/"> http://symfonyguide.wordpress.com/2009/09/28/symfony-forms-saving-process/</a><br />
<a href="http://vousavezchoisi.com/img/formsdiagram.png"> http://vousavezchoisi.com/img/formsdiagram.png</a><br />
<a href="http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms#chapter_06_ignoring_embedded_forms"> http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms#chapter_06_ignoring_embedded_forms</a><br />
<a href="http://www.ze-technology.com/2009/06/05/tests-fonctionnels-avec-symfony-gerer-lidentification/"> http://www.ze-technology.com/2009/06/05/tests-fonctionnels-avec-symfony-gerer-lidentification/</a></p>
<h2>Let&#8217;s start with the schema</h2>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">Article:
  actAs:
    Timestampable: ~
    I18n:
      fields: [ title, body ]
      actAs:
        Sluggable: { fields: [ title ], uniqueBy: [ lang, title ] }
&nbsp;
  columns:
    title: { type: string(255), notnull: true }
    body: { type: clob, notnull: true }
    author: { type: string(255), notnull: false }
&nbsp;
News:
  inheritance:
    extends: Article
    type: concrete</pre></div></div>

<p>As it&#8217;s friday, I will also give you some fixtures&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">News:
  n1:
    author: 'Fantomas'
    Translation:
      fr:
        title: 'OK, l''Ipad est sorti. Vous allez me foutre la paix maintentant ?'
        body: |
          Vous commencez serieusement à me gonfler avec vos articles et vos tweets sur
          une techno inutile et bardée de DRM.
&nbsp;
  n2:
    author: 'Garcin Fony'
    Translation:
      fr:
        title: 'Sinon, à part ça, ça va ?'
        body: |
          Allez, pour me calmer, je vais me refaire un p'tit café</pre></div></div>

<p>Let&#8217;s build the whole thing, and generate the admin in the same time.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">php symfony doctrine:build <span class="re5">--all</span> <span class="re5">--and-load</span>
php symfony generate:app backend
php symfony doctrine:generate-admin backend News</pre></div></div>

<p>Check the module admin we&#8217;ve just build. Click on the first &laquo;&nbsp;&nbsp;edit&nbsp;&nbsp;&raquo; button. Wait a minute<span class="fine">&nbsp;</span>? The I18n fields are just missing, how are we gonna edit our articles<span class="fine">&nbsp;</span>? If you&#8217;re not familiar with the I18n behavior, you must know that the content is split into two tables. The new table, &laquo;&nbsp;&nbsp;article_translation&nbsp;&nbsp;&raquo;, holds all the I18n fields.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">mysql<span class="sy0">&gt;</span> <span class="kw1">SELECT</span> <span class="sy0">*</span> <span class="kw1">FROM</span> news;
<span class="sy0">+</span><span class="co1">----+-------------+---------------------+---------------------+</span>
<span class="sy0">|</span> id <span class="sy0">|</span> author      <span class="sy0">|</span> created_at          <span class="sy0">|</span> updated_at          <span class="sy0">|</span>
<span class="sy0">+</span><span class="co1">----+-------------+---------------------+---------------------+</span>
<span class="sy0">|</span>  <span class="nu0">1</span> <span class="sy0">|</span> Fantomas    <span class="sy0">|</span> <span class="nu0">2010</span><span class="sy0">-</span>01<span class="sy0">-</span><span class="nu0">29</span> <span class="nu0">12</span>:<span class="nu0">14</span>:<span class="nu0">46</span> <span class="sy0">|</span> <span class="nu0">2010</span><span class="sy0">-</span>01<span class="sy0">-</span><span class="nu0">29</span> <span class="nu0">12</span>:<span class="nu0">14</span>:<span class="nu0">46</span> <span class="sy0">|</span> 
<span class="sy0">|</span>  <span class="nu0">2</span> <span class="sy0">|</span> Garcin Fony <span class="sy0">|</span> <span class="nu0">2010</span><span class="sy0">-</span>01<span class="sy0">-</span><span class="nu0">29</span> <span class="nu0">12</span>:<span class="nu0">14</span>:<span class="nu0">46</span> <span class="sy0">|</span> <span class="nu0">2010</span><span class="sy0">-</span>01<span class="sy0">-</span><span class="nu0">29</span> <span class="nu0">12</span>:<span class="nu0">14</span>:<span class="nu0">46</span> <span class="sy0">|</span> 
<span class="sy0">+</span><span class="co1">----+-------------+---------------------+---------------------+</span>
&nbsp;
mysql<span class="sy0">&gt;</span> <span class="kw1">SELECT</span> id<span class="sy0">,</span> lang<span class="sy0">,</span> title <span class="kw1">FROM</span> news_translation;
<span class="sy0">+</span><span class="co1">----+------+------------------------------------------------------------------+</span>
<span class="sy0">|</span> id <span class="sy0">|</span> lang <span class="sy0">|</span> title                                                            <span class="sy0">|</span>
<span class="sy0">+</span><span class="co1">----+------+------------------------------------------------------------------+</span>
<span class="sy0">|</span>  <span class="nu0">1</span> <span class="sy0">|</span> fr   <span class="sy0">|</span> OK<span class="sy0">,</span> l<span class="st0">'Ipad est sorti. Vous allez me foutre la paix maintentant ? | 
|  2 | fr   | Sinon, à part ça, ça va ?                                     | 
+----+------+------------------------------------------------------------------+</span></pre></div></div>

<p>So, to be able to edit our translations, you have to embed the I18n forms, using the embedI18 function. Let&#8217;s do that.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/NewsForm.class.php</span>
<span class="kw2">class</span> NewsForm <span class="kw2">extends</span> BaseNewsForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * @see ArticleForm
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">configure</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedI18n</span><span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'fr'</span><span class="sy0">,</span> <span class="st_h">'en'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Reload the edit page. Now you can edit your news in french and english. Pretty cool, isn&#8217;t it<span class="fine">&nbsp;</span>?</p>
<h2>Let&#8217;s refactor this mess</h2>
<p>Since now, it&#8217;s been pretty easy. However, the code we&#8217;ve written is bad. It&#8217;s bad, for the following reasons&nbsp;:</p>
<ol>
<li>Each time we will add a new article type (e.g. interview, etc.), we will have to update it&#8217;s configure method&nbsp;<span class="fine">&nbsp;</span>;</li>
<li>Each time we will change the available languages (to add a new one, or disable an existing one), we will have to edit every forms&nbsp;<span class="fine">&nbsp;</span>;</li>
</ol>
<p>Fortunately, since Symfony 1.3, <a href="http://www.symfony-project.org/tutorial/1_4/en/whats-new#chapter_a2fae23c9403b0e9ec99806fccf6b53e_sub_form_classes_inheritance">the form inheritance follow the model structure</a>. Notice that NewsForm extends BaseNewsForm, which extends ArticleForm.</p>
<p>Let&#8217;s refactor our code&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="yml" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"># config/app.yml
all:
  cultures:
    enabled:
      fr: Français
      en: English</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/NewsForm.class.php</span>
&nbsp;
<span class="co1">// Revert the changes we added there</span>
<span class="kw2">class</span> NewsForm <span class="kw2">extends</span> BaseNewsForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * @see ArticleForm
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">configure</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="co1">// lib/form/doctrine/ArticleForm.class.php</span>
<span class="kw2">class</span> ArticleForm <span class="kw2">extends</span> BaseArticleForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * Available languages
   *
   * @var array $languages
   **/</span>
  protected <span class="re0">$langages</span><span class="sy0">;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="sy0">=</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'app_cultures_enabled'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$langs</span> <span class="sy0">=</span> <a href="http://www.php.net/array_keys"><span class="kw3">array_keys</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedI18n</span><span class="br0">&#40;</span><span class="re0">$langs</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="kw1">as</span> <span class="re0">$lang</span> <span class="sy0">=&gt;</span> <span class="re0">$label</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">setLabel</span><span class="br0">&#40;</span><span class="re0">$label</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Reload the edit form. Now, no matter how many articles sub-types you add, you still can configure available languages from one place.</p>
<h2>Translation edition</h2>
<p>Let&#8217;s try our brand new admin module by editing a news. If you used the fixtures I provided, you should have a french article, with no english translation. Try to update the french version, and click on the &#8216;Save&#8217; button.</p>
<p>This is a miserable failure. We can&#8217;t save the form, because the english fields are required. We&#8217;re stuck, we have to fill every translation for an article before we can save it. Wouldn&#8217;t it be nice if we could make a translation form optional<span class="fine">&nbsp;</span>? Let&#8217;s add a requirement&nbsp;: if every fields in a translation form are empty, it just should be ignored.</p>
<p>To achieve this goal, we will update the doBind method. Here&#8217;s the new ArticleForm class.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/ArticleForm.class.php</span>
<span class="kw2">class</span> ArticleForm <span class="kw2">extends</span> BaseArticleForm
<span class="br0">&#123;</span>
  <span class="co4">/**
   * Available languages
   *
   * @var array $languages
   **/</span>
  protected <span class="re0">$langages</span><span class="sy0">;</span>
&nbsp;
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="sy0">=</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'app_cultures_enabled'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$langs</span> <span class="sy0">=</span> <a href="http://www.php.net/array_keys"><span class="kw3">array_keys</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embedI18n</span><span class="br0">&#40;</span><span class="re0">$langs</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="kw1">as</span> <span class="re0">$lang</span> <span class="sy0">=&gt;</span> <span class="re0">$label</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widgetSchema</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="sy0">-&gt;</span><span class="me1">setLabel</span><span class="br0">&#40;</span><span class="re0">$label</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co4">/**
   * Cleans and binds values to the current form
   *
   * Ignore i18n forms when all their fields are empty
   *
   * @see sfForm::doBind
   **/</span>
  protected <span class="kw2">function</span> doBind<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="re0">$values</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="kw1">as</span> <span class="re0">$lang</span> <span class="sy0">=&gt;</span> <span class="re0">$label</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embeddedI18nFormIsEmpty</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span>
          <span class="re0">$values</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="sy0">,</span>
          <span class="re0">$this</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span>
        <span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    parent<span class="sy0">::</span><span class="me2">doBind</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co4">/**
   * Check if every fields, except for id and lang, are empty
   **/</span>
  protected <span class="kw2">function</span> embeddedI18nFormIsEmpty<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="re0">$values</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$values</span> <span class="kw1">as</span> <span class="re0">$key</span> <span class="sy0">=&gt;</span> <span class="re0">$value</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/in_array"><span class="kw3">in_array</span></a><span class="br0">&#40;</span><span class="re0">$key</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'id'</span><span class="sy0">,</span> <span class="st_h">'lang'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
        <span class="kw1">continue</span><span class="sy0">;</span>
&nbsp;
      <span class="kw1">if</span><span class="br0">&#40;</span><span class="st_h">''</span> <span class="sy0">!==</span> <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$value</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="kw4">false</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    <span class="kw1">return</span> <span class="kw4">true</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>In the overidden doBind method, we check, for every I18n form, if some values has been submited. If not, we just unset the corresponding fields.</p>
<p>Reload the edit form, update the french translation, leave the english field empty, and click on &#8216;Save&#8217;. Hurray, the forms is saved correctly.</p>
<p>However, you should keep reading, because you&#8217;re gonna have a surprise. Let&#8217;s look into the database.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;">mysql<span class="sy0">&gt;</span> <span class="kw1">SELECT</span> id<span class="sy0">,</span> lang<span class="sy0">,</span> slug <span class="kw1">FROM</span> news_translation;
<span class="sy0">+</span><span class="co1">----+------+--------------------------------------------------------------+</span>
<span class="sy0">|</span> id <span class="sy0">|</span> lang <span class="sy0">|</span> slug                                                         <span class="sy0">|</span>
<span class="sy0">+</span><span class="co1">----+------+--------------------------------------------------------------+</span>
<span class="sy0">|</span>  <span class="nu0">1</span> <span class="sy0">|</span> en   <span class="sy0">|</span>                                                              <span class="sy0">|</span> 
<span class="sy0">|</span>  <span class="nu0">1</span> <span class="sy0">|</span> fr   <span class="sy0">|</span> ok<span class="sy0">-</span>l<span class="sy0">-</span>ipad<span class="sy0">-</span>est<span class="sy0">-</span>sorti<span class="sy0">-</span>vous<span class="sy0">-</span>allez<span class="sy0">-</span>me<span class="sy0">-</span>foutre<span class="sy0">-</span>la<span class="sy0">-</span>paix<span class="sy0">-</span>maintentant <span class="sy0">|</span> 
<span class="sy0">|</span>  <span class="nu0">2</span> <span class="sy0">|</span> fr   <span class="sy0">|</span> sinon<span class="sy0">-</span>a<span class="sy0">-</span>part<span class="sy0">-</span>ca<span class="sy0">-</span>ca<span class="sy0">-</span>va                                        <span class="sy0">|</span> 
<span class="sy0">+</span><span class="co1">----+------+--------------------------------------------------------------</span></pre></div></div>

<p>Something went wrong<span class="fine">&nbsp;</span>! Somewhere in the process, Symfony created an empty translation object for our article. Notice the void &laquo;&nbsp;&nbsp;slug&nbsp;&nbsp;&raquo; field<span class="fine">&nbsp;</span>? If you try to edit another news, you will receive a duplicate content error. WTF<span class="fine">&nbsp;</span>?</p>
<p>I must admit that I don&#8217;t fully understand why this happens (sometimes I think I do, and a few minutes later, I realize I don&#8217;t). However, here&#8217;s the solution to overcome this problem.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/ArticleForm.class.php</span>
&nbsp;
  <span class="co1">// Add this at the beginnig of the class:</span>
  <span class="co4">/**
   * I18n ignored forms
   **/</span>
  protected <span class="re0">$I18nFormsIgnored</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
  <span class="co1">// update the doBind method:</span>
  <span class="co4">/**
   * Unset i18n forms values when every field is empty
   **/</span>
  protected <span class="kw2">function</span> doBind<span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a> <span class="re0">$values</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">languages</span> <span class="kw1">as</span> <span class="re0">$lang</span> <span class="sy0">=&gt;</span> <span class="re0">$label</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">embeddedI18nFormEmpty</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
      <span class="br0">&#123;</span>
        <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">I18nFormsIgnored</span><span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="re0">$lang</span><span class="sy0">;</span>
        <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span>
          <span class="re0">$values</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="sy0">,</span>
          <span class="re0">$this</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span>
        <span class="br0">&#41;</span><span class="sy0">;</span>
      <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    parent<span class="sy0">::</span><span class="me2">doBind</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co1">// And override the doUpdateObject method:</span>
  <span class="co4">/**
   * Updates the values of the object with the cleaned up values.
   *
   * @param  array $values An array of values
   *
   * @see sfFormDoctrine::doUpdateObject()
   */</span>
  protected <span class="kw2">function</span> doUpdateObject<span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">doUpdateObject</span><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">I18nFormsIgnored</span> <span class="kw1">as</span> <span class="re0">$lang</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
      <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">object</span><span class="sy0">-&gt;</span><span class="me1">Translation</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
      <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$values</span><span class="br0">&#91;</span><span class="re0">$lang</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
  <span class="br0">&#125;</span></pre></div></div>

<p>Delete the useless line in the mysql database, so we can start on a clean base. Once more, reload the edit form, leave the english translation empty, save the form, et voil&agrave;<span class="fine">&nbsp;</span>! The form is saved, the translation is updated, and no empty line is added in the table.</p>
<h2>Adding and deleting a translation</h2>
<p>Just to be sure, add some data in the english translation title, and try to save the form. You should get a &laquo;&nbsp;&nbsp;body is required&nbsp;&nbsp;&raquo; error, which is the expected behavior. Try to fill correctly the english translation, and save again. Check that the english translation is correctly added in the database. Erase all french fields, save one more time, and check that the french translation is definitly removed from the DB (no dummy entry).</p>
<p>Well, it seems that our form is pretty functional. One last thing&nbsp;: there is still a &laquo;&nbsp;&nbsp;slug&nbsp;&nbsp;&raquo; field in each translation form, that you might want to unset. Easy, just edit the ArticleTranslationForm.class.php file&nbsp;:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/ArticleTranslationForm.class.php</span>
&nbsp;
<span class="kw2">class</span> ArticleTranslationForm <span class="kw2">extends</span> BaseArticleTranslationForm
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    <a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$this</span><span class="br0">&#91;</span><span class="st_h">'slug'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Edit a news. If you&#8217;re using Symfony 1.{3,4}.1, you&#8217;ll see that the damn slug field is still there. It&#8217;s a Symfony bug. Indeed, <a href="http://trac.symfony-project.org/ticket/8199">the translations forms don&#8217;t follow the inheritance schema</a>. Notice that BaseNewsTranslationForm extends BaseFormDoctrine instead of ArticleNewsTranslation.</p>
<p>You&#8217;ll have to manually change that, however, this will be overidden each time you rebuild your forms.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/form/doctrine/base/BaseNewsTranslationForm.class.php</span>
<span class="co1">// Replace</span>
abstract <span class="kw2">class</span> BaseNewsTranslationForm <span class="kw2">extends</span> BaseFormDoctrine
&nbsp;
<span class="co1">// with</span>
abstract <span class="kw2">class</span> BaseNewsTranslationForm <span class="kw2">extends</span> ArticleTranslationForm
&nbsp;
<span class="co1">// lib/form/doctrine/NewsTranslationForm.class.php</span>
<span class="co1">// Edit the configure method</span>
<span class="kw2">class</span> NewsTranslationForm <span class="kw2">extends</span> BaseNewsTranslationForm
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> configure<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span><span class="me2">configure</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>

<p>Now, the slug field should disapear. At the present moment, the bug is still open.</p>
<h2>Let&#8217;s test everything</h2>
<p>As it&#8217;s friday, I feel generous, so as a bonus, I will give you the functional tests to cover our magical form. Enjoy.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// lib/sfBackendTestFunctional.class.php</span>
<span class="co4">/**
 * This class is used to run functional tests in a secured backend
 *
 * Takes care of the login action, and the fixtures loading
 */</span>
<span class="kw2">class</span> sfBackendTestFunctional <span class="kw2">extends</span> sfTestFunctional
<span class="br0">&#123;</span>
  <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$browser</span><span class="sy0">,</span> <span class="re0">$lime</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="re0">$testers</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    parent<span class="sy0">::</span>__construct<span class="br0">&#40;</span><span class="re0">$browser</span><span class="sy0">,</span> <span class="re0">$lime</span><span class="sy0">,</span> <span class="re0">$testers</span><span class="br0">&#41;</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
&nbsp;
  <span class="co4">/**
   * Perform user authentication
   *
   * @param   array of String         $user_data
   * @return  sfGuardTestFunctional   $this
   */</span>
  <span class="kw2">public</span> <span class="kw2">function</span> signin<span class="br0">&#40;</span><span class="re0">$user_data</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
   <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">info</span><span class="br0">&#40;</span><a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">&#40;</span><span class="st_h">'Login as &quot;%s&quot;'</span><span class="sy0">,</span> <span class="re0">$user_data</span><span class="br0">&#91;</span><span class="st_h">'username'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
     <span class="me1">get</span><span class="br0">&#40;</span><span class="st_h">'/login'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
     <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'sign in'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'signin'</span> <span class="sy0">=&gt;</span> <span class="re0">$user_data</span><span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
     <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
     <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
     <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'user'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">isAuthenticated</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
     <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
     <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'request'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">isParameter</span><span class="br0">&#40;</span><span class="st_h">'module'</span><span class="sy0">,</span> <span class="st_h">'sfGuardAuth'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">isParameter</span><span class="br0">&#40;</span><span class="st_h">'action'</span><span class="sy0">,</span> <span class="st_h">'signin'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
     <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
     <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">isRedirected</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <span class="me1">followRedirect</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
       <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="sy0">;</span>
  <span class="br0">&#125;</span>
  <span class="co4">/**
   * Load project fixtures
   **/</span>
  <span class="kw2">public</span> <span class="kw2">function</span> loadData<span class="br0">&#40;</span><span class="br0">&#41;</span>
  <span class="br0">&#123;</span>
    Doctrine<span class="sy0">::</span><span class="me2">loadData</span><span class="br0">&#40;</span>sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'sf_data_dir'</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'/fixtures'</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">return</span> <span class="re0">$this</span><span class="sy0">;</span>
  <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;color: #ccc; font: 12px Consolas, Lucida Console, Monaco, monospace;"><span class="co1">// test/functional/backend/newsActionsTest.php</span>
&nbsp;
<span class="kw1">include</span><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><span class="kw4">__FILE__</span><span class="br0">&#41;</span><span class="sy0">.</span><span class="st_h">'/../../bootstrap/functional.php'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$browser</span> <span class="sy0">=</span> <span class="kw2">new</span> sfBackendTestFunctional<span class="br0">&#40;</span><span class="kw2">new</span> sfBrowser<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">loadData</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$browser</span><span class="sy0">-&gt;</span><span class="me1">setTester</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="sy0">,</span> <span class="st_h">'sfTesterDoctrine'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$languages</span> <span class="sy0">=</span> sfConfig<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'app_cultures_enabled'</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$news</span> <span class="sy0">=</span> Doctrine<span class="sy0">::</span><span class="me2">getTable</span><span class="br0">&#40;</span><span class="st_h">'News'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">createQuery</span><span class="br0">&#40;</span><span class="st_h">'n'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">leftJoin</span><span class="br0">&#40;</span><span class="st_h">'n.Translation t'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">andWhere</span><span class="br0">&#40;</span><span class="st_h">'t.lang = ?'</span><span class="sy0">,</span> <span class="st_h">'fr'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">orderBy</span><span class="br0">&#40;</span><span class="st_h">'n.id'</span><span class="sy0">,</span> <span class="st_h">'asc'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">fetchOne</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$editUrl</span> <span class="sy0">=</span> <a href="http://www.php.net/sprintf"><span class="kw3">sprintf</span></a><span class="br0">&#40;</span><span class="st_h">'/news/%s/edit'</span><span class="sy0">,</span> <span class="re0">$news</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$browser</span><span class="sy0">-&gt;</span>
  <span class="co1">// Uncomment this if your backend is protected by a login</span>
  <span class="co1">//signin(array(</span>
  <span class="co1">//  'username' =&gt; 'admin',</span>
  <span class="co1">//  'password' =&gt; 'admin'</span>
  <span class="co1">//)))-&gt;</span>
  get<span class="br0">&#40;</span><span class="st_h">'/news'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">isStatusCode</span><span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'1 - News list'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'h1'</span><span class="sy0">,</span> <span class="st_h">'/News List/'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'body'</span><span class="sy0">,</span> <span class="st_h">'/Fantomas/'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'2 - News edit'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.1 - I18n forms for all languages are embedded'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'response'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">isStatusCode</span><span class="br0">&#40;</span><span class="nu0">200</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">checkElement</span><span class="br0">&#40;</span><span class="st_h">'input[name$=&quot;[title]&quot;]'</span><span class="sy0">,</span> <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$languages</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.2 - I18n forms are validated'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'news'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'en'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'toto'</span><span class="sy0">,</span>
      <span class="st_h">'body'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">isError</span><span class="br0">&#40;</span><span class="st_h">'en[body]'</span><span class="sy0">,</span> <span class="st_h">'required'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.3 - Empty forms are validated'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'news'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'en'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span>
      <span class="st_h">'body'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.4 - Translations are updated'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'news'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'fr'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'toto tutu tata'</span><span class="sy0">,</span>
      <span class="st_h">'body'</span> <span class="sy0">=&gt;</span> <span class="st_h">'riri fifi loulou'</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'NewsTranslation'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$news</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'lang'</span> <span class="sy0">=&gt;</span> <span class="st_h">'fr'</span><span class="sy0">,</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'toto tutu tata'</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.5 - No empty translation is created'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'NewsTranslation'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$news</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'lang'</span> <span class="sy0">=&gt;</span> <span class="st_h">'en'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.6 - New translations can be added'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'news'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'en'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'toto tutu tata'</span><span class="sy0">,</span>
      <span class="st_h">'body'</span> <span class="sy0">=&gt;</span> <span class="st_h">'riri fifi loulou'</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'NewsTranslation'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$news</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'lang'</span> <span class="sy0">=&gt;</span> <span class="st_h">'en'</span><span class="sy0">,</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">'toto tutu tata'</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">info</span><span class="br0">&#40;</span><span class="st_h">'  2.7 - Existing translations can be deleted'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">get</span><span class="br0">&#40;</span><span class="re0">$editUrl</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">click</span><span class="br0">&#40;</span><span class="st_h">'Save'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'news'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
    <span class="st_h">'fr'</span> <span class="sy0">=&gt;</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'title'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span><span class="sy0">,</span>
      <span class="st_h">'body'</span> <span class="sy0">=&gt;</span> <span class="st_h">''</span>
    <span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st_h">'_with_csrf'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="br0">&#41;</span>
  <span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'form'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">hasErrors</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
&nbsp;
  <span class="me1">with</span><span class="br0">&#40;</span><span class="st_h">'doctrine'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
    <span class="me1">check</span><span class="br0">&#40;</span><span class="st_h">'NewsTranslation'</span><span class="sy0">,</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span>
      <span class="st_h">'id'</span> <span class="sy0">=&gt;</span> <span class="re0">$news</span><span class="sy0">-&gt;</span><span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span>
      <span class="st_h">'lang'</span> <span class="sy0">=&gt;</span> <span class="st_h">'fr'</span><span class="sy0">,</span>
    <span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw4">false</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span>
  <a href="http://www.php.net/end"><span class="kw3">end</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="sy0">;</span></pre></div></div>

<p>Here we are. Hope you find this helpful. I thought some kind of requirement would be pretty common, however, I didn&#8217;t find any directly related howto&#8217;s. If you can think of any other way to achieve this, please, let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miximum.fr/tutos/449-optional-translation-form-for-i18n-objects-with-symfony-and-doctrine/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>

