[Form] Fixed ResolvedFormType to really be replaceable

This commit is contained in:
Bernhard Schussek 2012-07-29 19:10:47 +02:00
parent 6b39ebc4f8
commit 8070e6997e
13 changed files with 342 additions and 123 deletions

View File

@ -247,11 +247,10 @@
reasons. It is now not possible anymore to use custom implementations of
`FormBuilderInterface` for specific form types.
If you are in such a situation, you can subclass `FormRegistry` instead and override
`resolveType` to return a custom `ResolvedFormTypeInterface` implementation, within
which you can create your own `FormBuilderInterface` implementation. You should
register this custom registry class under the service name "form.registry" in order
to replace the default implementation.
If you are in such a situation, you can implement a custom `ResolvedFormTypeInterface`
where you create your own `FormBuilderInterface` implementation. You also need to
register a custom `ResolvedFormTypeFactoryInterface` implementation under the service
name "form.resolved_type_factory" in order to replace the default implementation.
* If you previously inherited from `FieldType`, you should now inherit from
`FormType`. You should also set the option `compound` to `false` if your field

View File

@ -5,13 +5,17 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="form.extension.class">Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension</parameter>
<parameter key="form.resolved_type_factory.class">Symfony\Component\Form\ResolvedFormTypeFactory</parameter>
<parameter key="form.registry.class">Symfony\Component\Form\FormRegistry</parameter>
<parameter key="form.factory.class">Symfony\Component\Form\FormFactory</parameter>
<parameter key="form.extension.class">Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension</parameter>
<parameter key="form.type_guesser.validator.class">Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser</parameter>
</parameters>
<services>
<!-- ResolvedFormTypeFactory -->
<service id="form.resolved_type_factory" class="%form.resolved_type_factory.class%" />
<!-- FormRegistry -->
<service id="form.registry" class="%form.registry.class%">
<argument type="collection">
@ -23,11 +27,13 @@
-->
<argument type="service" id="form.extension" />
</argument>
<argument type="service" id="form.resolved_type_factory" />
</service>
<!-- FormFactory -->
<service id="form.factory" class="%form.factory.class%">
<argument type="service" id="form.registry" />
<argument type="service" id="form.resolved_type_factory" />
</service>
<!-- DependencyInjectionExtension -->

View File

@ -152,12 +152,12 @@ CHANGELOG
* deprecated the options "data_timezone" and "user_timezone" in DateType, DateTimeType and TimeType
and renamed them to "model_timezone" and "view_timezone"
* fixed: TransformationFailedExceptions thrown in the model transformer are now caught by the form
* added FormRegistry and ResolvedFormTypeInterface
* added FormRegistryInterface, ResolvedFormTypeInterface and ResolvedFormTypeFactoryInterface
* deprecated FormFactory methods
* `addType`
* `hasType`
* `getType`
* [BC BREAK] FormFactory now expects a FormRegistryInterface as constructor argument
* [BC BREAK] FormFactory now expects a FormRegistryInterface and a ResolvedFormTypeFactoryInterface as constructor argument
* [BC BREAK] The method `createBuilder` in FormTypeInterface is not supported anymore for performance reasons
* [BC BREAK] Removed `setTypes` from FormBuilder
* deprecated AbstractType methods

View File

@ -23,9 +23,15 @@ class FormFactory implements FormFactoryInterface
*/
private $registry;
public function __construct(FormRegistryInterface $registry)
/**
* @var ResolvedFormTypeFactoryInterface
*/
private $resolvedTypeFactory;
public function __construct(FormRegistryInterface $registry, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
{
$this->registry = $registry;
$this->resolvedTypeFactory = $resolvedTypeFactory;
}
/**
@ -73,14 +79,20 @@ class FormFactory implements FormFactoryInterface
$options['data'] = $data;
}
if ($type instanceof ResolvedFormTypeInterface) {
$this->registry->addType($type);
} elseif ($type instanceof FormTypeInterface) {
$type = $this->registry->resolveType($type);
$this->registry->addType($type);
if ($type instanceof FormTypeInterface) {
// An unresolved type instance was passed. Type extensions
// 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)) {
$type = $this->registry->getType($type);
} else {
} elseif (!$type instanceof ResolvedFormTypeInterface) {
throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
}
@ -152,12 +164,18 @@ class FormFactory implements FormFactoryInterface
* @param FormTypeInterface $type The type
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link FormRegistryInterface::resolveType()} and
* {@link FormRegistryInterface::addType()} instead.
* form extensions or type registration in the Dependency
* Injection Container instead.
*/
public function addType(FormTypeInterface $type)
{
$this->registry->addType($this->registry->resolveType($type));
$parentType = $type->getParent();
$this->registry->addType($this->resolvedTypeFactory->createResolvedType(
$type,
array(),
$parentType ? $this->registry->getType($parentType) : null
));
}
/**

View File

@ -37,14 +37,20 @@ class FormRegistry implements FormRegistryInterface
*/
private $guesser;
/**
* @var ResolvedFormTypeFactoryInterface
*/
private $resolvedTypeFactory;
/**
* Constructor.
*
* @param array $extensions An array of FormExtensionInterface
* @param array $extensions An array of FormExtensionInterface
* @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory The factory for resolved form types.
*
* @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
*/
public function __construct(array $extensions)
public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
{
foreach ($extensions as $extension) {
if (!$extension instanceof FormExtensionInterface) {
@ -53,26 +59,7 @@ class FormRegistry implements FormRegistryInterface
}
$this->extensions = $extensions;
}
/**
* {@inheritdoc}
*/
public function resolveType(FormTypeInterface $type)
{
$typeExtensions = array();
foreach ($this->extensions as $extension) {
/* @var FormExtensionInterface $extension */
$typeExtensions = array_merge(
$typeExtensions,
$extension->getTypeExtensions($type->getName())
);
}
$parent = $type->getParent() ? $this->getType($type->getParent()) : null;
return new ResolvedFormType($type, $typeExtensions, $parent);
$this->resolvedTypeFactory = $resolvedTypeFactory;
}
/**
@ -93,6 +80,7 @@ class FormRegistry implements FormRegistryInterface
}
if (!isset($this->types[$name])) {
/** @var FormTypeInterface $type */
$type = null;
foreach ($this->extensions as $extension) {
@ -107,7 +95,22 @@ class FormRegistry implements FormRegistryInterface
throw new FormException(sprintf('Could not load type "%s"', $name));
}
$this->addType($this->resolveType($type));
$parentType = $type->getParent();
$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];

View File

@ -22,6 +22,10 @@ interface FormRegistryInterface
* Adds a form type.
*
* @param ResolvedFormTypeInterface $type The type
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* form extensions or type registration in the Dependency
* Injection Container instead.
*/
public function addType(ResolvedFormTypeInterface $type);
@ -48,18 +52,6 @@ interface FormRegistryInterface
*/
public function hasType($name);
/**
* Resolves a form type.
*
* @param FormTypeInterface $type
*
* @return ResolvedFormTypeInterface
*
* @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string
* @throws Exception\FormException if the types parent can not be retrieved from any extension
*/
public function resolveType(FormTypeInterface $type);
/**
* Returns the guesser responsible for guessing types.
*

View File

@ -35,7 +35,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface
private $typeExtensions;
/**
* @var ResolvedFormType
* @var ResolvedFormTypeInterface
*/
private $parent;
@ -44,7 +44,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface
*/
private $optionsResolver;
public function __construct(FormTypeInterface $innerType, array $typeExtensions = array(), ResolvedFormType $parent = null)
public function __construct(FormTypeInterface $innerType, array $typeExtensions = array(), ResolvedFormTypeInterface $parent = null)
{
if (!preg_match('/^[a-z0-9_]*$/i', $innerType->getName())) {
throw new FormException(sprintf(
@ -148,7 +148,16 @@ class ResolvedFormType implements ResolvedFormTypeInterface
return $view;
}
private function buildForm(FormBuilderInterface $builder, array $options)
/**
* Configures a form builder for the type hierarchy.
*
* This method is protected in order to allow implementing classes
* to change or call it in re-implementations of {@link createBuilder()}.
*
* @param FormBuilderInterface $builder The builder to configure.
* @param array $options The options used for the configuration.
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (null !== $this->parent) {
$this->parent->buildForm($builder, $options);
@ -162,7 +171,19 @@ class ResolvedFormType implements ResolvedFormTypeInterface
}
}
private function buildView(FormView $view, FormInterface $form, array $options)
/**
* Configures a form view for the type hierarchy.
*
* This method is protected in order to allow implementing classes
* to change or call it in re-implementations of {@link createView()}.
*
* It is called before the children of the view are built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (null !== $this->parent) {
$this->parent->buildView($view, $form, $options);
@ -176,7 +197,19 @@ class ResolvedFormType implements ResolvedFormTypeInterface
}
}
private function finishView(FormView $view, FormInterface $form, array $options)
/**
* Finishes a form view for the type hierarchy.
*
* This method is protected in order to allow implementing classes
* to change or call it in re-implementations of {@link createView()}.
*
* It is called after the children of the view have been built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function finishView(FormView $view, FormInterface $form, array $options)
{
if (null !== $this->parent) {
$this->parent->finishView($view, $form, $options);
@ -190,7 +223,15 @@ class ResolvedFormType implements ResolvedFormTypeInterface
}
}
private function getOptionsResolver()
/**
* Returns the configured options resolver used for this type.
*
* This method is protected in order to allow implementing classes
* to change or call it in re-implementations of {@link createBuilder()}.
*
* @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
*/
public function getOptionsResolver()
{
if (null === $this->optionsResolver) {
if (null !== $this->parent) {

View File

@ -0,0 +1,26 @@
<?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;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ResolvedFormTypeFactory implements ResolvedFormTypeFactoryInterface
{
/**
* {@inheritdoc}
*/
public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null)
{
return new ResolvedFormType($type, $typeExtensions, $parent);
}
}

View File

@ -0,0 +1,38 @@
<?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;
/**
* Creates ResolvedFormTypeInterface instances.
*
* This interface allows you to use your custom ResolvedFormTypeInterface
* implementation, within which you can customize the concrete FormBuilderInterface
* implementations or FormView subclasses that are used by the framework.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface ResolvedFormTypeFactoryInterface
{
/**
* Resolves a form type.
*
* @param FormTypeInterface $type
* @param array $typeExtensions
* @param ResolvedFormTypeInterface $parent
*
* @return ResolvedFormTypeInterface
*
* @throws Exception\UnexpectedTypeException if the types parent {@link FormTypeInterface::getParent()} is not a string
* @throws Exception\FormException if the types parent can not be retrieved from any extension
*/
public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null);
}

View File

@ -67,4 +67,41 @@ interface ResolvedFormTypeInterface
* @return FormView The created form view.
*/
public function createView(FormInterface $form, FormView $parent = null);
/**
* Configures a form builder for the type hierarchy.
*
* @param FormBuilderInterface $builder The builder to configure.
* @param array $options The options used for the configuration.
*/
public function buildForm(FormBuilderInterface $builder, array $options);
/**
* Configures a form view for the type hierarchy.
*
* It is called before the children of the view are built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function buildView(FormView $view, FormInterface $form, array $options);
/**
* Finishes a form view for the type hierarchy.
*
* It is called after the children of the view have been built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function finishView(FormView $view, FormInterface $form, array $options);
/**
* Returns the configured options resolver used for this type.
*
* @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
*/
public function getOptionsResolver();
}

View File

@ -44,6 +44,11 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
*/
private $registry;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $resolvedTypeFactory;
/**
* @var FormFactory
*/
@ -55,10 +60,11 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->markTestSkipped('The "EventDispatcher" component is not available');
}
$this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactoryInterface');
$this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
$this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
$this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
$this->factory = new FormFactory($this->registry);
$this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
$this->registry->expects($this->any())
->method('getTypeGuesser')
@ -73,8 +79,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$type = new FooType();
$resolvedType = $this->getMockResolvedType();
$this->registry->expects($this->once())
->method('resolveType')
$this->resolvedTypeFactory->expects($this->once())
->method('createResolvedType')
->with($type)
->will($this->returnValue($resolvedType));
@ -136,16 +142,11 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$type = $this->getMockType();
$resolvedType = $this->getMockResolvedType();
$this->registry->expects($this->once())
->method('resolveType')
$this->resolvedTypeFactory->expects($this->once())
->method('createResolvedType')
->with($type)
->will($this->returnValue($resolvedType));
// The type is also implicitly added to the registry
$this->registry->expects($this->once())
->method('addType')
->with($resolvedType);
$resolvedType->expects($this->once())
->method('createBuilder')
->with($this->factory, 'name', $options)
@ -159,11 +160,6 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$options = array('a' => '1', 'b' => '2');
$resolvedType = $this->getMockResolvedType();
// The type is also implicitly added to the registry
$this->registry->expects($this->once())
->method('addType')
->with($resolvedType);
$resolvedType->expects($this->once())
->method('createBuilder')
->with($this->factory, 'name', $options)
@ -555,7 +551,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
{
return $this->getMockBuilder('Symfony\Component\Form\FormFactory')
->setMethods($methods)
->setConstructorArgs(array($this->registry))
->setConstructorArgs(array($this->registry, $this->resolvedTypeFactory))
->getMock();
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\ResolvedFormTypeFactory;
use Symfony\Component\Form\FormRegistry;
use Symfony\Component\Form\Extension\Core\CoreExtension;
@ -20,6 +21,11 @@ use Symfony\Component\Form\Extension\Core\CoreExtension;
*/
class FormIntegrationTestCase extends \PHPUnit_Framework_TestCase
{
/**
* @var ResolvedFormTypeFactory
*/
protected $resolvedTypeFactory;
/**
* @var FormRegistry
*/
@ -36,8 +42,9 @@ class FormIntegrationTestCase extends \PHPUnit_Framework_TestCase
$this->markTestSkipped('The "EventDispatcher" component is not available');
}
$this->registry = new FormRegistry($this->getExtensions());
$this->factory = new FormFactory($this->registry);
$this->resolvedTypeFactory = new ResolvedFormTypeFactory();
$this->registry = new FormRegistry($this->getExtensions(), $this->resolvedTypeFactory);
$this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
}
protected function getExtensions()

View File

@ -27,6 +27,11 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
*/
private $registry;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $resolvedTypeFactory;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
@ -49,6 +54,7 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->resolvedTypeFactory = $this->getMock('Symfony\Component\Form\ResolvedFormTypeFactory');
$this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
$this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
$this->extension1 = new TestExtension($this->guesser1);
@ -56,53 +62,16 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
$this->registry = new FormRegistry(array(
$this->extension1,
$this->extension2,
));
}
public function testResolveType()
{
$type = new FooType();
$ext1 = new FooTypeBarExtension();
$ext2 = new FooTypeBazExtension();
$this->extension1->addTypeExtension($ext1);
$this->extension2->addTypeExtension($ext2);
$resolvedType = $this->registry->resolveType($type);
$this->assertEquals($type, $resolvedType->getInnerType());
$this->assertEquals(array($ext1, $ext2), $resolvedType->getTypeExtensions());
}
public function testResolveTypeConnectsParent()
{
$parentType = new FooType();
$type = new FooSubType();
$resolvedParentType = $this->registry->resolveType($parentType);
$this->registry->addType($resolvedParentType);
$resolvedType = $this->registry->resolveType($type);
$this->assertSame($resolvedParentType, $resolvedType->getParent());
}
/**
* @expectedException Symfony\Component\Form\Exception\FormException
*/
public function testResolveTypeThrowsExceptionIfParentNotFound()
{
$type = new FooSubType();
$this->registry->resolveType($type);
), $this->resolvedTypeFactory);
}
public function testGetTypeReturnsAddedType()
{
$type = new FooType();
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$resolvedType = $this->registry->resolveType($type);
$resolvedType->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->registry->addType($resolvedType);
@ -112,13 +81,88 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
public function testGetTypeFromExtension()
{
$type = new FooType();
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$this->extension2->addType($type);
$this->resolvedTypeFactory->expects($this->once())
->method('createResolvedType')
->with($type)
->will($this->returnValue($resolvedType));
$resolvedType->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$resolvedType = $this->registry->getType('foo');
$this->assertInstanceOf('Symfony\Component\Form\ResolvedFormTypeInterface', $resolvedType);
$this->assertSame($type, $resolvedType->getInnerType());
$this->assertSame($resolvedType, $this->registry->getType('foo'));
}
public function testGetTypeWithTypeExtensions()
{
$type = new FooType();
$ext1 = new FooTypeBarExtension();
$ext2 = new FooTypeBazExtension();
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$this->extension2->addType($type);
$this->extension1->addTypeExtension($ext1);
$this->extension2->addTypeExtension($ext2);
$this->resolvedTypeFactory->expects($this->once())
->method('createResolvedType')
->with($type, array($ext1, $ext2))
->will($this->returnValue($resolvedType));
$resolvedType->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->assertSame($resolvedType, $this->registry->getType('foo'));
}
public function testGetTypeConnectsParent()
{
$parentType = new FooType();
$type = new FooSubType();
$parentResolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$this->extension1->addType($parentType);
$this->extension2->addType($type);
$this->resolvedTypeFactory->expects($this->at(0))
->method('createResolvedType')
->with($parentType)
->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'));
$this->assertSame($resolvedType, $this->registry->getType('foo_sub_type'));
}
/**
* @expectedException Symfony\Component\Form\Exception\FormException
*/
public function testGetTypeThrowsExceptionIfParentNotFound()
{
$type = new FooSubType();
$this->extension1->addType($type);
$this->registry->getType($type);
}
/**
@ -139,9 +183,11 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
public function testHasTypeAfterAdding()
{
$type = new FooType();
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$resolvedType = $this->registry->resolveType($type);
$resolvedType->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->assertFalse($this->registry->hasType('foo'));
@ -153,6 +199,16 @@ class FormRegistryTest extends \PHPUnit_Framework_TestCase
public function testHasTypeAfterLoadingFromExtension()
{
$type = new FooType();
$resolvedType = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
$this->resolvedTypeFactory->expects($this->once())
->method('createResolvedType')
->with($type)
->will($this->returnValue($resolvedType));
$resolvedType->expects($this->any())
->method('getName')
->will($this->returnValue('foo'));
$this->assertFalse($this->registry->hasType('foo'));