[Form] Fixed: FormTypeInterface::getParent() supports returning FormTypeInterface instances again
This commit is contained in:
parent
7a233bc7a6
commit
a38232ae0e
@ -80,16 +80,7 @@ class FormFactory implements FormFactoryInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($type instanceof FormTypeInterface) {
|
if ($type instanceof FormTypeInterface) {
|
||||||
// An unresolved type instance was passed. Type extensions
|
$type = $this->resolveType($type);
|
||||||
// are not supported for these. If you want to use type
|
|
||||||
// extensions, you should create form extensions or register
|
|
||||||
// your type in the Dependency Injection configuration instead.
|
|
||||||
$parentType = $type->getParent();
|
|
||||||
$type = $this->resolvedTypeFactory->createResolvedType(
|
|
||||||
$type,
|
|
||||||
array(),
|
|
||||||
$parentType ? $this->registry->getType($parentType) : null
|
|
||||||
);
|
|
||||||
} elseif (is_string($type)) {
|
} elseif (is_string($type)) {
|
||||||
$type = $this->registry->getType($type);
|
$type = $this->registry->getType($type);
|
||||||
} elseif (!$type instanceof ResolvedFormTypeInterface) {
|
} elseif (!$type instanceof ResolvedFormTypeInterface) {
|
||||||
@ -196,4 +187,32 @@ class FormFactory implements FormFactoryInterface
|
|||||||
{
|
{
|
||||||
return $this->registry->getType($name)->getInnerType();
|
return $this->registry->getType($name)->getInnerType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a type into a ResolvedFormTypeInterface implementation and connects
|
||||||
|
* it with its parent type.
|
||||||
|
*
|
||||||
|
* @param FormTypeInterface $type The type to resolve.
|
||||||
|
*
|
||||||
|
* @return ResolvedFormTypeInterface The resolved type.
|
||||||
|
*/
|
||||||
|
private function resolveType(FormTypeInterface $type)
|
||||||
|
{
|
||||||
|
$parentType = $type->getParent();
|
||||||
|
|
||||||
|
if ($parentType instanceof FormTypeInterface) {
|
||||||
|
$parentType = $this->resolveType($parentType);
|
||||||
|
} elseif (null !== $parentType) {
|
||||||
|
$parentType = $this->registry->getType($parentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->resolvedTypeFactory->createResolvedType(
|
||||||
|
$type,
|
||||||
|
// Type extensions are not supported for unregistered type instances,
|
||||||
|
// i.e. type instances that are passed to the FormFactory directly,
|
||||||
|
// nor for their parents, if getParent() also returns a type instance.
|
||||||
|
array(),
|
||||||
|
$parentType
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,27 +95,46 @@ class FormRegistry implements FormRegistryInterface
|
|||||||
throw new FormException(sprintf('Could not load type "%s"', $name));
|
throw new FormException(sprintf('Could not load type "%s"', $name));
|
||||||
}
|
}
|
||||||
|
|
||||||
$parentType = $type->getParent();
|
$this->resolveAndAddType($type);
|
||||||
$typeExtensions = array();
|
|
||||||
|
|
||||||
foreach ($this->extensions as $extension) {
|
|
||||||
/* @var FormExtensionInterface $extension */
|
|
||||||
$typeExtensions = array_merge(
|
|
||||||
$typeExtensions,
|
|
||||||
$extension->getTypeExtensions($name)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addType($this->resolvedTypeFactory->createResolvedType(
|
|
||||||
$type,
|
|
||||||
$typeExtensions,
|
|
||||||
$parentType ? $this->getType($parentType) : null
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->types[$name];
|
return $this->types[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a type into a ResolvedFormTypeInterface implementation and connects
|
||||||
|
* it with its parent type.
|
||||||
|
*
|
||||||
|
* @param FormTypeInterface $type The type to resolve.
|
||||||
|
*
|
||||||
|
* @return ResolvedFormTypeInterface The resolved type.
|
||||||
|
*/
|
||||||
|
private function resolveAndAddType(FormTypeInterface $type)
|
||||||
|
{
|
||||||
|
$parentType = $type->getParent();
|
||||||
|
|
||||||
|
if ($parentType instanceof FormTypeInterface) {
|
||||||
|
$this->resolveAndAddType($parentType);
|
||||||
|
$parentType = $parentType->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
$typeExtensions = array();
|
||||||
|
|
||||||
|
foreach ($this->extensions as $extension) {
|
||||||
|
/* @var FormExtensionInterface $extension */
|
||||||
|
$typeExtensions = array_merge(
|
||||||
|
$typeExtensions,
|
||||||
|
$extension->getTypeExtensions($type->getName())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addType($this->resolvedTypeFactory->createResolvedType(
|
||||||
|
$type,
|
||||||
|
$typeExtensions,
|
||||||
|
$parentType ? $this->getType($parentType) : null
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -78,7 +78,11 @@ interface FormTypeInterface
|
|||||||
/**
|
/**
|
||||||
* Returns the name of the parent type.
|
* Returns the name of the parent type.
|
||||||
*
|
*
|
||||||
* @return string|null The name of the parent type if any, null otherwise.
|
* You can also return a type instance from this method, although doing so
|
||||||
|
* is discouraged because it leads to a performance penalty. The support
|
||||||
|
* for returning type instances may be dropped from future releases.
|
||||||
|
*
|
||||||
|
* @return string|null|FormTypeInterface The name of the parent type if any, null otherwise.
|
||||||
*/
|
*/
|
||||||
public function getParent();
|
public function getParent();
|
||||||
|
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form\Tests\Fixtures;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormFactoryInterface;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
||||||
|
|
||||||
|
class FooSubTypeWithParentInstance extends AbstractType
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'foo_sub_type_parent_instance';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return new FooType();
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,8 @@ use Symfony\Component\Form\Tests\Fixtures\Author;
|
|||||||
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
|
use Symfony\Component\Form\Tests\Fixtures\AuthorType;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\TestExtension;
|
use Symfony\Component\Form\Tests\Fixtures\TestExtension;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooType;
|
use Symfony\Component\Form\Tests\Fixtures\FooType;
|
||||||
|
use Symfony\Component\Form\Tests\Fixtures\FooSubType;
|
||||||
|
use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
|
use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
|
use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
|
||||||
|
|
||||||
@ -139,7 +141,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testCreateNamedBuilderWithTypeInstance()
|
public function testCreateNamedBuilderWithTypeInstance()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
$type = $this->getMockType();
|
$type = new FooType();
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
$this->resolvedTypeFactory->expects($this->once())
|
$this->resolvedTypeFactory->expects($this->once())
|
||||||
@ -155,6 +157,56 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testCreateNamedBuilderWithTypeInstanceWithParentType()
|
||||||
|
{
|
||||||
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$type = new FooSubType();
|
||||||
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
$parentResolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
|
$this->registry->expects($this->once())
|
||||||
|
->method('getType')
|
||||||
|
->with('foo')
|
||||||
|
->will($this->returnValue($parentResolvedType));
|
||||||
|
|
||||||
|
$this->resolvedTypeFactory->expects($this->once())
|
||||||
|
->method('createResolvedType')
|
||||||
|
->with($type, array(), $parentResolvedType)
|
||||||
|
->will($this->returnValue($resolvedType));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('createBuilder')
|
||||||
|
->with($this->factory, 'name', $options)
|
||||||
|
->will($this->returnValue('BUILDER'));
|
||||||
|
|
||||||
|
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance()
|
||||||
|
{
|
||||||
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$type = new FooSubTypeWithParentInstance();
|
||||||
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
$parentResolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
|
$this->resolvedTypeFactory->expects($this->at(0))
|
||||||
|
->method('createResolvedType')
|
||||||
|
->with($type->getParent())
|
||||||
|
->will($this->returnValue($parentResolvedType));
|
||||||
|
|
||||||
|
$this->resolvedTypeFactory->expects($this->at(1))
|
||||||
|
->method('createResolvedType')
|
||||||
|
->with($type, array(), $parentResolvedType)
|
||||||
|
->will($this->returnValue($resolvedType));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('createBuilder')
|
||||||
|
->with($this->factory, 'name', $options)
|
||||||
|
->will($this->returnValue('BUILDER'));
|
||||||
|
|
||||||
|
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderWithResolvedTypeInstance()
|
public function testCreateNamedBuilderWithResolvedTypeInstance()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Form;
|
namespace Symfony\Component\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\Tests\Fixtures\TestExtension;
|
use Symfony\Component\Form\Tests\Fixtures\TestExtension;
|
||||||
|
use Symfony\Component\Form\Tests\Fixtures\FooSubTypeWithParentInstance;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooSubType;
|
use Symfony\Component\Form\Tests\Fixtures\FooSubType;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
|
use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
|
use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension;
|
||||||
@ -153,6 +154,35 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertSame($resolvedType, $this->registry->getType('foo_sub_type'));
|
$this->assertSame($resolvedType, $this->registry->getType('foo_sub_type'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetTypeConnectsParentIfGetParentReturnsInstance()
|
||||||
|
{
|
||||||
|
$type = new FooSubTypeWithParentInstance();
|
||||||
|
$parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
|
||||||
|
$this->extension1->addType($type);
|
||||||
|
|
||||||
|
$this->resolvedTypeFactory->expects($this->at(0))
|
||||||
|
->method('createResolvedType')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Form\Tests\Fixtures\FooType'))
|
||||||
|
->will($this->returnValue($parentResolvedType));
|
||||||
|
|
||||||
|
$this->resolvedTypeFactory->expects($this->at(1))
|
||||||
|
->method('createResolvedType')
|
||||||
|
->with($type, array(), $parentResolvedType)
|
||||||
|
->will($this->returnValue($resolvedType));
|
||||||
|
|
||||||
|
$parentResolvedType->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('foo'));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('foo_sub_type_parent_instance'));
|
||||||
|
|
||||||
|
$this->assertSame($resolvedType, $this->registry->getType('foo_sub_type_parent_instance'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException Symfony\Component\Form\Exception\FormException
|
* @expectedException Symfony\Component\Form\Exception\FormException
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user