Skip to content

Commit 2a155e0

Browse files
committed
Introduced recursive form embed (fix many embed form issues)
1 parent 98f4306 commit 2a155e0

File tree

9 files changed

+127
-142
lines changed

9 files changed

+127
-142
lines changed

lib/form/addon/sfFormObject.class.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
/**
1212
* Base class for forms that deal with a single object.
13-
*
13+
*
1414
* @package symfony
1515
* @subpackage form
1616
* @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
@@ -24,7 +24,7 @@ abstract class sfFormObject extends BaseForm
2424

2525
/**
2626
* Returns the current model name.
27-
*
27+
*
2828
* @return string
2929
*/
3030
abstract public function getModelName();
@@ -50,7 +50,7 @@ abstract protected function doUpdateObject($values);
5050
* Processes cleaned up values.
5151
*
5252
* @param array $values An array of values
53-
*
53+
*
5454
* @return array An array of cleaned up values
5555
*/
5656
abstract public function processValues($values);
@@ -108,7 +108,7 @@ public function bindAndSave($taintedValues, $taintedFiles = null, $con = null)
108108
* @return mixed The current saved object
109109
*
110110
* @see doSave()
111-
*
111+
*
112112
* @throws sfValidatorError If the form is not valid
113113
*/
114114
public function save($con = null)
@@ -123,10 +123,9 @@ public function save($con = null)
123123
$con = $this->getConnection();
124124
}
125125

126+
$con->beginTransaction();
126127
try
127128
{
128-
$con->beginTransaction();
129-
130129
$this->doSave($con);
131130

132131
$con->commit();

lib/form/sfForm.class.php

Lines changed: 73 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public function renderUsing($formatterName, $attributes = array())
154154
* @param boolean $recursive False will prevent hidden fields from embedded forms from rendering
155155
*
156156
* @return string
157-
*
157+
*
158158
* @see sfFormFieldSchema
159159
*/
160160
public function renderHiddenFields($recursive = true)
@@ -235,6 +235,11 @@ public function bind(array $taintedValues = null, array $taintedFiles = null)
235235
$this->values = array();
236236
$this->errorSchema = $e;
237237
}
238+
239+
if ($this->embeddedForms)
240+
{
241+
$this->bindEmbeddedForms($this->taintedValues, $this->taintedFiles);
242+
}
238243
}
239244

240245
/**
@@ -247,6 +252,38 @@ protected function doBind(array $values)
247252
$this->values = $this->validatorSchema->clean($values);
248253
}
249254

255+
/**
256+
* Bind embedded forms (recursivly)
257+
*
258+
* @param array $taintedValues
259+
* @param array $taintedFiles
260+
*/
261+
public function bindEmbeddedForms(array $taintedValues = null, array $taintedFiles = null)
262+
{
263+
foreach ($this->embeddedForms as $name => $form)
264+
{
265+
$form->bind(
266+
isset($taintedValues[$name]) ? $taintedValues[$name] : array(),
267+
isset($taintedFiles[$name]) ? $taintedFiles[$name] : array()
268+
);
269+
270+
$this->values[$name] = $form->getValues();
271+
272+
$widgetSchema = $form->getWidgetSchema();
273+
$decorator = $widgetSchema->getFormFormatter()->getDecoratorFormat();
274+
$this->widgetSchema[$name] = new sfWidgetFormSchemaDecorator($widgetSchema, $decorator);
275+
276+
// keep widgetSchema synchronized
277+
$form->setWidgetSchema($this->widgetSchema[$name]->getWidget());
278+
279+
// update errorSchema
280+
if ($form->hasErrors())
281+
{
282+
$this->errorSchema->addError($form->getErrorSchema(), $name);
283+
}
284+
}
285+
}
286+
250287
/**
251288
* Returns true if the form is bound to input values.
252289
*
@@ -257,6 +294,37 @@ public function isBound()
257294
return $this->isBound;
258295
}
259296

297+
/**
298+
* Directly updates form (and embbeded forms) values
299+
*
300+
* USE WITH CAUTION !!!!
301+
*
302+
* @param array $values
303+
*/
304+
public function updateValues(array $values)
305+
{
306+
$this->values = $values + $this->values;
307+
308+
$this->updateValuesEmbeddedForms($values);
309+
}
310+
311+
/**
312+
* Directly updates embedded form values
313+
*
314+
* @param array $values®
315+
*/
316+
public function updateValuesEmbeddedForms(array $values)
317+
{
318+
foreach ($this->embeddedForms as $name => $form)
319+
{
320+
if (isset($values[$name]))
321+
{
322+
$form->updateValues($values[$name]);
323+
$this->values[$name] = $form->getValues();
324+
}
325+
}
326+
}
327+
260328
/**
261329
* Returns the submitted tainted values.
262330
*
@@ -385,64 +453,10 @@ public function embedForm($name, sfForm $form, $decorator = null)
385453
$decorator = null === $decorator ? $widgetSchema->getFormFormatter()->getDecoratorFormat() : $decorator;
386454

387455
$this->widgetSchema[$name] = new sfWidgetFormSchemaDecorator($widgetSchema, $decorator);
388-
$this->validatorSchema[$name] = $form->getValidatorSchema();
389-
390-
$this->resetFormFields();
391-
}
392-
393-
/**
394-
* Embeds a sfForm into the current form n times.
395-
*
396-
* @param string $name The field name
397-
* @param sfForm $form A sfForm instance
398-
* @param integer $n The number of times to embed the form
399-
* @param string $decorator A HTML decorator for the main form around embedded forms
400-
* @param string $innerDecorator A HTML decorator for each embedded form
401-
* @param array $options Options for schema
402-
* @param array $attributes Attributes for schema
403-
* @param array $labels Labels for schema
404-
*/
405-
public function embedFormForEach($name, sfForm $form, $n, $decorator = null, $innerDecorator = null, $options = array(), $attributes = array(), $labels = array())
406-
{
407-
if (true === $this->isBound() || true === $form->isBound())
408-
{
409-
throw new LogicException('A bound form cannot be embedded');
410-
}
411-
412-
$this->embeddedForms[$name] = new sfForm();
413-
414-
$form = clone $form;
415-
unset($form[self::$CSRFFieldName]);
416-
417-
$widgetSchema = $form->getWidgetSchema();
418-
419-
// generate default values
420-
$defaults = array();
421-
for ($i = 0; $i < $n; $i++)
422-
{
423-
$defaults[$i] = $form->getDefaults();
456+
$this->validatorSchema[$name] = new sfValidatorPass();
424457

425-
$this->embeddedForms[$name]->embedForm($i, $form);
426-
}
427-
428-
$this->setDefault($name, $defaults);
429-
430-
$decorator = null === $decorator ? $widgetSchema->getFormFormatter()->getDecoratorFormat() : $decorator;
431-
$innerDecorator = null === $innerDecorator ? $widgetSchema->getFormFormatter()->getDecoratorFormat() : $innerDecorator;
432-
433-
$this->widgetSchema[$name] = new sfWidgetFormSchemaDecorator(new sfWidgetFormSchemaForEach(new sfWidgetFormSchemaDecorator($widgetSchema, $innerDecorator), $n, $options, $attributes), $decorator);
434-
$this->validatorSchema[$name] = new sfValidatorSchemaForEach($form->getValidatorSchema(), $n);
435-
436-
// generate labels
437-
for ($i = 0; $i < $n; $i++)
438-
{
439-
if (!isset($labels[$i]))
440-
{
441-
$labels[$i] = sprintf('%s (%s)', $this->widgetSchema->getFormFormatter()->generateLabelName($name), $i);
442-
}
443-
}
444-
445-
$this->widgetSchema[$name]->setLabels($labels);
458+
// keep widgetSchema synchronized
459+
$form->setWidgetSchema($this->widgetSchema[$name]->getWidget());
446460

447461
$this->resetFormFields();
448462
}
@@ -463,7 +477,7 @@ public function getEmbeddedForms()
463477
* @param string $name The name used to embed the form
464478
*
465479
* @return sfForm
466-
*
480+
*
467481
* @throws InvalidArgumentException If there is no form embedded with the supplied name
468482
*/
469483
public function getEmbeddedForm($name)

lib/plugins/sfDoctrinePlugin/data/generator/sfDoctrineForm/default/template/sfDoctrineFormGeneratedTemplate.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,32 +74,27 @@ public function updateDefaultsFromObject()
7474
<?php endforeach; ?>
7575
}
7676

77-
protected function doSave($con = null)
77+
public function updateObject($values = null)
7878
{
7979
<?php foreach ($this->getManyToManyRelations() as $relation): ?>
80-
$this->save<?php echo $relation['alias'] ?>List($con);
80+
$this->update<?php echo $relation['alias'] ?>List($values);
8181
<?php endforeach; ?>
8282

83-
parent::doSave($con);
83+
parent::updateObject($values);
8484
}
8585

8686
<?php foreach ($this->getManyToManyRelations() as $relation): ?>
87-
public function save<?php echo $relation['alias'] ?>List($con = null)
87+
public function update<?php echo $relation['alias'] ?>List($values = null)
8888
{
89-
if (!$this->isValid())
90-
{
91-
throw $this->getErrorSchema();
92-
}
93-
9489
if (!isset($this->widgetSchema['<?php echo $this->underscore($relation['alias']) ?>_list']))
9590
{
9691
// somebody has unset this widget
9792
return;
9893
}
9994

100-
if (null === $con)
95+
if (null === $values)
10196
{
102-
$con = $this->getConnection();
97+
$values = $this->values;
10398
}
10499

105100
$existing = $this->object-><?php echo $relation['alias']; ?>->getPrimaryKeys();

lib/validator/sfValidatorAnd.class.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function __construct($validators = null, $options = array(), $messages =
5353
{
5454
throw new InvalidArgumentException('sfValidatorAnd constructor takes a sfValidatorBase object, or a sfValidatorBase array.');
5555
}
56-
56+
5757
parent::__construct($options, $messages);
5858
}
5959

@@ -102,7 +102,7 @@ public function getValidators()
102102
protected function doClean($value)
103103
{
104104
$clean = $value;
105-
$errors = array();
105+
$errors = new sfValidatorErrorSchema($this);
106106
foreach ($this->validators as $validator)
107107
{
108108
try
@@ -111,7 +111,7 @@ protected function doClean($value)
111111
}
112112
catch (sfValidatorError $e)
113113
{
114-
$errors[] = $e;
114+
$errors->addError($e);
115115

116116
if ($this->getOption('halt_on_error'))
117117
{
@@ -120,14 +120,14 @@ protected function doClean($value)
120120
}
121121
}
122122

123-
if (count($errors))
123+
if ($errors->count())
124124
{
125125
if ($this->getMessage('invalid'))
126126
{
127127
throw new sfValidatorError($this, 'invalid', array('value' => $value));
128128
}
129129

130-
throw new sfValidatorErrorSchema($this, $errors);
130+
throw $errors;
131131
}
132132

133133
return $clean;

lib/validator/sfValidatorErrorSchema.class.php

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function __construct(sfValidatorBase $validator, $errors = array())
5454
*/
5555
public function addError(sfValidatorError $error, $name = null)
5656
{
57-
if (null === $name || is_integer($name))
57+
if (null === $name)
5858
{
5959
if ($error instanceof sfValidatorErrorSchema)
6060
{
@@ -66,35 +66,27 @@ public function addError(sfValidatorError $error, $name = null)
6666
$this->errors[] = $error;
6767
}
6868
}
69-
else
69+
elseif (isset($this->namedErrors[$name]))
7070
{
71-
if (!isset($this->namedErrors[$name]) && !$error instanceof sfValidatorErrorSchema)
71+
if (!$this->namedErrors[$name] instanceof sfValidatorErrorSchema)
7272
{
73-
$this->namedErrors[$name] = $error;
74-
$this->errors[$name] = $error;
75-
}
76-
else
77-
{
78-
if (!isset($this->namedErrors[$name]))
79-
{
80-
$this->namedErrors[$name] = new sfValidatorErrorSchema($error->getValidator());
81-
$this->errors[$name] = new sfValidatorErrorSchema($error->getValidator());
82-
}
83-
else if (!$this->namedErrors[$name] instanceof sfValidatorErrorSchema)
84-
{
85-
$current = $this->namedErrors[$name];
86-
$this->namedErrors[$name] = new sfValidatorErrorSchema($current->getValidator());
87-
$this->errors[$name] = new sfValidatorErrorSchema($current->getValidator());
88-
89-
$method = $current instanceof sfValidatorErrorSchema ? 'addErrors' : 'addError';
90-
$this->namedErrors[$name]->$method($current);
91-
$this->errors[$name]->$method($current);
92-
}
93-
94-
$method = $error instanceof sfValidatorErrorSchema ? 'addErrors' : 'addError';
95-
$this->namedErrors[$name]->$method($error);
96-
$this->errors[$name]->$method($error);
73+
$current = $this->namedErrors[$name];
74+
$this->namedErrors[$name] = new sfValidatorErrorSchema($current->getValidator());
75+
$this->errors[$name] = new sfValidatorErrorSchema($current->getValidator());
76+
77+
$method = $current instanceof sfValidatorErrorSchema ? 'addErrors' : 'addError';
78+
$this->namedErrors[$name]->$method($current);
79+
$this->errors[$name]->$method($current);
9780
}
81+
82+
$method = $error instanceof sfValidatorErrorSchema ? 'addErrors' : 'addError';
83+
$this->namedErrors[$name]->$method($error);
84+
$this->errors[$name]->$method($error);
85+
}
86+
else
87+
{
88+
$this->namedErrors[$name] = $error;
89+
$this->errors[$name] = $error;
9890
}
9991

10092
$this->updateCode();
@@ -128,7 +120,8 @@ public function addErrors($errors)
128120
{
129121
foreach ($errors as $name => $error)
130122
{
131-
$this->addError($error, $name);
123+
$this->addError($error, is_numeric($name) ? null : $name);
124+
132125
}
133126
}
134127

0 commit comments

Comments
 (0)