[Form] Adapted Form to create a deterministic property path by default

This commit is contained in:
Bernhard Schussek 2012-05-17 16:09:13 +02:00
parent 03f50588c2
commit 860dd1f7d8
23 changed files with 355 additions and 156 deletions

View File

@ -18,18 +18,6 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException;
class PropertyPathMapper implements DataMapperInterface
{
/**
* Stores the class that the data of this form must be instances of.
*
* @var string
*/
private $dataClass;
public function __construct($dataClass = null)
{
$this->dataClass = $dataClass;
}
/**
* {@inheritdoc}
*/
@ -40,10 +28,6 @@ class PropertyPathMapper implements DataMapperInterface
}
if (!empty($data)) {
if (null !== $this->dataClass && !$data instanceof $this->dataClass) {
throw new UnexpectedTypeException($data, $this->dataClass);
}
$iterator = new VirtualFormAwareIterator($forms);
$iterator = new \RecursiveIteratorIterator($iterator);
@ -59,7 +43,7 @@ class PropertyPathMapper implements DataMapperInterface
public function mapDataToForm($data, FormInterface $form)
{
if (!empty($data)) {
$propertyPath = $form->getAttribute('property_path');
$propertyPath = $form->getPropertyPath();
if (null !== $propertyPath) {
$propertyData = $propertyPath->getValue($data);
@ -91,7 +75,7 @@ class PropertyPathMapper implements DataMapperInterface
*/
public function mapFormToData(FormInterface $form, &$data)
{
$propertyPath = $form->getAttribute('property_path');
$propertyPath = $form->getPropertyPath();
if (null !== $propertyPath && $form->isSynchronized() && !$form->isDisabled()) {
// If the data is identical to the value in $data, we are

View File

@ -31,16 +31,6 @@ class FormType extends AbstractType
*/
public function buildForm(FormBuilder $builder, array $options)
{
if (null === $options['property_path']) {
$options['property_path'] = $builder->getName();
}
if (false === $options['property_path'] || '' === $options['property_path']) {
$options['property_path'] = null;
} else {
$options['property_path'] = new PropertyPath($options['property_path']);
}
if (!is_array($options['attr'])) {
throw new FormException('The "attr" option must be an "array".');
}
@ -54,9 +44,9 @@ class FormType extends AbstractType
->setDisabled($options['disabled'])
->setErrorBubbling($options['error_bubbling'])
->setEmptyData($options['empty_data'])
->setPropertyPath($options['property_path'])
->setAttribute('read_only', $options['read_only'])
->setAttribute('by_reference', $options['by_reference'])
->setAttribute('property_path', $options['property_path'])
->setAttribute('error_mapping', $options['error_mapping'])
->setAttribute('max_length', $options['max_length'])
->setAttribute('pattern', $options['pattern'])
@ -69,7 +59,7 @@ class FormType extends AbstractType
->setAttribute('virtual', $options['virtual'])
->setAttribute('single_control', $options['single_control'])
->setData($options['data'])
->setDataMapper(new PropertyPathMapper($options['data_class']))
->setDataMapper(new PropertyPathMapper())
->addEventSubscriber(new ValidationListener())
;
@ -112,7 +102,7 @@ class FormType extends AbstractType
}
$types = array();
foreach ($form->getTypes() as $type) {
foreach ($form->getConfig()->getTypes() as $type) {
$types[] = $type->getName();
}
@ -229,7 +219,7 @@ class FormType extends AbstractType
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $factory, new EventDispatcher(), $options['data_class']);
return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory);
}
/**

View File

@ -17,6 +17,7 @@ use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\AlreadyBoundException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -162,10 +163,33 @@ class Form implements \IteratorAggregate, FormInterface
return $this->config->getName();
}
/**
* {@inheritdoc}
*/
public function getPropertyPath()
{
if (!$this->hasParent() || null !== $this->config->getPropertyPath()) {
return $this->config->getPropertyPath();
}
if (null === $this->getName() || '' === $this->getName()) {
return null;
}
if (null === $this->getParent()->getConfig()->getDataClass()) {
return new PropertyPath('[' . $this->getName() . ']');
}
return new PropertyPath($this->getName());
}
/**
* Returns the types used by this form.
*
* @return array An array of FormTypeInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getTypes()} instead.
*/
public function getTypes()
{
@ -261,9 +285,9 @@ class Form implements \IteratorAggregate, FormInterface
/**
* Returns whether the form has an attribute with the given name.
*
* @param string $name The name of the attribute
* @param string $name The name of the attribute.
*
* @return Boolean
* @return Boolean Whether the attribute exists.
*/
public function hasAttribute($name)
{
@ -273,7 +297,9 @@ class Form implements \IteratorAggregate, FormInterface
/**
* Returns the value of the attributes with the given name.
*
* @param string $name The name of the attribute
* @param string $name The name of the attribute
*
* @return mixed The attribute value.
*/
public function getAttribute($name)
{
@ -310,6 +336,25 @@ class Form implements \IteratorAggregate, FormInterface
$normData = $this->appToNorm($appData);
$clientData = $this->normToClient($normData);
// Validate if client data matches data class (unless empty)
if (!empty($clientData)) {
// TESTME
$dataClass = $this->config->getDataClass();
if (null === $dataClass && is_object($clientData)) {
// TODO clarify error message: should not be transformed to object if data class is null
// possible solutions: set data class or change client transformers
throw new UnexpectedTypeException($clientData, 'scalar or array');
}
// TESTME
if (null !== $dataClass && !$clientData instanceof $dataClass) {
// TODO clarify error message: should be transformed to object if data class is set
// possible solutions: change data class or client transformers
throw new UnexpectedTypeException($clientData, $dataClass);
}
}
$this->appData = $appData;
$this->normData = $normData;
$this->clientData = $clientData;
@ -568,6 +613,9 @@ class Form implements \IteratorAggregate, FormInterface
* Returns whether errors bubble up to the parent.
*
* @return Boolean
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getErrorBubbling()} instead.
*/
public function getErrorBubbling()
{
@ -693,6 +741,9 @@ class Form implements \IteratorAggregate, FormInterface
* Returns the DataTransformers.
*
* @return array An array of DataTransformerInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getNormTransformers()} instead.
*/
public function getNormTransformers()
{
@ -703,6 +754,9 @@ class Form implements \IteratorAggregate, FormInterface
* Returns the DataTransformers.
*
* @return array An array of DataTransformerInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getClientTransformers()} instead.
*/
public function getClientTransformers()
{

View File

@ -31,11 +31,6 @@ class FormBuilder extends FormConfig
*/
private $factory;
/**
* @var string
*/
private $dataClass;
/**
* The children of the form builder.
*
@ -59,19 +54,18 @@ class FormBuilder extends FormConfig
private $parent;
/**
* Constructor.
* Creates a new form builder.
*
* @param string $name
* @param FormFactoryInterface $factory
* @param EventDispatcherInterface $dispatcher
* @param string $dataClass
* @param EventDispatcherInterface $dispatcher
* @param FormFactoryInterface $factory
*/
public function __construct($name, FormFactoryInterface $factory, EventDispatcherInterface $dispatcher, $dataClass = null)
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory)
{
parent::__construct($name, $dispatcher);
parent::__construct($name, $dataClass, $dispatcher);
$this->factory = $factory;
$this->dataClass = $dataClass;
}
/**
@ -140,7 +134,7 @@ class FormBuilder extends FormConfig
*/
public function create($name, $type = null, array $options = array())
{
if (null === $type && !$this->dataClass) {
if (null === $type && null === $this->getDataClass()) {
$type = 'text';
}
@ -148,7 +142,7 @@ class FormBuilder extends FormConfig
return $this->getFormFactory()->createNamedBuilder($type, $name, null, $options, $this);
}
return $this->getFormFactory()->createBuilderForProperty($this->dataClass, $name, null, $options, $this);
return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options, $this);
}
/**

View File

@ -33,6 +33,16 @@ class FormConfig implements FormConfigInterface
*/
private $name;
/**
* @var PropertyPath
*/
private $propertyPath;
/**
* @var Boolean
*/
private $mapped;
/**
* @var array
*/
@ -88,19 +98,34 @@ class FormConfig implements FormConfigInterface
*/
private $data;
/**
* @var string
*/
private $dataClass;
/**
* Creates an empty form configuration.
*
* @param string $name The form name.
* @param EventDispatcherInterface $dispatcher The event dispatcher.
* @param string $name The form name.
* @param string $dataClass The class of the form's data.
* @param EventDispatcherInterface $dispatcher The event dispatcher.
*
* @throws UnexpectedTypeException If the name is not a string.
* @throws \InvalidArgumentException If the data class is not a valid class or if
* the name contains invalid characters.
*/
public function __construct($name, EventDispatcherInterface $dispatcher)
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher)
{
$name = (string) $name;
self::validateName($name);
if (null !== $dataClass && !class_exists($dataClass)) {
throw new \InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
}
$this->name = $name;
$this->dataClass = $dataClass;
$this->dispatcher = $dispatcher;
}
@ -248,6 +273,22 @@ class FormConfig implements FormConfigInterface
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPropertyPath()
{
return $this->propertyPath;
}
/**
* {@inheritdoc}
*/
public function getMapped()
{
return $this->mapped;
}
/**
* {@inheritdoc}
*/
@ -354,6 +395,14 @@ class FormConfig implements FormConfigInterface
return $this->data;
}
/**
* {@inheritdoc}
*/
public function getDataClass()
{
return $this->dataClass;
}
/**
* Sets the value for an attribute.
*
@ -453,6 +502,41 @@ class FormConfig implements FormConfigInterface
return $this;
}
/**
* Sets the property path that the form should be mapped to.
*
* @param string|PropertyPath $propertyPath The property path or null if the path
* should be set automatically based on
* the form's name.
*
* @return self The configuration object.
*/
public function setPropertyPath($propertyPath)
{
if (null !== $propertyPath && !$propertyPath instanceof PropertyPath) {
$propertyPath = new PropertyPath($propertyPath);
}
$this->propertyPath = $propertyPath;
return $this;
}
/**
* Sets whether the form should be mapped to an element of its
* parent's data.
*
* @param Boolean $mapped Whether the form should be mapped.
*
* @return self The configuration object.
*/
public function setMapped($mapped)
{
$this->mapped = $mapped;
return $this;
}
/**
* Set the types.
*
@ -486,7 +570,7 @@ class FormConfig implements FormConfigInterface
*
* @param string $name The tested form name.
*
* @throws UnexpectedTypeException If the name is not a string.
* @throws UnexpectedTypeException If the name is not a string.
* @throws \InvalidArgumentException If the name contains invalid characters.
*/
static public function validateName($name)

View File

@ -32,6 +32,21 @@ interface FormConfigInterface
*/
function getName();
/**
* Returns the property path that the form should be mapped to.
*
* @return Util\PropertyPath The property path.
*/
function getPropertyPath();
/**
* Returns whether the form should be mapped to an element of its
* parent's data.
*
* @return Boolean Whether the form is mapped.
*/
function getMapped();
/**
* Returns the form types used to construct the form.
*
@ -128,4 +143,11 @@ interface FormConfigInterface
* @return mixed The initial form data.
*/
function getData();
/**
* Returns the class of the form data or null if the data is scalar or an array.
*
* @return string The data class or null.
*/
function getDataClass();
}

View File

@ -151,7 +151,6 @@ class FormFactory implements FormFactoryInterface
$builder = null;
$types = array();
$optionValues = array();
$knownOptions = array();
$optionsResolver = new OptionsResolver();

View File

@ -131,6 +131,13 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*/
function getExtraData();
/**
* Returns the form's configuration.
*
* @return FormConfigInterface The configuration.
*/
function getConfig();
/**
* Returns whether the field is bound.
*
@ -138,13 +145,6 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*/
function isBound();
/**
* Returns the supported types.
*
* @return array An array of FormTypeInterface
*/
function getTypes();
/**
* Returns the name by which the form is identified in forms.
*
@ -152,6 +152,13 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
*/
function getName();
/**
* Returns the property path that the form is mapped to.
*
* @return Util\PropertyPath The property path.
*/
function getPropertyPath();
/**
* Adds an error to this form.
*

View File

@ -31,6 +31,16 @@ class ImmutableFormConfig implements FormConfigInterface
*/
private $name;
/**
* @var PropertyPath
*/
private $propertyPath;
/**
* @var Boolean
*/
private $mapped;
/**
* @var array
*/
@ -86,6 +96,11 @@ class ImmutableFormConfig implements FormConfigInterface
*/
private $data;
/**
* @var string
*/
private $dataClass;
/**
* Creates an immutable copy of a given configuration.
*
@ -95,6 +110,8 @@ class ImmutableFormConfig implements FormConfigInterface
{
$this->dispatcher = $config->getEventDispatcher();
$this->name = $config->getName();
$this->propertyPath = $config->getPropertyPath();
$this->mapped = $config->getMapped();
$this->types = $config->getTypes();
$this->clientTransformers = $config->getClientTransformers();
$this->normTransformers = $config->getNormTransformers();
@ -104,8 +121,9 @@ class ImmutableFormConfig implements FormConfigInterface
$this->disabled = $config->getDisabled();
$this->errorBubbling = $config->getErrorBubbling();
$this->emptyData = $config->getEmptyData();
$this->data = $config->getData();
$this->attributes = $config->getAttributes();
$this->data = $config->getData();
$this->dataClass = $config->getDataClass();
}
/**
@ -124,6 +142,22 @@ class ImmutableFormConfig implements FormConfigInterface
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPropertyPath()
{
return $this->propertyPath;
}
/**
* {@inheritdoc}
*/
public function getMapped()
{
return $this->mapped;
}
/**
* {@inheritdoc}
*/
@ -229,4 +263,12 @@ class ImmutableFormConfig implements FormConfigInterface
{
return $this->data;
}
/**
* {@inheritdoc}
*/
public function getDataClass()
{
return $this->dataClass;
}
}

View File

@ -74,9 +74,12 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase
->setMethods(array('foo'))
->getMockForAbstractClass();
$form->setAttribute('property_path', $propertyPath);
$form->setAttribute('by_reference', $byReference);
$form->expects($this->any())
->method('getPropertyPath')
->will($this->returnValue($propertyPath));
$form->expects($this->any())
->method('isSynchronized')
->will($this->returnValue($synchronized));

View File

@ -11,10 +11,17 @@
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
use Symfony\Component\Form\FormBuilder;
class MergeCollectionListenerArrayObjectTest extends MergeCollectionListenerTest
{
protected function getData(array $data)
{
return new \ArrayObject($data);
}
protected function getBuilder($name = 'name')
{
return new FormBuilder($name, '\ArrayObject', $this->dispatcher, $this->factory);
}
}

View File

@ -11,10 +11,17 @@
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
use Symfony\Component\Form\FormBuilder;
class MergeCollectionListenerArrayTest extends MergeCollectionListenerTest
{
protected function getData(array $data)
{
return $data;
}
protected function getBuilder($name = 'name')
{
return new FormBuilder($name, null, $this->dispatcher, $this->factory);
}
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
use Symfony\Component\Form\Tests\Fixtures\CustomArrayObject;
use Symfony\Component\Form\FormBuilder;
class MergeCollectionListenerCustomArrayObjectTest extends MergeCollectionListenerTest
{
@ -19,4 +20,9 @@ class MergeCollectionListenerCustomArrayObjectTest extends MergeCollectionListen
{
return new CustomArrayObject($data);
}
protected function getBuilder($name = 'name')
{
return new FormBuilder($name, 'Symfony\Component\Form\Tests\Fixtures\CustomArrayObject', $this->dispatcher, $this->factory);
}
}

View File

@ -17,9 +17,9 @@ use Symfony\Component\Form\FormBuilder;
abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase
{
private $dispatcher;
private $factory;
private $form;
protected $dispatcher;
protected $factory;
protected $form;
protected function setUp()
{
@ -39,10 +39,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase
$this->form = null;
}
protected function getBuilder($name = 'name')
{
return new FormBuilder($name, $this->factory, $this->dispatcher);
}
abstract protected function getBuilder($name = 'name');
protected function getForm($name = 'name', $propertyPath = null)
{

View File

@ -42,7 +42,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
protected function getBuilder($name = 'name')
{
return new FormBuilder($name, $this->factory, $this->dispatcher);
return new FormBuilder($name, null, $this->dispatcher, $this->factory);
}
protected function getForm($name = 'name')

View File

@ -51,41 +51,6 @@ class FormTest_AuthorWithoutRefSetter
class FormTypeTest extends TypeTestCase
{
public function testGetPropertyPathDefaultPath()
{
$form = $this->factory->createNamed('form', 'title');
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsZero()
{
$form = $this->factory->create('form', null, array('property_path' => '0'));
$this->assertEquals(new PropertyPath('0'), $form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsEmpty()
{
$form = $this->factory->create('form', null, array('property_path' => ''));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsFalse()
{
$form = $this->factory->create('form', null, array('property_path' => false));
$this->assertNull($form->getAttribute('property_path'));
}
public function testGetPropertyPathPathIsNull()
{
$form = $this->factory->createNamed('form', 'title', null, array('property_path' => null));
$this->assertEquals(new PropertyPath('title'), $form->getAttribute('property_path'));
}
public function testPassRequiredAsOption()
{
$form = $this->factory->create('form', null, array('required' => false));
@ -285,10 +250,9 @@ class FormTypeTest extends TypeTestCase
$this->assertEquals($author, $form->getData());
}
public function testBindWithEmptyDataDoesNotCreateObjectIfDataClassIsNull()
public function testBindWithEmptyDataCreatesArrayIfDataClassIsNull()
{
$form = $this->factory->create('form', null, array(
'data' => new Author(),
'data_class' => null,
'required' => false,
));
@ -365,6 +329,7 @@ class FormTypeTest extends TypeTestCase
$author = new Author();
$form = $this->factory->create('form', null, array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'empty_data' => $author,
));
$form->add($this->factory->createNamed('form', 'firstName'));
@ -430,10 +395,11 @@ class FormTypeTest extends TypeTestCase
{
$author = new FormTest_AuthorWithoutRefSetter(new Author());
$builder = $this->factory->createBuilder('form');
$builder->add('reference', 'form');
$builder = $this->factory->createBuilder('form', $author);
$builder->add('reference', 'form', array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
));
$builder->get('reference')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
$form->bind(array(
@ -452,10 +418,11 @@ class FormTypeTest extends TypeTestCase
$author = new FormTest_AuthorWithoutRefSetter(null);
$newReference = new Author();
$builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form');
$builder = $this->factory->createBuilder('form', $author);
$builder->add('referenceCopy', 'form', array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
));
$builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
$form['referenceCopy']->setData($newReference); // new author object
@ -474,17 +441,19 @@ class FormTypeTest extends TypeTestCase
{
$author = new FormTest_AuthorWithoutRefSetter(new Author());
$builder = $this->factory->createBuilder('form');
$builder->add('referenceCopy', 'form', array('by_reference' => false));
$builder = $this->factory->createBuilder('form', $author);
$builder->add('referenceCopy', 'form', array(
'data_class' => 'Symfony\Component\Form\Tests\Fixtures\Author',
'by_reference' => false
));
$builder->get('referenceCopy')->add('firstName', 'form');
$builder->setData($author);
$form = $builder->getForm();
$form->bind(array(
// referenceCopy has a getter that returns a copy
// referenceCopy has a getter that returns a copy
'referenceCopy' => array(
'firstName' => 'Foo',
)
)
));
// firstName can only be updated if setReferenceCopy() was called
@ -495,16 +464,14 @@ class FormTypeTest extends TypeTestCase
{
$author = new FormTest_AuthorWithoutRefSetter('scalar');
$builder = $this->factory->createBuilder('form');
$builder = $this->factory->createBuilder('form', $author);
$builder->add('referenceCopy', 'form');
$builder->get('referenceCopy')->appendClientTransformer(new CallbackTransformer(
function () {},
function ($value) { // reverseTransform
return 'foobar';
}
function () {},
function ($value) { // reverseTransform
return 'foobar';
}
));
$builder->setData($author);
$form = $builder->getForm();
$form->bind(array(
@ -525,11 +492,10 @@ class FormTypeTest extends TypeTestCase
$builder->setData($author);
$builder->add('referenceCopy', 'form');
$builder->get('referenceCopy')->appendClientTransformer(new CallbackTransformer(
function () {},
function ($value) use ($ref2) { // reverseTransform
return $ref2;
}
function () {},
function ($value) use ($ref2) { // reverseTransform
return $ref2;
}
));
$form = $builder->getForm();

View File

@ -18,10 +18,19 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
abstract class TypeTestCase extends \PHPUnit_Framework_TestCase
{
/**
* @var FormFactory
*/
protected $factory;
/**
* @var FormBuilder
*/
protected $builder;
/**
* @var EventDispatcher
*/
protected $dispatcher;
protected function setUp()
@ -32,7 +41,7 @@ abstract class TypeTestCase extends \PHPUnit_Framework_TestCase
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->factory = new FormFactory($this->getExtensions());
$this->builder = new FormBuilder(null, $this->factory, $this->dispatcher);
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
}
protected function tearDown()

View File

@ -88,9 +88,9 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
return new FormError($this->message, $this->params);
}
protected function getBuilder($name = 'name', $propertyPath = null)
protected function getBuilder($name = 'name', $propertyPath = null, $dataClass = null)
{
$builder = new FormBuilder($name, $this->factory, $this->dispatcher);
$builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory);
$builder->setAttribute('property_path', new PropertyPath($propertyPath ?: $name));
$builder->setAttribute('error_mapping', array());
$builder->setErrorBubbling(false);
@ -98,9 +98,9 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
return $builder;
}
protected function getForm($name = 'name', $propertyPath = null)
protected function getForm($name = 'name', $propertyPath = null, $dataClass = null)
{
return $this->getBuilder($name, $propertyPath)->getForm();
return $this->getBuilder($name, $propertyPath, $dataClass)->getForm();
}
protected function getMockForm()
@ -608,7 +608,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass');
$form = $this->getBuilder()
$form = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', array('group1', 'group2'))
->getForm();
@ -629,7 +629,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass');
$form = $this->getBuilder()
$form = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', array($this, 'getValidationGroups'))
->getForm();
@ -650,7 +650,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext();
$graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass');
$form = $this->getBuilder()
$form = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', function(FormInterface $form){
return array('group1', 'group2');
})
@ -677,7 +677,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$parent = $this->getBuilder()
->setAttribute('validation_groups', 'group')
->getForm();
$child = $this->getBuilder()
$child = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', null)
->getForm();
$parent->add($child);
@ -700,7 +700,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$parent = $this->getBuilder()
->setAttribute('validation_groups', array($this, 'getValidationGroups'))
->getForm();
$child = $this->getBuilder()
$child = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', null)
->getForm();
$parent->add($child);
@ -728,7 +728,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
return array('group1', 'group2');
})
->getForm();
$child = $this->getBuilder()
$child = $this->getBuilder('name', null, '\stdClass')
->setAttribute('validation_groups', null)
->getForm();
$parent->add($child);
@ -750,7 +750,7 @@ class DelegatingValidationListenerTest extends \PHPUnit_Framework_TestCase
$context = $this->getExecutionContext('foo.bar');
$graphWalker = $context->getGraphWalker();
$object = $this->getMock('\stdClass');
$form = $this->getForm();
$form = $this->getForm('name', null, '\stdClass');
$graphWalker->expects($this->once())
->method('walkReference')

View File

@ -31,7 +31,7 @@ class FooType extends AbstractType
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $factory, new EventDispatcher());
return new FormBuilder($name, null, new EventDispatcher(), $factory);
}
public function getDefaultOptions()

View File

@ -25,7 +25,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
{
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
$this->builder = new FormBuilder('name', $this->factory, $this->dispatcher);
$this->builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
}
protected function tearDown()
@ -60,7 +60,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
public function testAddWithGuessFluent()
{
$this->builder = new FormBuilder('name', $this->factory, $this->dispatcher, 'stdClass');
$this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
$builder = $this->builder->add('foo');
$this->assertSame($builder, $this->builder);
}
@ -83,7 +83,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
$this->factory->expects($this->once())
->method('createNamedBuilder')
->with('text', 'foo')
->will($this->returnValue(new FormBuilder('foo', $this->factory, $this->dispatcher)));
->will($this->returnValue(new FormBuilder('foo', null, $this->dispatcher, $this->factory)));
$this->assertCount(0, $this->builder->all());
$this->assertFalse($this->builder->has('foo'));
@ -159,7 +159,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
->with('stdClass', $expectedName, null, $expectedOptions)
->will($this->returnValue($this->getFormBuilder()));
$this->builder = new FormBuilder('name', $this->factory, $this->dispatcher, 'stdClass');
$this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
$this->builder->add($expectedName, null, $expectedOptions);
$builder = $this->builder->get($expectedName);
@ -173,14 +173,14 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
public function testGetParentForAddedBuilder()
{
$builder = new FormBuilder('name', $this->factory, $this->dispatcher);
$builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
$this->builder->add($builder);
$this->assertSame($this->builder, $builder->getParent());
}
public function testGetParentForRemovedBuilder()
{
$builder = new FormBuilder('name', $this->factory, $this->dispatcher);
$builder = new FormBuilder('name', null, $this->dispatcher, $this->factory);
$this->builder->add($builder);
$this->builder->remove('name');
$this->assertNull($builder->getParent());
@ -188,7 +188,7 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase
public function testGetParentForCreatedBuilder()
{
$this->builder = new FormBuilder('name', $this->factory, $this->dispatcher, 'stdClass');
$this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory);
$this->factory
->expects($this->once())
->method('createNamedBuilder')

View File

@ -64,7 +64,7 @@ class FormConfigTest extends \PHPUnit_Framework_TestCase
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
try {
new FormConfig($name, $dispatcher);
new FormConfig($name, null, $dispatcher);
if (!$accepted) {
$this->fail(sprintf('The value "%s" should not be accepted', $name));
}

View File

@ -598,7 +598,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->extension1->addType($type);
$parentBuilder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder')
->setConstructorArgs(array('name', $this->factory, $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface')))
->setConstructorArgs(array('name', null, $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'), $this->factory))
->getMock()
;

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\FormConfig;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormBuilder;
@ -61,7 +62,7 @@ class FormTest extends \PHPUnit_Framework_TestCase
'foo' => 'bar',
));
$config = new FormConfig('name', $this->dispatcher);
$config = new FormConfig('name', null, $this->dispatcher);
$config->appendClientTransformer($client);
$config->appendNormTransformer($norm);
$form = new Form($config);
@ -1201,14 +1202,41 @@ class FormTest extends \PHPUnit_Framework_TestCase
*/
public function testFormCannotHaveEmptyNameNotInRootLevel()
{
$parent = $this->getBuilder()
$this->getBuilder()
->add($this->getBuilder(''))
->getForm();
}
protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null)
public function testGetPropertyPathReturnsConfiguredPath()
{
return new FormBuilder($name, $this->factory, $dispatcher ?: $this->dispatcher);
$form = $this->getBuilder()->setPropertyPath('address.street')->getForm();
$this->assertEquals(new PropertyPath('address.street'), $form->getPropertyPath());
}
// see https://github.com/symfony/symfony/issues/3903
public function testGetPropertyPathDefaultsToNameIfParentHasDataClass()
{
$parent = $this->getBuilder(null, null, 'stdClass')->getForm();
$form = $this->getBuilder('name')->getForm();
$parent->add($form);
$this->assertEquals(new PropertyPath('name'), $form->getPropertyPath());
}
// see https://github.com/symfony/symfony/issues/3903
public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull()
{
$parent = $this->getBuilder()->getForm();
$form = $this->getBuilder('name')->getForm();
$parent->add($form);
$this->assertEquals(new PropertyPath('[name]'), $form->getPropertyPath());
}
protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null)
{
return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory);
}
protected function getMockForm($name = 'name')