Ask your Symfony questions! Pay money and get answers fast! (more info)

Emded form with I18N Symfony

  • SOLVED

Hello,

I have this schema :

csResume:
actAs: [Timestampable]
columns:
id: { type: integer, primary: true, autoincrement: true }
user_id: { type: integer, notnull: true }
is_online: { type: boolean, notnull: true, default: false }
relations:
User:
class: sfGuardUser
type: one
foreignType: one
local: user_id
foreign: id
foreignAlias: Resume

csResumeEntry:
actAs:
Timestampable: ~
I18n:
fields: [title, description, location]
columns:
id: { type: integer, primary: true, autoincrement: true }
resume_id: { type: integer, notnull: true }
title: { type: string(128) }
description: { type: string }
location: { type: string(128) }
url: { type: string(256) }
started_at: { type: timestamp }
ended_at: { type: timestamp }
relations:
Resume:
class: csResume
type: one
foreignType: many
local: resume_id
foreign: id
foreignAlias: ResumeEntries


I need to do a form where you can in the same time :
- edit some resume entries
- add some resume entries

All these needs are done. But I have a problem when I add a new entry !
This is the error reported by Symfony :
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'id' cannot be null

I think... SF try to insert in translation table (cs_resume_entry_table) before insert the entity in table cs_resume_entry
You can see the wrong request :
at Doctrine_Connection->exec('INSERT INTO `cs_resume_entry_translation` (`id`, `lang`, `title`, `location`, `position_name`, `description`, `certificate_name`) VALUES (?, ?, ?, ?, ?, ?, ?)', array(null, 'en', '', '', '', '', ''))

Someone can help me please ?

Regards,
Joel

Answers (1)

2011-08-30

Ben answers:

I had this exact same error, and used used this class as my BaseFormDoctrine which works (although it's a bit of a hack!) If anybody has a better solution, I'd love to hear it!



<?php


abstract class BaseFormDoctrine extends sfFormDoctrine
{
protected $culture_array= array();
protected $i18nFormsIgnored = array();
protected $hasi18N = false;

public function setup()
{
parent::setup();
}

public function getCultures(){
return $this->culture_array;
}

protected function setupI18n(){
$cultures = CultureTable::getInstance()->getCultures()->toArray();
$culture_array = array();
$this->hasi18N = true;
foreach($cultures as $culture){
$culture_array[] = $culture['language_code'];
}
$this->embedI18n($culture_array);


$this->culture_array = $culture_array;
}

public function bind(array $taintedValues = null, array $taintedFiles = null) {


if($this->hasi18N)
{

$this->removeEmptyI18nForms($taintedValues, $taintedFiles);
}

parent::bind($taintedValues, $taintedFiles);
}

public function removeEmptyI18nForms(&$taintedValues, &$taintedFiles, $form_name = false)
{

$removed_array = array();
if($this->hasi18N)
{
foreach($this->culture_array as $culture)
{

if(isset($taintedValues[$culture]) && $this->isValueArrayEmpty($taintedValues[$culture]))
{

$this->i18nFormsIgnored[] = $culture;
unset($this[$culture]);
unset($taintedValues[$culture]);


if($form_name && isset($taintedFiles[$form_name]))
{
unset($taintedFiles[$form_name][$culture]);
}
else
{
unset($taintedFiles[$culture]);
}
$removed_array[] = $culture;
}
}
/* let's sort out the embedded forms as well */
foreach($this->getEmbeddedForms() as $key => $form){

if(!in_array($key, $this->culture_array))
{
if(method_exists($form, 'removeEmptyI18nForms')){
$form->removeEmptyI18nForms($taintedValues[$key], $taintedFiles[$key], $key);
}


}

}
}
if(is_array($taintedFiles)){
foreach ($taintedFiles as $key => $data)
{
if(!is_array($data)){
unset($taintedFiles[$key]);
}
}
}

return $removed_array;
}

protected function isValueArrayEmpty(array $form_values){

foreach($form_values as $key => $value){
if(!empty($value))
{
return false;
}
}
return true;
}

protected function doUpdateObject($values)
{

parent::doUpdateObject($values);
if($this->hasi18N)
{
foreach($this->i18nFormsIgnored as $culture)
{
unset($this->object->Translation[$culture]);
unset($values[$culture]);
}
}

}

public function saveEmbeddedForms($con = null, $forms = null)
{

/* this hack fixes what appears to be a bug in Doctrine that prevents nested embedded forms from working correctly. */

$this->getObject()->save();

parent::saveEmbeddedForms($con, $forms);

}


public function updateObjectEmbeddedForms($values, $forms = null)
{


if (null === $forms)
{
$forms = $this->embeddedForms;
}

foreach ($forms as $name => $form)
{
if (!isset($values[$name]) || !is_array($values[$name]))
{
continue;
}

if ($form instanceof sfFormObject)
{

/* this hack seems to fix bug resulting in doctrine not saving embedded forms correctly */

$this->getObject()->save();

$form->updateObject($values[$name]);

}
else
{
$this->updateObjectEmbeddedForms($values[$name], $form->getEmbeddedForms());
}
}

}


}



I was storing cultures in a table called "Culture", and would call
$this->setupI18n
in the configure method of relevant child form classes.