[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:
parent
733290c112
commit
e4c21708ca
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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()
|
||||
|
@ -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');
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user