From 1ce2db87e2e50f0269870c6bdf1c2d13729a9ab3 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Fri, 22 Apr 2011 19:22:26 +0200 Subject: [PATCH] [Form] Added FormTypeExtensionInterface With implementations of this interface, existing types can be amended. The Csrf extension, for example, now contains a class FormTypeCsrfExtension that adds CSRF capabilities to the "form" type. To register new type extensions in the DIC, tag them with "form.type_extension" and the name of the extended type as alias. --- .../DependencyInjection/Compiler/FormPass.php | 18 ++++- .../FrameworkBundle/Resources/config/form.xml | 20 ++++-- .../Component/Form/AbstractExtension.php | 69 ++++++++++++++++--- src/Symfony/Component/Form/AbstractType.php | 18 +++++ .../Component/Form/AbstractTypeExtension.php | 32 +++++++++ .../Form/Extension/Core/Type/FormType.php | 14 ---- .../Form/Extension/Csrf/CsrfExtension.php | 5 +- .../Csrf/Type/FormTypeCsrfExtension.php | 46 +++++++++++++ .../DependencyInjectionExtension.php | 34 +++++++-- src/Symfony/Component/Form/Form.php | 8 +++ .../Component/Form/FormExtensionInterface.php | 4 ++ src/Symfony/Component/Form/FormFactory.php | 65 +++++++++++++---- .../Form/FormTypeExtensionInterface.php | 25 +++++++ .../Component/Form/FormTypeInterface.php | 4 ++ .../Component/Form/AbstractExtensionTest.php | 4 ++ .../Core/Type/CollectionTypeTest.php | 6 +- .../Form/Extension/Core/Type/FormTypeTest.php | 18 ----- .../Form/Extension/Core/Type/TypeTestCase.php | 5 -- .../Form/Extension/Csrf/Type/CsrfTypeTest.php | 2 - .../Csrf/Type/FormTypeCsrfExtensionTest.php | 33 +++++++++ .../Form/Extension/Csrf/Type/TypeTestCase.php | 34 +++++++++ .../Symfony/Tests/Component/Form/FormTest.php | 48 ++++++++++++- 22 files changed, 431 insertions(+), 81 deletions(-) create mode 100644 src/Symfony/Component/Form/AbstractTypeExtension.php create mode 100644 src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php create mode 100644 src/Symfony/Component/Form/FormTypeExtensionInterface.php create mode 100644 tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php create mode 100644 tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/TypeTestCase.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php index 60fbf9fdeb..7fe8bb8772 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @@ -42,9 +42,25 @@ class FormPass implements CompilerPassInterface $container->getDefinition('form.extension')->replaceArgument(1, $types); + $typeExtensions = array(); + + foreach ($container->findTaggedServiceIds('form.type_extension') as $serviceId => $tag) { + $alias = isset($tag[0]['alias']) + ? $tag[0]['alias'] + : $serviceId; + + if (!isset($typeExtensions[$alias])) { + $typeExtensions[$alias] = array(); + } + + $typeExtensions[$alias][] = $serviceId; + } + + $container->getDefinition('form.extension')->replaceArgument(2, $typeExtensions); + // Find all services annotated with "form.type_guesser" $guessers = array_keys($container->findTaggedServiceIds('form.type_guesser')); - $container->getDefinition('form.extension')->replaceArgument(2, $guessers); + $container->getDefinition('form.extension')->replaceArgument(3, $guessers); } } \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml index fd4d1fd2ee..8cbcdf89a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml @@ -42,6 +42,11 @@ --> + + @@ -68,7 +73,7 @@ %file.temporary_storage.directory% - + @@ -91,10 +96,6 @@ - - - - @@ -153,6 +154,15 @@ + + + + + + + + + diff --git a/src/Symfony/Component/Form/AbstractExtension.php b/src/Symfony/Component/Form/AbstractExtension.php index 358b690084..25a4c527aa 100644 --- a/src/Symfony/Component/Form/AbstractExtension.php +++ b/src/Symfony/Component/Form/AbstractExtension.php @@ -25,9 +25,9 @@ abstract class AbstractExtension implements FormExtensionInterface private $types; /** - * @var Boolean + * @var array */ - private $typesLoaded = false; + private $typeExtensions; /** * @var FormTypeGuesserInterface @@ -39,14 +39,23 @@ abstract class AbstractExtension implements FormExtensionInterface */ private $typeGuesserLoaded = false; - abstract protected function loadTypes(); + protected function loadTypes() + { + return array(); + } - abstract protected function loadTypeGuesser(); + protected function loadTypeExtensions() + { + return array(); + } + + protected function loadTypeGuesser() + { + return null; + } private function initTypes() { - $this->typesLoaded = true; - $types = $this->loadTypes(); $typesByName = array(); @@ -61,6 +70,28 @@ abstract class AbstractExtension implements FormExtensionInterface $this->types = $typesByName; } + private function initTypeExtensions() + { + $extensions = $this->loadTypeExtensions(); + $extensionsByType = array(); + + foreach ($extensions as $extension) { + if (!$extension instanceof FormTypeExtensionInterface) { + throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface'); + } + + $type = $extension->getExtendedType(); + + if (!isset($extensionsByType[$type])) { + $extensionsByType[$type] = array(); + } + + $extensionsByType[$type][] = $extension; + } + + $this->typeExtensions = $extensionsByType; + } + private function initTypeGuesser() { $this->typeGuesserLoaded = true; @@ -76,12 +107,12 @@ abstract class AbstractExtension implements FormExtensionInterface public function getType($name) { - if (!$this->typesLoaded) { + if (null === $this->types) { $this->initTypes(); } if (!isset($this->types[$name])) { - throw new FormException(sprintf('The type "%s" can not be typesLoaded by this extension', $name)); + throw new FormException(sprintf('The type "%s" can not be loaded by this extension', $name)); } return $this->types[$name]; @@ -89,13 +120,33 @@ abstract class AbstractExtension implements FormExtensionInterface public function hasType($name) { - if (!$this->typesLoaded) { + if (null === $this->types) { $this->initTypes(); } return isset($this->types[$name]); } + function getTypeExtensions($name) + { + if (null === $this->typeExtensions) { + $this->initTypeExtensions(); + } + + return isset($this->typeExtensions[$name]) + ? $this->typeExtensions[$name] + : array(); + } + + function hasTypeExtensions($name) + { + if (null === $this->typeExtensions) { + $this->initTypeExtensions(); + } + + return isset($this->typeExtensions[$name]) && count($this->typeExtensions[$name]) > 0; + } + public function getTypeGuesser() { if (!$this->typeGuesserLoaded) { diff --git a/src/Symfony/Component/Form/AbstractType.php b/src/Symfony/Component/Form/AbstractType.php index 7d3de6ee15..f7c5d9e94c 100644 --- a/src/Symfony/Component/Form/AbstractType.php +++ b/src/Symfony/Component/Form/AbstractType.php @@ -13,6 +13,8 @@ namespace Symfony\Component\Form; abstract class AbstractType implements FormTypeInterface { + private $extensions = array(); + public function buildForm(FormBuilder $builder, array $options) { } @@ -46,4 +48,20 @@ abstract class AbstractType implements FormTypeInterface return strtolower($matches[1]); } + + public function setExtensions(array $extensions) + { + foreach ($extensions as $extension) { + if (!$extension instanceof FormTypeExtensionInterface) { + throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface'); + } + } + + $this->extensions = $extensions; + } + + public function getExtensions() + { + return $this->extensions; + } } diff --git a/src/Symfony/Component/Form/AbstractTypeExtension.php b/src/Symfony/Component/Form/AbstractTypeExtension.php new file mode 100644 index 0000000000..6aa29161a6 --- /dev/null +++ b/src/Symfony/Component/Form/AbstractTypeExtension.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +abstract class AbstractTypeExtension implements FormTypeExtensionInterface +{ + public function buildForm(FormBuilder $builder, array $options) + { + } + + public function buildView(FormView $view, FormInterface $form) + { + } + + public function buildViewBottomUp(FormView $view, FormInterface $form) + { + } + + public function getDefaultOptions(array $options) + { + return array(); + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index a1b378b73d..387d43b028 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -25,16 +25,6 @@ class FormType extends AbstractType { $builder->setAttribute('virtual', $options['virtual']) ->setDataMapper(new PropertyPathMapper($options['data_class'])); - - if ($options['csrf_protection']) { - $csrfOptions = array('page_id' => $options['csrf_page_id']); - - if ($options['csrf_provider']) { - $csrfOptions['csrf_provider'] = $options['csrf_provider']; - } - - $builder->add($options['csrf_field_name'], 'csrf', $csrfOptions); - } } public function buildViewBottomUp(FormView $view, FormInterface $form) @@ -54,10 +44,6 @@ class FormType extends AbstractType public function getDefaultOptions(array $options) { $defaultOptions = array( - 'csrf_protection' => true, - 'csrf_field_name' => '_token', - 'csrf_provider' => null, - 'csrf_page_id' => get_class($this), 'virtual' => false, // Errors in forms bubble by default, so that form errors will // end up as global errors in the root form diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php index 1a7a882620..951f1fb67d 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php @@ -31,7 +31,10 @@ class CsrfExtension extends AbstractExtension ); } - protected function loadTypeGuesser() + protected function loadTypeExtensions() { + return array( + new Type\FormTypeCsrfExtension(), + ); } } diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php new file mode 100644 index 0000000000..14befd02e6 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Csrf\Type; + +use Symfony\Component\Form\AbstractTypeExtension; +use Symfony\Component\Form\FormBuilder; + +class FormTypeCsrfExtension extends AbstractTypeExtension +{ + public function buildForm(FormBuilder $builder, array $options) + { + if ($options['csrf_protection']) { + $csrfOptions = array('page_id' => $options['csrf_page_id']); + + if ($options['csrf_provider']) { + $csrfOptions['csrf_provider'] = $options['csrf_provider']; + } + + $builder->add($options['csrf_field_name'], 'csrf', $csrfOptions); + } + } + + public function getDefaultOptions(array $options) + { + return array( + 'csrf_protection' => true, + 'csrf_field_name' => '_token', + 'csrf_provider' => null, + 'csrf_page_id' => get_class($this), + ); + } + + public function getExtendedType() + { + return 'form'; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php b/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php index 295a76d32d..a668ff4628 100644 --- a/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php +++ b/src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php @@ -28,25 +28,45 @@ class DependencyInjectionExtension implements FormExtensionInterface private $guesserLoaded = false; public function __construct(ContainerInterface $container, - array $typeServiceIds, array $guesserServiceIds) + array $typeServiceIds, array $typeExtensionServiceIds, + array $guesserServiceIds) { $this->container = $container; $this->typeServiceIds = $typeServiceIds; + $this->typeExtensionServiceIds = $typeExtensionServiceIds; $this->guesserServiceIds = $guesserServiceIds; } - public function getType($identifier) + public function getType($name) { - if (!isset($this->typeServiceIds[$identifier])) { - throw new \InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $identifier)); + if (!isset($this->typeServiceIds[$name])) { + throw new \InvalidArgumentException(sprintf('The field type "%s" is not registered with the service container.', $name)); } - return $this->container->get($this->typeServiceIds[$identifier]); + return $this->container->get($this->typeServiceIds[$name]); } - public function hasType($identifier) + public function hasType($name) { - return isset($this->typeServiceIds[$identifier]); + return isset($this->typeServiceIds[$name]); + } + + public function getTypeExtensions($name) + { + $extensions = array(); + + if (isset($this->typeExtensionServiceIds[$name])) { + foreach ($this->typeExtensionServiceIds[$name] as $serviceId) { + $extensions[] = $this->container->get($serviceId); + } + } + + return $extensions; + } + + public function hasTypeExtensions($name) + { + return isset($this->typeExtensionServiceIds[$name]); } public function getTypeGuesser() diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 2c8c4168df..f855650b99 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -844,6 +844,10 @@ class Form implements \IteratorAggregate, FormInterface foreach ($types as $type) { $type->buildView($view, $this); + + foreach ($type->getExtensions() as $typeExtension) { + $typeExtension->buildView($view, $this); + } } foreach ($this->children as $key => $child) { @@ -854,6 +858,10 @@ class Form implements \IteratorAggregate, FormInterface foreach ($types as $type) { $type->buildViewBottomUp($view, $this); + + foreach ($type->getExtensions() as $typeExtension) { + $typeExtension->buildViewBottomUp($view, $this); + } } return $view; diff --git a/src/Symfony/Component/Form/FormExtensionInterface.php b/src/Symfony/Component/Form/FormExtensionInterface.php index e1ddc9d7de..770e714ae7 100644 --- a/src/Symfony/Component/Form/FormExtensionInterface.php +++ b/src/Symfony/Component/Form/FormExtensionInterface.php @@ -17,5 +17,9 @@ interface FormExtensionInterface function hasType($name); + function getTypeExtensions($name); + + function hasTypeExtensions($name); + function getTypeGuesser(); } diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index a935a58a4e..66d219caa0 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -20,6 +20,8 @@ class FormFactory implements FormFactoryInterface { private $extensions = array(); + private $types = array(); + private $guesser; public function __construct(array $extensions) @@ -48,6 +50,46 @@ class FormFactory implements FormFactoryInterface $this->guesser = new FormTypeGuesserChain($guessers); } + public function getType($name) + { + $type = null; + + if ($name instanceof FormTypeInterface) { + $type = $name; + $name = $type->getName(); + } + + if (!isset($this->types[$name])) { + if (!$type) { + foreach ($this->extensions as $extension) { + if ($extension->hasType($name)) { + $type = $extension->getType($name); + break; + } + } + + if (!$type) { + throw new FormException(sprintf('Could not load type "%s"', $name)); + } + } + + $typeExtensions = array(); + + foreach ($this->extensions as $extension) { + $typeExtensions = array_merge( + $typeExtensions, + $extension->getTypeExtensions($name) + ); + } + + $type->setExtensions($typeExtensions); + + $this->types[$name] = $type; + } + + return $this->types[$name]; + } + public function create($type, $data = null, array $options = array()) { return $this->createBuilder($type, $data, $options)->getForm(); @@ -77,27 +119,22 @@ class FormFactory implements FormFactoryInterface { $builder = null; $types = array(); + $typeExtensions = array(); $knownOptions = array(); $passedOptions = array_keys($options); while (null !== $type) { - if (!$type instanceof FormTypeInterface) { - foreach ($this->extensions as $extension) { - if ($extension->hasType($type)) { - $type = $extension->getType($type); - break; - } - } + $type = $this->getType($type); - if (!$type) { - throw new FormException(sprintf('Could not load type "%s"', $type)); - } + $defaultOptions = $type->getDefaultOptions($options); + + foreach ($type->getExtensions() as $typeExtension) { + $defaultOptions = array_merge($defaultOptions, $typeExtension->getDefaultOptions($options)); } - array_unshift($types, $type); - $defaultOptions = $type->getDefaultOptions($options); $options = array_merge($defaultOptions, $options); $knownOptions = array_merge($knownOptions, array_keys($defaultOptions)); + array_unshift($types, $type); $type = $type->getParent($options); } @@ -117,6 +154,10 @@ class FormFactory implements FormFactoryInterface foreach ($types as $type) { $type->buildForm($builder, $options); + + foreach ($type->getExtensions() as $typeExtension) { + $typeExtension->buildForm($builder, $options); + } } if (null !== $data) { diff --git a/src/Symfony/Component/Form/FormTypeExtensionInterface.php b/src/Symfony/Component/Form/FormTypeExtensionInterface.php new file mode 100644 index 0000000000..f641b1b8bf --- /dev/null +++ b/src/Symfony/Component/Form/FormTypeExtensionInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +interface FormTypeExtensionInterface +{ + function buildForm(FormBuilder $builder, array $options); + + function buildView(FormView $view, FormInterface $form); + + function buildViewBottomUp(FormView $view, FormInterface $form); + + function getDefaultOptions(array $options); + + function getExtendedType(); +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/FormTypeInterface.php b/src/Symfony/Component/Form/FormTypeInterface.php index 34dfffc8a7..f5a1dd0008 100644 --- a/src/Symfony/Component/Form/FormTypeInterface.php +++ b/src/Symfony/Component/Form/FormTypeInterface.php @@ -26,4 +26,8 @@ interface FormTypeInterface function getParent(array $options); function getName(); + + function setExtensions(array $extensions); + + function getExtensions(); } \ No newline at end of file diff --git a/tests/Symfony/Tests/Component/Form/AbstractExtensionTest.php b/tests/Symfony/Tests/Component/Form/AbstractExtensionTest.php index cd52277fb6..4b7d67141e 100644 --- a/tests/Symfony/Tests/Component/Form/AbstractExtensionTest.php +++ b/tests/Symfony/Tests/Component/Form/AbstractExtensionTest.php @@ -53,6 +53,10 @@ class TestType implements FormTypeInterface function getDefaultOptions(array $options) {} function getParent(array $options) {} + + function setExtensions(array $extensions) {} + + function getExtensions() {} } class TestExtension extends AbstractExtension diff --git a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php index c5a7f378a3..5e7afb363d 100644 --- a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php +++ b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/CollectionTypeTest.php @@ -16,15 +16,13 @@ use Symfony\Component\Form\Form; class CollectionFormTest extends TypeTestCase { - public function testContainsOnlyCsrfTokenByDefault() + public function testContainsNoFieldByDefault() { $form = $this->factory->create('collection', null, array( 'type' => 'field', - 'csrf_field_name' => 'abc', )); - $this->assertTrue($form->has('abc')); - $this->assertEquals(1, count($form)); + $this->assertEquals(0, count($form)); } public function testSetDataAdjustsSize() diff --git a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/FormTypeTest.php b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/FormTypeTest.php index e0ded2a005..373697aef1 100644 --- a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/FormTypeTest.php +++ b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/FormTypeTest.php @@ -63,24 +63,6 @@ class FormTest_AuthorWithoutRefSetter class FormTypeTest extends TypeTestCase { - public function testCsrfProtectionByDefault() - { - $form = $this->factory->create('form', null, array( - 'csrf_field_name' => 'csrf', - )); - - $this->assertTrue($form->has('csrf')); - } - - public function testCsrfProtectionCanBeDisabled() - { - $form = $this->factory->create('form', null, array( - 'csrf_protection' => false, - )); - - $this->assertEquals(0, count($form)); - } - public function testValidationGroupNullByDefault() { $form = $this->factory->create('form'); diff --git a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/TypeTestCase.php b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/TypeTestCase.php index e96ac838c9..917fbd20d1 100644 --- a/tests/Symfony/Tests/Component/Form/Extension/Core/Type/TypeTestCase.php +++ b/tests/Symfony/Tests/Component/Form/Extension/Core/Type/TypeTestCase.php @@ -14,13 +14,10 @@ namespace Symfony\Tests\Component\Form\Extension\Core\Type; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\Extension\Core\CoreExtension; -use Symfony\Component\Form\Extension\Csrf\CsrfExtension; use Symfony\Component\EventDispatcher\EventDispatcher; abstract class TypeTestCase extends \PHPUnit_Framework_TestCase { - protected $csrfProvider; - protected $validator; protected $storage; @@ -35,7 +32,6 @@ abstract class TypeTestCase extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'); $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface'); $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $this->storage = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\TemporaryStorage') @@ -49,7 +45,6 @@ abstract class TypeTestCase extends \PHPUnit_Framework_TestCase { return array( new CoreExtension($this->validator, $this->storage), - new CsrfExtension($this->csrfProvider), ); } diff --git a/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/CsrfTypeTest.php b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/CsrfTypeTest.php index 38c0e804a6..f4e7c714ac 100644 --- a/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/CsrfTypeTest.php +++ b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/CsrfTypeTest.php @@ -11,8 +11,6 @@ namespace Symfony\Tests\Component\Form\Extension\Csrf\Type; -use Symfony\Tests\Component\Form\Extension\Core\Type\TypeTestCase; - class CsrfTypeTest extends TypeTestCase { protected $provider; diff --git a/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php new file mode 100644 index 0000000000..3e10e0b21d --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Component\Form\Extension\Csrf\Type; + +class FormTypeCsrfExtensionTest extends TypeTestCase +{ + public function testCsrfProtectionByDefault() + { + $form = $this->factory->create('form', null, array( + 'csrf_field_name' => 'csrf', + )); + + $this->assertTrue($form->has('csrf')); + } + + public function testCsrfProtectionCanBeDisabled() + { + $form = $this->factory->create('form', null, array( + 'csrf_protection' => false, + )); + + $this->assertEquals(0, count($form)); + } +} diff --git a/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/TypeTestCase.php b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/TypeTestCase.php new file mode 100644 index 0000000000..4432e5d6e1 --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/TypeTestCase.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Component\Form\Extension\Csrf\Type; + +use Symfony\Tests\Component\Form\Extension\Core\Type\TypeTestCase as BaseTestCase; +use Symfony\Component\Form\Extension\Csrf\CsrfExtension; + +abstract class TypeTestCase extends BaseTestCase +{ + protected $csrfProvider; + + protected function setUp() + { + $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'); + + parent::setUp(); + } + + protected function getExtensions() + { + return array_merge(parent::getExtensions(), array( + new CsrfExtension($this->csrfProvider), + )); + } +} diff --git a/tests/Symfony/Tests/Component/Form/FormTest.php b/tests/Symfony/Tests/Component/Form/FormTest.php index eb4e1f334e..e1282313c1 100644 --- a/tests/Symfony/Tests/Component/Form/FormTest.php +++ b/tests/Symfony/Tests/Component/Form/FormTest.php @@ -869,7 +869,15 @@ class FormTest extends \PHPUnit_Framework_TestCase { $test = $this; $type1 = $this->getMock('Symfony\Component\Form\FormTypeInterface'); + $type1Extension = $this->getMock('Symfony\Component\Form\FormTypeExtensionInterface'); + $type1->expects($this->any()) + ->method('getExtensions') + ->will($this->returnValue(array($type1Extension))); $type2 = $this->getMock('Symfony\Component\Form\FormTypeInterface'); + $type2Extension = $this->getMock('Symfony\Component\Form\FormTypeExtensionInterface'); + $type2->expects($this->any()) + ->method('getExtensions') + ->will($this->returnValue(array($type2Extension))); $calls = array(); $type1->expects($this->once()) @@ -880,6 +888,14 @@ class FormTest extends \PHPUnit_Framework_TestCase $test->assertFalse($view->hasChildren()); })); + $type1Extension->expects($this->once()) + ->method('buildView') + ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { + $calls[] = 'type1ext::buildView'; + $test->assertTrue($view->hasParent()); + $test->assertFalse($view->hasChildren()); + })); + $type2->expects($this->once()) ->method('buildView') ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { @@ -888,6 +904,14 @@ class FormTest extends \PHPUnit_Framework_TestCase $test->assertFalse($view->hasChildren()); })); + $type2Extension->expects($this->once()) + ->method('buildView') + ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { + $calls[] = 'type2ext::buildView'; + $test->assertTrue($view->hasParent()); + $test->assertFalse($view->hasChildren()); + })); + $type1->expects($this->once()) ->method('buildViewBottomUp') ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { @@ -895,6 +919,13 @@ class FormTest extends \PHPUnit_Framework_TestCase $test->assertTrue($view->hasChildren()); })); + $type1Extension->expects($this->once()) + ->method('buildViewBottomUp') + ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { + $calls[] = 'type1ext::buildViewBottomUp'; + $test->assertTrue($view->hasChildren()); + })); + $type2->expects($this->once()) ->method('buildViewBottomUp') ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { @@ -902,6 +933,13 @@ class FormTest extends \PHPUnit_Framework_TestCase $test->assertTrue($view->hasChildren()); })); + $type2Extension->expects($this->once()) + ->method('buildViewBottomUp') + ->will($this->returnCallback(function (FormView $view, Form $form) use ($test, &$calls) { + $calls[] = 'type2ext::buildViewBottomUp'; + $test->assertTrue($view->hasChildren()); + })); + $form = $this->getBuilder()->setTypes(array($type1, $type2))->getForm(); $form->setParent($this->getBuilder()->getForm()); $form->add($this->getBuilder()->getForm()); @@ -910,9 +948,13 @@ class FormTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array( 0 => 'type1::buildView', - 1 => 'type2::buildView', - 2 => 'type1::buildViewBottomUp', - 3 => 'type2::buildViewBottomUp', + 1 => 'type1ext::buildView', + 2 => 'type2::buildView', + 3 => 'type2ext::buildView', + 4 => 'type1::buildViewBottomUp', + 5 => 'type1ext::buildViewBottomUp', + 6 => 'type2::buildViewBottomUp', + 7 => 'type2ext::buildViewBottomUp', ), $calls); }