[Form] Separated value transformers from normalization transformers.

Fields can now easier support different data types in their underlying object.
These datatypes can be normalized to a single datatype using a normalization
transformer. The normalized value can then be transformed to the user's
representation with the value transformer (better name required?).
This commit is contained in:
Bernhard Schussek 2010-10-21 21:18:27 +02:00 committed by Fabien Potencier
parent 733290c112
commit e4c21708ca
8 changed files with 300 additions and 118 deletions

View File

@ -99,50 +99,50 @@ class DateField extends HybridField
$this->initFormatter();
$transformers = array();
if ($this->getOption('type') === self::STRING) {
$transformers[] = new ReversedTransformer(new DateTimeToStringTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'format' => 'Y-m-d',
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToStringTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'format' => 'Y-m-d',
))
));
} else if ($this->getOption('type') === self::TIMESTAMP) {
$transformers[] = new ReversedTransformer(new DateTimeToTimestampTransformer(array(
'output_timezone' => $this->getOption('data_timezone'),
'input_timezone' => $this->getOption('data_timezone'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToTimestampTransformer(array(
'output_timezone' => $this->getOption('data_timezone'),
'input_timezone' => $this->getOption('data_timezone'),
))
));
} else if ($this->getOption('type') === self::RAW) {
$transformers[] = new ReversedTransformer(new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'fields' => array('year', 'month', 'day'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'fields' => array('year', 'month', 'day'),
))
));
}
if ($this->getOption('widget') === self::INPUT) {
$transformers[] = new DateTimeToLocalizedStringTransformer(array(
$this->setValueTransformer(new DateTimeToLocalizedStringTransformer(array(
'date_format' => $this->getOption('format'),
'time_format' => DateTimeToLocalizedStringTransformer::NONE,
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('user_timezone'),
));
)));
$this->setFieldMode(self::FIELD);
} else {
$transformers[] = new DateTimeToArrayTransformer(array(
$this->setValueTransformer(new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('user_timezone'),
));
)));
$this->setFieldMode(self::GROUP);
$this->addChoiceFields();
}
if (count($transformers) > 0) {
$this->setValueTransformer(new ValueTransformerChain($transformers));
}
}
/**

View File

@ -85,23 +85,25 @@ class DateTimeField extends FieldGroup
$transformers = array();
if ($this->getOption('type') == self::STRING) {
$transformers[] = new ReversedTransformer(new DateTimeToStringTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToStringTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
))
));
} else if ($this->getOption('type') == self::TIMESTAMP) {
$transformers[] = new ReversedTransformer(new DateTimeToTimestampTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToTimestampTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
))
));
}
$transformers[] = new DateTimeToArrayTransformer(array(
$this->setValueTransformer(new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('user_timezone'),
));
$this->setValueTransformer(new ValueTransformerChain($transformers));
)));
}
/**

View File

@ -14,6 +14,38 @@ namespace Symfony\Component\Form;
use Symfony\Component\Form\ValueTransformer\ValueTransformerInterface;
use Symfony\Component\Form\ValueTransformer\TransformationFailedException;
/**
* Base class for form fields
*
* To implement your own form fields, you need to have a thorough understanding
* of the data flow within a form field. A form field stores its data in three
* different representations:
*
* (1) the format required by the form's object
* (2) a normalized format for internal processing
* (3) the format used for display
*
* A date field, for example, may store a date as "Y-m-d" string (1) in the
* object. To facilitate processing in the field, this value is normalized
* to a DateTime object (2). In the HTML representation of your form, a
* localized string (3) is presented to and modified by the user.
*
* In most cases, format (1) and format (2) will be the same. For example,
* a checkbox field uses a boolean value both for internal processing as for
* storage in the object. In these cases you simply need to set a value
* transformer to convert between formats (2) and (3). You can do this by
* calling setValueTransformer() in the configure() method.
*
* In some cases though it makes sense to make format (1) configurable. To
* demonstrate this, let's extend our above date field to store the value
* either as "Y-m-d" string or as timestamp. Internally we still want to
* use a DateTime object for processing. To convert the data from string/integer
* to DateTime you can set a normalization transformer by calling
* setNormalizationTransformer() in configure(). The normalized data is then
* converted to the displayed data as described before.
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
abstract class Field extends Configurable implements FieldInterface
{
protected $taintedData = null;
@ -25,7 +57,9 @@ abstract class Field extends Configurable implements FieldInterface
private $bound = false;
private $required = null;
private $data = null;
private $normalizedData = null;
private $transformedData = null;
private $normalizationTransformer = null;
private $valueTransformer = null;
private $propertyPath = null;
@ -44,7 +78,8 @@ abstract class Field extends Configurable implements FieldInterface
parent::__construct($options);
$this->transformedData = $this->transform($this->data);
$this->normalizedData = $this->normalize($this->data);
$this->transformedData = $this->transform($this->normalizedData);
$this->required = $this->getOption('required');
$this->setPropertyPath($this->getOption('property_path'));
@ -209,7 +244,8 @@ abstract class Field extends Configurable implements FieldInterface
public function setData($data)
{
$this->data = $data;
$this->transformedData = $this->transform($data);
$this->normalizedData = $this->normalize($data);
$this->transformedData = $this->transform($this->normalizedData);
}
/**
@ -230,8 +266,9 @@ abstract class Field extends Configurable implements FieldInterface
}
try {
$this->data = $this->processData($this->reverseTransform($this->transformedData));
$this->transformedData = $this->transform($this->data);
$this->normalizedData = $this->processData($this->reverseTransform($this->transformedData));
$this->data = $this->denormalize($this->normalizedData);
$this->transformedData = $this->transform($this->normalizedData);
} catch (TransformationFailedException $e) {
// TODO better text
// TESTME
@ -267,6 +304,11 @@ abstract class Field extends Configurable implements FieldInterface
return $this->data;
}
protected function getNormalizedData()
{
return $this->normalizedData;
}
/**
* Adds an error to the field.
*
@ -350,7 +392,29 @@ abstract class Field extends Configurable implements FieldInterface
*
* @param ValueTransformerInterface $valueTransformer
*/
public function setValueTransformer(ValueTransformerInterface $valueTransformer)
protected function setNormalizationTransformer(ValueTransformerInterface $normalizationTransformer)
{
$this->injectLocale($normalizationTransformer);
$this->normalizationTransformer = $normalizationTransformer;
}
/**
* Returns the ValueTransformer.
*
* @return ValueTransformerInterface
*/
protected function getNormalizationTransformer()
{
return $this->normalizationTransformer;
}
/**
* Sets the ValueTransformer.
*
* @param ValueTransformerInterface $valueTransformer
*/
protected function setValueTransformer(ValueTransformerInterface $valueTransformer)
{
$this->injectLocale($valueTransformer);
@ -362,11 +426,41 @@ abstract class Field extends Configurable implements FieldInterface
*
* @return ValueTransformerInterface
*/
public function getValueTransformer()
protected function getValueTransformer()
{
return $this->valueTransformer;
}
/**
* Normalizes the value if a normalization transformer is set
*
* @param mixed $value The value to transform
* @return string
*/
protected function normalize($value)
{
if (null === $this->normalizationTransformer) {
return $value;
} else {
return $this->normalizationTransformer->transform($value);
}
}
/**
* Reverse transforms a value if a normalization transformer is set.
*
* @param string $value The value to reverse transform
* @return mixed
*/
protected function denormalize($value)
{
if (null === $this->normalizationTransformer) {
return $value;
} else {
return $this->normalizationTransformer->reverseTransform($value, $this->data);
}
}
/**
* Transforms the value if a value transformer is set.
*

View File

@ -84,34 +84,38 @@ class TimeField extends FieldGroup
}
if ($this->getOption('type') == self::STRING) {
$transformers[] = new ReversedTransformer(new DateTimeToStringTransformer(array(
'format' => 'H:i:s',
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToStringTransformer(array(
'format' => 'H:i:s',
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
))
));
} else if ($this->getOption('type') == self::TIMESTAMP) {
$transformers[] = new ReversedTransformer(new DateTimeToTimestampTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToTimestampTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
))
));
} else if ($this->getOption('type') === self::RAW) {
$transformers[] = new ReversedTransformer(new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'fields' => $fields,
)));
$this->setNormalizationTransformer(new ReversedTransformer(
new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('data_timezone'),
'fields' => $fields,
))
));
}
$transformers[] = new DateTimeToArrayTransformer(array(
$this->setValueTransformer(new DateTimeToArrayTransformer(array(
'input_timezone' => $this->getOption('data_timezone'),
'output_timezone' => $this->getOption('user_timezone'),
// if the field is rendered as choice field, the values should be trimmed
// of trailing zeros to render the selected choices correctly
'pad' => $this->getOption('widget') == self::INPUT,
'fields' => $fields,
));
$this->setValueTransformer(new ValueTransformerChain($transformers));
)));
}
public function isField()

View File

@ -4,6 +4,7 @@ namespace Symfony\Tests\Component\Form;
require_once __DIR__ . '/Fixtures/Author.php';
require_once __DIR__ . '/Fixtures/TestField.php';
require_once __DIR__ . '/Fixtures/TestFieldGroup.php';
use Symfony\Component\Form\Field;
use Symfony\Component\Form\FieldInterface;
@ -11,9 +12,10 @@ use Symfony\Component\Form\FieldGroup;
use Symfony\Component\Form\PropertyPath;
use Symfony\Tests\Component\Form\Fixtures\Author;
use Symfony\Tests\Component\Form\Fixtures\TestField;
use Symfony\Tests\Component\Form\Fixtures\TestFieldGroup;
abstract class FieldGroupTest_Field implements FieldInterface
abstract class FieldGroupTest_Field extends TestField
{
public $locales = array();
@ -28,7 +30,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
{
public function testSupportsArrayAccess()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createMockField('firstName'));
$this->assertEquals($group->get('firstName'), $group['firstName']);
$this->assertTrue(isset($group['firstName']));
@ -36,7 +38,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testSupportsUnset()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createMockField('firstName'));
unset($group['firstName']);
$this->assertFalse(isset($group['firstName']));
@ -44,14 +46,14 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testDoesNotSupportAddingFields()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$this->setExpectedException('LogicException');
$group[] = $this->createMockField('lastName');
}
public function testSupportsCountable()
{
$group = new FieldGroup('group');
$group = new TestFieldGroup('group');
$group->add($this->createMockField('firstName'));
$group->add($this->createMockField('lastName'));
$this->assertEquals(2, count($group));
@ -62,7 +64,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testSupportsIterable()
{
$group = new FieldGroup('group');
$group = new TestFieldGroup('group');
$group->add($field1 = $this->createMockField('field1'));
$group->add($field2 = $this->createMockField('field2'));
$group->add($field3 = $this->createMockField('field3'));
@ -78,7 +80,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testIsBound()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$this->assertFalse($group->isBound());
$group->bind(array('firstName' => 'Bernhard'));
$this->assertTrue($group->isBound());
@ -86,7 +88,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testValidIfAllFieldsAreValid()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createValidMockField('firstName'));
$group->add($this->createValidMockField('lastName'));
@ -97,7 +99,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testInvalidIfFieldIsInvalid()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createInvalidMockField('firstName'));
$group->add($this->createValidMockField('lastName'));
@ -108,7 +110,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testInvalidIfBoundWithExtraFields()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createValidMockField('firstName'));
$group->add($this->createValidMockField('lastName'));
@ -124,7 +126,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('bind')
->with($this->equalTo('Bernhard'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$group->bind(array('firstName' => 'Bernhard'));
@ -137,7 +139,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('bind')
->with($this->equalTo(null));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$group->bind(array());
@ -150,7 +152,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('addError')
->with($this->equalTo('Message'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('fields[firstName].data');
@ -165,8 +167,8 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('addError')
->with($this->equalTo('Message'));
$group = new FieldGroup('author');
$innerGroup = new FieldGroup('names');
$group = new TestFieldGroup('author');
$innerGroup = new TestFieldGroup('names');
$innerGroup->add($field);
$group->add($innerGroup);
@ -181,7 +183,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
$field->expects($this->never())
->method('addError');
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('fields[bar].data');
@ -200,7 +202,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
$field->expects($this->never())
->method('addError');
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('fields[firstName].data');
@ -224,7 +226,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('addError')
->with($this->equalTo('Message'), array(), $this->equalTo($expectedPathIterator), $this->equalTo(FieldGroup::DATA_ERROR));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('firstName');
@ -241,7 +243,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
$field->expects($this->never())
->method('addError');
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('bar');
@ -261,7 +263,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
$field->expects($this->never())
->method('addError');
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('firstName');
@ -284,7 +286,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('addError')
->with($this->equalTo('Message'), array(), $this->equalTo($expectedPathIterator), $this->equalTo(FieldGroup::DATA_ERROR));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$path = new PropertyPath('address.street');
@ -306,8 +308,8 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('addError')
->with($this->equalTo('Message'), array(), $this->equalTo($expectedPathIterator), $this->equalTo(FieldGroup::DATA_ERROR));
$group = new FieldGroup('author');
$group2 = new FieldGroup('anonymous', array('property_path' => null));
$group = new TestFieldGroup('author');
$group2 = new TestFieldGroup('anonymous', array('property_path' => null));
$group2->add($field);
$group->add($group2);
@ -318,7 +320,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testAddThrowsExceptionIfAlreadyBound()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createMockField('firstName'));
$group->bind(array('firstName' => 'Bernhard'));
@ -328,7 +330,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testAddSetsFieldParent()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$field = $this->createMockField('firstName');
$field->expects($this->once())
@ -341,7 +343,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testRemoveUnsetsFieldParent()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$field = $this->createMockField('firstName');
$field->expects($this->exactly(2))
@ -354,10 +356,10 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testMergeAddsFieldsFromAnotherGroup()
{
$group1 = new FieldGroup('author');
$group1 = new TestFieldGroup('author');
$group1->add($field1 = new TestField('firstName'));
$group2 = new FieldGroup('publisher');
$group2 = new TestFieldGroup('publisher');
$group2->add($field2 = new TestField('lastName'));
$group1->merge($group2);
@ -368,8 +370,8 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testMergeThrowsExceptionIfOtherGroupAlreadyBound()
{
$group1 = new FieldGroup('author');
$group2 = new FieldGroup('publisher');
$group1 = new TestFieldGroup('author');
$group2 = new TestFieldGroup('publisher');
$group2->add($this->createMockField('firstName'));
$group2->bind(array('firstName' => 'Bernhard'));
@ -385,7 +387,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
// the authors should differ to make sure the test works
$transformedAuthor->firstName = 'Foo';
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$transformer = $this->createMockTransformer();
$transformer->expects($this->once())
@ -409,7 +411,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testAddDoesNotUpdateFieldsWithEmptyPropertyPath()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->setData(new Author());
$field = $this->createMockField('firstName');
@ -426,7 +428,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
{
$originalAuthor = new Author();
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$transformer = $this->createMockTransformer();
$transformer->expects($this->once())
@ -451,7 +453,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
// the authors should differ to make sure the test works
$transformedAuthor->firstName = 'Foo';
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$transformer = $this->createMockTransformer();
$transformer->expects($this->once())
@ -480,7 +482,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testSetDataThrowsAnExceptionIfArgumentIsNotObjectOrArray()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$this->setExpectedException('InvalidArgumentException');
@ -494,7 +496,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
// the authors should differ to make sure the test works
$transformedAuthor->firstName = 'Foo';
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$transformer = $this->createMockTransformer();
$transformer->expects($this->exactly(2))
@ -527,7 +529,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testGetDataReturnsObject()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$object = new \stdClass();
$group->setData($object);
$this->assertEquals($object, $group->getData());
@ -540,7 +542,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('getDisplayedData')
->will($this->returnValue('Bernhard'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$this->assertEquals(array('firstName' => 'Bernhard'), $group->getDisplayedData());
@ -548,7 +550,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testIsMultipartIfAnyFieldIsMultipart()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createMultipartMockField('firstName'));
$group->add($this->createNonMultipartMockField('lastName'));
@ -557,7 +559,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testIsNotMultipartIfNoFieldIsMultipart()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createNonMultipartMockField('firstName'));
$group->add($this->createNonMultipartMockField('lastName'));
@ -574,7 +576,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('setLocale')
->with($this->equalTo('de_DE'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->setLocale('de_DE');
$group->add($field);
}
@ -594,7 +596,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
// ->method('setLocale')
// ->with($this->equalTo('de_DE'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$group->setLocale('de_DE');
@ -603,7 +605,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
public function testSupportsClone()
{
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($this->createMockField('firstName'));
$clone = clone $group;
@ -619,7 +621,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
->method('getData')
->will($this->returnValue('Bernhard'));
$group = new FieldGroup('author');
$group = new TestFieldGroup('author');
$group->add($field);
$group->bind(array('firstName' => 'Bernhard'));
@ -652,7 +654,7 @@ class FieldGroupTest extends \PHPUnit_Framework_TestCase
*/
protected function getGroupWithBothVisibleAndHiddenField()
{
$group = new FieldGroup('testGroup');
$group = new TestFieldGroup('testGroup');
// add a visible field
$visibleField = $this->createMockField('visibleField');

View File

@ -237,30 +237,43 @@ class FieldTest extends \PHPUnit_Framework_TestCase
array('title')
);
// 1. The value is converted to a string and passed to the value transformer
$transformer = $this->createMockTransformer();
$transformer->expects($this->once())
// 1a. The value is converted to a string and passed to the value transformer
$valueTransformer = $this->createMockTransformer();
$valueTransformer->expects($this->once())
->method('reverseTransform')
->with($this->identicalTo('0'))
->will($this->returnValue('reverse[0]'));
$field->setValueTransformer($transformer);
$field->setValueTransformer($valueTransformer);
// 2. The output of the reverse transformation is passed to processData()
// The processed data is accessible through getNormalizedData()
$field->expects($this->once())
->method('processData')
->with($this->equalTo('reverse[0]'))
->will($this->returnValue('processed[reverse[0]]'));
// 3. The processed data is transformed again (for displayed data)
$transformer->expects($this->once())
// 3. The processed data is denormalized and then accessible through
// getData()
$normTransformer = $this->createMockTransformer();
$normTransformer->expects($this->once())
->method('reverseTransform')
->with($this->identicalTo('processed[reverse[0]]'))
->will($this->returnValue('denorm[processed[reverse[0]]]'));
$field->setNormalizationTransformer($normTransformer);
// 4. The processed data is transformed again and then accessible
// through getDisplayedData()
$valueTransformer->expects($this->once())
->method('transform')
->with($this->equalTo('processed[reverse[0]]'))
->will($this->returnValue('transform[processed[reverse[0]]]'));
$field->bind(0);
$this->assertEquals('processed[reverse[0]]', $field->getData());
$this->assertEquals('denorm[processed[reverse[0]]]', $field->getData());
$this->assertEquals('processed[reverse[0]]', $field->getNormalizedData());
$this->assertEquals('transform[processed[reverse[0]]]', $field->getDisplayedData());
}
@ -333,18 +346,27 @@ class FieldTest extends \PHPUnit_Framework_TestCase
public function testValuesAreTransformedCorrectly()
{
// The value is passed to the value transformer
$transformer = $this->createMockTransformer();
$transformer->expects($this->once())
// The value is first passed to the normalization transformer...
$normTransformer = $this->createMockTransformer();
$normTransformer->expects($this->once())
->method('transform')
->with($this->identicalTo(0))
->will($this->returnValue('transform[0]'));
->will($this->returnValue('norm[0]'));
$this->field->setValueTransformer($transformer);
// ...and then to the value transformer
$valueTransformer = $this->createMockTransformer();
$valueTransformer->expects($this->once())
->method('transform')
->with($this->identicalTo('norm[0]'))
->will($this->returnValue('transform[norm[0]]'));
$this->field->setNormalizationTransformer($normTransformer);
$this->field->setValueTransformer($valueTransformer);
$this->field->setData(0);
$this->assertEquals(0, $this->field->getData());
$this->assertEquals('transform[0]', $this->field->getDisplayedData());
$this->assertEquals('norm[0]', $this->field->getNormalizedData());
$this->assertEquals('transform[norm[0]]', $this->field->getDisplayedData());
}
public function testBoundValuesAreTrimmedBeforeTransforming()

View File

@ -3,10 +3,35 @@
namespace Symfony\Tests\Component\Form\Fixtures;
use Symfony\Component\Form\Field;
use Symfony\Component\Form\ValueTransformer\ValueTransformerInterface;
class TestField extends Field
{
public function render(array $attributes = array())
{
}
/**
* Expose method for testing purposes
*/
public function setNormalizationTransformer(ValueTransformerInterface $normalizationTransformer)
{
parent::setNormalizationTransformer($normalizationTransformer);
}
/**
* Expose method for testing purposes
*/
public function setValueTransformer(ValueTransformerInterface $valueTransformer)
{
parent::setValueTransformer($valueTransformer);
}
/**
* Expose method for testing purposes
*/
public function getNormalizedData()
{
return parent::getNormalizedData();
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Symfony\Tests\Component\Form\Fixtures;
use Symfony\Component\Form\FieldGroup;
use Symfony\Component\Form\ValueTransformer\ValueTransformerInterface;
class TestFieldGroup extends FieldGroup
{
/**
* Expose method for testing purposes
*/
public function setNormalizationTransformer(ValueTransformerInterface $normalizationTransformer)
{
parent::setNormalizationTransformer($normalizationTransformer);
}
/**
* Expose method for testing purposes
*/
public function setValueTransformer(ValueTransformerInterface $valueTransformer)
{
parent::setValueTransformer($valueTransformer);
}
/**
* Expose method for testing purposes
*/
public function getNormalizedData()
{
return parent::getNormalizedData();
}
}