소스 검색

[Form] Introduced renderer theme factories so that themes can be changed during runtime

Bernhard Schussek 14 년 전
부모
커밋
1211d77f49
19개의 변경된 파일343개의 추가작업 그리고 57개의 파일을 삭제
  1. 3 3
      src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
  2. 2 4
      src/Symfony/Bundle/FrameworkBundle/Form/PhpEngineTheme.php
  3. 41 0
      src/Symfony/Bundle/FrameworkBundle/Form/PhpEngineThemeFactory.php
  4. 8 9
      src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
  5. 2 2
      src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
  6. 28 0
      src/Symfony/Bundle/FrameworkBundle/Tests/Form/PhpEngineThemeFactoryTest.php
  7. 3 3
      src/Symfony/Bundle/FrameworkBundle/Tests/Form/PhpEngineThemeFunctionalTest.php
  8. 9 8
      src/Symfony/Component/Form/DefaultFormFactory.php
  9. 17 0
      src/Symfony/Component/Form/Renderer/Theme/FormThemeFactoryInterface.php
  10. 44 0
      src/Symfony/Component/Form/Renderer/Theme/PhpThemeFactory.php
  11. 44 0
      src/Symfony/Component/Form/Renderer/Theme/TwigThemeFactory.php
  12. 27 8
      src/Symfony/Component/Form/Renderer/ThemeRenderer.php
  13. 12 6
      src/Symfony/Component/Form/Type/FieldType.php
  14. 5 5
      src/Symfony/Component/Form/Type/Loader/DefaultTypeLoader.php
  15. 8 3
      tests/Symfony/Tests/Component/Form/Renderer/Theme/AbstractThemeFunctionalTest.php
  16. 39 0
      tests/Symfony/Tests/Component/Form/Renderer/Theme/PhpThemeFactoryTest.php
  17. 3 3
      tests/Symfony/Tests/Component/Form/Renderer/Theme/PhpThemeFunctionalTest.php
  18. 42 0
      tests/Symfony/Tests/Component/Form/Renderer/Theme/TwigThemeFactoryTest.php
  19. 6 3
      tests/Symfony/Tests/Component/Form/Type/TestCase.php

+ 3 - 3
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

@@ -408,10 +408,10 @@ class FrameworkExtension extends Extension
             $container->setAlias('templating', 'templating.engine.delegating');
         }
 
-        $container->setAlias('form.theme', 'form.theme.default');
+        $container->setAlias('form.theme.factory', 'form.theme.factory.default');
         foreach ($config['engines'] as $engine) {
-            if ($container->hasDefinition('form.theme.' . $engine)) {
-                $container->setAlias('form.theme', 'form.theme.' . $engine);
+            if ($container->hasDefinition('form.theme.factory.' . $engine)) {
+                $container->setAlias('form.theme.factory', 'form.theme.factory.' . $engine);
             }
         }
     }

+ 2 - 4
src/Symfony/Bundle/FrameworkBundle/Form/PhpEngineTheme.php

@@ -11,10 +11,8 @@
 
 namespace Symfony\Bundle\FrameworkBundle\Form;
 
-use Symfony\Component\Form\Form;
-use Symfony\Component\Form\FieldInterface;
 use Symfony\Component\Form\Exception\FormException;
-use Symfony\Component\Form\Renderer\Theme\ThemeInterface;
+use Symfony\Component\Form\Renderer\Theme\FormThemeInterface;
 use Symfony\Component\Templating\PhpEngine;
 
 /**
@@ -24,7 +22,7 @@ use Symfony\Component\Templating\PhpEngine;
  *
  * @author Benjamin Eberlei <kontakt@beberlei.de>
  */
-class PhpEngineTheme implements ThemeInterface
+class PhpEngineTheme implements FormThemeInterface
 {
     /**
      * @var array

+ 41 - 0
src/Symfony/Bundle/FrameworkBundle/Form/PhpEngineThemeFactory.php

@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bundle\FrameworkBundle\Form;
+
+use Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface;
+use Symfony\Component\Templating\PhpEngine;
+
+/**
+ * Constructs PhpEngineTheme instances
+ *
+ * @author Bernhard Schussek <bernhard.schussek@symfony.com>
+ */
+class PhpEngineThemeFactory implements FormThemeFactoryInterface
+{
+    /**
+     * @var PhpEngine
+     */
+    private $engine;
+
+    public function __construct(PhpEngine $engine)
+    {
+        $this->engine = $engine;
+    }
+
+    /**
+     * @see Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface::create()
+     */
+    public function create($template = null)
+    {
+        return new PhpEngineTheme($this->engine, $template);
+    }
+}

+ 8 - 9
src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml

@@ -11,9 +11,9 @@
         <parameter key="form.type.loader.tagged.class">Symfony\Bundle\FrameworkBundle\Form\ContainerAwareTypeLoader</parameter>
         <parameter key="form.guesser.validator.class">Symfony\Component\Form\Type\Guesser\ValidatorTypeGuesser</parameter>
         <parameter key="form.csrf_provider.class">Symfony\Component\Form\CsrfProvider\SessionCsrfProvider</parameter>
-        <parameter key="form.theme.twig.class">Symfony\Component\Form\Renderer\Theme\TwigTheme</parameter>
-        <parameter key="form.theme.php.class">Symfony\Component\Form\Renderer\Theme\PhpTheme</parameter>
-        <parameter key="form.theme.phpengine.class">Symfony\Bundle\FrameworkBundle\Form\PhpEngineTheme</parameter>
+        <parameter key="form.theme.factory.twig.class">Symfony\Component\Form\Renderer\Theme\TwigThemeFactory</parameter>
+        <parameter key="form.theme.factory.php.class">Symfony\Component\Form\Renderer\Theme\PhpThemeFactory</parameter>
+        <parameter key="form.theme.factory.phpengine.class">Symfony\Bundle\FrameworkBundle\Form\PhpEngineThemeFactory</parameter>
         <parameter key="form.theme.template">TwigBundle::div_layout.html.twig</parameter>
         <parameter key="form.factory.class">Symfony\Component\Form\FormFactory</parameter>
         <parameter key="form.csrf_protection.enabled">true</parameter>
@@ -46,18 +46,16 @@
         </service>
         
         <!-- Themes -->
-        <service id="form.theme.twig" class="%form.theme.twig.class%">
+        <service id="form.theme.factory.twig" class="%form.theme.factory.twig.class%">
             <argument type="service" id="twig" />
-            <argument>%form.theme.template%</argument>
         </service>
 
-        <service id="form.theme.default" class="%form.theme.php.class%">
+        <service id="form.theme.factory.default" class="%form.theme.factory.php.class%">
             <argument>%kernel.charset%</argument>
         </service>
 
-        <service id="form.theme.php" class="%form.theme.phpengine.class%">
+        <service id="form.theme.factory.php" class="%form.theme.factory.phpengine.class%">
             <argument type="service" id="templating.engine.php" />
-            <argument>%form.theme.template%</argument>
         </service>
         
         <!-- TemporaryStorage - where should we put this? -->
@@ -95,8 +93,9 @@
         <!-- FieldTypes -->
         <service id="form.type.field" class="Symfony\Component\Form\Type\FieldType">
             <tag name="form.type" alias="field" />
-            <argument type="service" id="form.theme" />
             <argument type="service" id="validator" />
+            <argument type="service" id="form.theme.factory" />
+            <argument>%form.theme.template%</argument>
         </service>
         <service id="form.type.form" class="Symfony\Component\Form\Type\FormType">
             <tag name="form.type" alias="form" />

+ 2 - 2
src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

@@ -61,8 +61,8 @@ abstract class FrameworkExtensionTest extends TestCase
     {
         $container = $this->createContainerFromFile('full');
 
-        $this->assertTrue($container->hasAlias('form.theme'), '->registerTemplatingConfiguration() aliases a form.theme service.');
-        $this->assertEquals('form.theme.twig', (string)$container->getAlias('form.theme'));
+        $this->assertTrue($container->hasAlias('form.theme.factory'), '->registerTemplatingConfiguration() aliases a form.theme.factory service.');
+        $this->assertEquals('form.theme.factory.twig', (string)$container->getAlias('form.theme.factory'));
     }
 
     /**

+ 28 - 0
src/Symfony/Bundle/FrameworkBundle/Tests/Form/PhpEngineThemeFactoryTest.php

@@ -0,0 +1,28 @@
+<?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\Bundle\FrameworkBundle\Tests\Form;
+
+use Symfony\Bundle\FrameworkBundle\Form\PhpEngineThemeFactory;
+
+class PhpEngineThemeFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    public function testCreate()
+    {
+        $engine = $this->getMockBuilder('Symfony\Component\Templating\PhpEngine')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $factory = new PhpEngineThemeFactory($engine);
+
+        $this->assertInstanceOf('Symfony\Bundle\FrameworkBundle\Form\PhpEngineTheme', $factory->create());
+    }
+}

+ 3 - 3
src/Symfony/Bundle/FrameworkBundle/Tests/Form/PhpEngineThemeFunctionalTest.php

@@ -12,7 +12,7 @@
 namespace Symfony\Bundle\FrameworkBundle\Tests\Form;
 
 use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
-use Symfony\Bundle\FrameworkBundle\Form\PhpEngineTheme;
+use Symfony\Bundle\FrameworkBundle\Form\PhpEngineThemeFactory;
 use Symfony\Component\Form\Type\AbstractFieldType;
 use Symfony\Component\Form\FieldBuilder;
 use Symfony\Component\Form\CsrfProvider\DefaultCsrfProvider;
@@ -25,7 +25,7 @@ use Symfony\Tests\Component\Form\Renderer\Theme\AbstractThemeFunctionalTest;
  */
 class PhpEngineThemeFunctionalTest extends AbstractThemeFunctionalTest
 {
-    protected function createTheme()
+    protected function createThemeFactory()
     {
         $parser = new \Symfony\Component\Templating\TemplateNameParser();
         $loader = new \Symfony\Component\Templating\Loader\FilesystemLoader(__DIR__ . '/../../Resources/views/Form/%name%');
@@ -37,6 +37,6 @@ class PhpEngineThemeFunctionalTest extends AbstractThemeFunctionalTest
                 )
             )
         ));
-        return new PhpEngineTheme($engine);
+        return new PhpEngineThemeFactory($engine);
     }
 }

+ 9 - 8
src/Symfony/Component/Form/DefaultFormFactory.php

@@ -16,10 +16,11 @@ use Symfony\Component\Validator\ValidatorInterface;
 use Symfony\Component\Form\FormFactoryInterface;
 use Symfony\Component\Form\Type;
 use Symfony\Component\Form\Type\FormTypeInterface;
-use Symfony\Component\Form\Renderer\Theme\FormThemeInterface;
+use Symfony\Component\Form\Type\AbstractFieldType;
 use Symfony\Component\Form\Type\Loader\TypeLoaderInterface;
 use Symfony\Component\Form\Type\Loader\DefaultTypeLoader;
-use Symfony\Component\Form\Type\AbstractFieldType;
+use Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface;
+use Symfony\Component\Form\Renderer\Theme\PhpThemeFactory;
 use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface;
 use Symfony\Component\Form\CsrfProvider\DefaultCsrfProvider;
 use Doctrine\ORM\EntityManager;
@@ -47,21 +48,21 @@ class DefaultFormFactory extends FormFactory
     {
         $csrfProvider = new DefaultCsrfProvider($csrfSecret);
         $tempStorage = new TemporaryStorage($storageSecret);
-        $defaultTheme = new PhpTheme($charset);
-        return self::createInstance($defaultTheme, $validator, $csrfProvider, $tempStorage, $entityManager);
+        $defaultThemeFactory = new PhpThemeFactory($charset);
+        return self::createInstance($defaultThemeFactory, $validator, $csrfProvider, $tempStorage, $entityManager);
     }
 
     /**
      * Factory method to simplify creation of a default form factory.
-     * 
-     * @param FormThemeInterface $theme
+     *
+     * @param FormThemeFactoryInterface $themeFactory
      * @param ValidatorInterface $validator
      * @param CsrfProviderInterface $crsfProvider
      * @param TemporaryStorage $tempStorage
      * @param \Doctrine\ORM\EntityManager $entityManager
      * @return DefaultFormFactory
      */
-    public static function createInstance(FormThemeInterface $theme,
+    public static function createInstance(FormThemeFactoryInterface $themeFactory,
             ValidatorInterface $validator,
             CsrfProviderInterface $crsfProvider,
             TemporaryStorage $tempStorage,
@@ -69,7 +70,7 @@ class DefaultFormFactory extends FormFactory
     {
         $typeLoader = new DefaultTypeLoader();
         $factory = new self($typeLoader);
-        $typeLoader->initialize($factory, $theme, $crsfProvider, $validator, $tempStorage, $entityManager);
+        $typeLoader->initialize($factory, $themeFactory, null, $crsfProvider, $validator, $tempStorage, $entityManager);
 
         return $factory;
     }

+ 17 - 0
src/Symfony/Component/Form/Renderer/Theme/FormThemeFactoryInterface.php

@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Renderer\Theme;
+
+interface FormThemeFactoryInterface
+{
+    function create($template = null);
+}

+ 44 - 0
src/Symfony/Component/Form/Renderer/Theme/PhpThemeFactory.php

@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Renderer\Theme;
+
+use Symfony\Component\Form\Exception\FormException;
+
+/**
+ * Creates PhpTheme instances
+ *
+ * @author Bernhard Schussek <bernhard.schussek@symfony.com>
+ */
+class PhpThemeFactory implements FormThemeFactoryInterface
+{
+    /**
+     * @var string
+     */
+    private $charset;
+
+    public function __construct($charset = 'UTF-8')
+    {
+        $this->charset = $charset;
+    }
+
+    /**
+     * @see Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface::create()
+     */
+    public function create($template = null)
+    {
+        if ($template !== null) {
+            throw new FormException('PHP don\'t accept templates');
+        }
+
+        return new PhpTheme($this->charset);
+    }
+}

+ 44 - 0
src/Symfony/Component/Form/Renderer/Theme/TwigThemeFactory.php

@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Renderer\Theme;
+
+use Symfony\Component\Form\Exception\FormException;
+
+/**
+ * Creates TwigTheme instances
+ *
+ * @author Bernhard Schussek <bernhard.schussek@symfony.com>
+ */
+class TwigThemeFactory implements FormThemeFactoryInterface
+{
+    /**
+     * @var Twig_Environment
+     */
+    private $environment;
+
+    public function __construct(\Twig_Environment $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    /**
+     * @see Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface::create()
+     */
+    public function create($template = null)
+    {
+        if ($template === null) {
+            throw new FormException('Twig themes expect a template');
+        }
+
+        return new TwigTheme($this->environment, $template);
+    }
+}

+ 27 - 8
src/Symfony/Component/Form/Renderer/ThemeRenderer.php

@@ -13,13 +13,16 @@ namespace Symfony\Component\Form\Renderer;
 
 use Symfony\Component\Form\FormInterface;
 use Symfony\Component\Form\Renderer\Theme\FormThemeInterface;
+use Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface;
 use Symfony\Component\Form\Renderer\Plugin\FormRendererPluginInterface;
 
 class ThemeRenderer implements FormRendererInterface, \ArrayAccess
 {
     private $form;
 
-    private $template;
+    private $block;
+
+    private $themeFactory;
 
     private $theme;
 
@@ -36,16 +39,17 @@ class ThemeRenderer implements FormRendererInterface, \ArrayAccess
      * Row implicitly includes widget, however certain rendering mechanisms
      * have to skip widget rendering when a row is rendered.
      *
-     * @var bool
+     * @var Boolean
      */
     private $rendered = false;
 
     private $children = array();
 
-    public function __construct(FormThemeInterface $theme, $template)
+    public function __construct(FormThemeFactoryInterface $themeFactory, $template = null)
     {
-        $this->theme = $theme;
-        $this->template = $template;
+        $this->themeFactory = $themeFactory;
+
+        $this->setTemplate($template);
     }
 
     public function __clone()
@@ -86,6 +90,11 @@ class ThemeRenderer implements FormRendererInterface, \ArrayAccess
         $this->children = $renderers;
     }
 
+    public function setTemplate($template)
+    {
+        $this->setTheme($this->themeFactory->create($template));
+    }
+
     public function setTheme(FormThemeInterface $theme)
     {
         $this->theme = $theme;
@@ -96,6 +105,16 @@ class ThemeRenderer implements FormRendererInterface, \ArrayAccess
         return $this->theme;
     }
 
+    public function setBlock($block)
+    {
+        $this->block = $block;
+    }
+
+    public function getBlock()
+    {
+        return $this->block;
+    }
+
     public function addPlugin(FormRendererPluginInterface $plugin)
     {
         $this->initialized = false;
@@ -162,7 +181,7 @@ class ThemeRenderer implements FormRendererInterface, \ArrayAccess
      * Renders the label of the given form
      *
      * @param FormInterface $form  The form to render the label for
-     * @param array $params          Additional variables passed to the template
+     * @param array $params          Additional variables passed to the block
      */
     public function getLabel($label = null, array $vars = array())
     {
@@ -178,11 +197,11 @@ class ThemeRenderer implements FormRendererInterface, \ArrayAccess
         return $this->render('enctype', $this->vars);
     }
 
-    protected function render($block, array $vars = array())
+    protected function render($part, array $vars = array())
     {
         $this->initialize();
 
-        return $this->theme->render($this->template, $block, array_replace(
+        return $this->theme->render($this->block, $part, array_replace(
             $this->vars,
             $vars
         ));

+ 12 - 6
src/Symfony/Component/Form/Type/FieldType.php

@@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Type;
 use Symfony\Component\Form\PropertyPath;
 use Symfony\Component\Form\FormBuilder;
 use Symfony\Component\Form\Renderer\ThemeRenderer;
-use Symfony\Component\Form\Renderer\Theme\FormThemeInterface;
+use Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface;
 use Symfony\Component\Form\Renderer\Plugin\FieldPlugin;
 use Symfony\Component\Form\EventListener\TrimListener;
 use Symfony\Component\Form\EventListener\ValidationListener;
@@ -26,14 +26,17 @@ use Symfony\Component\Validator\ValidatorInterface;
 
 class FieldType extends AbstractType
 {
-    private $theme;
-
     private $validator;
 
-    public function __construct(FormThemeInterface $theme, ValidatorInterface $validator)
+    private $themeFactory;
+
+    private $template;
+
+    public function __construct(ValidatorInterface $validator, FormThemeFactoryInterface $themeFactory, $template = null)
     {
-        $this->theme = $theme;
         $this->validator = $validator;
+        $this->themeFactory = $themeFactory;
+        $this->template = $template;
     }
 
     public function configure(FormBuilder $builder, array $options)
@@ -52,6 +55,9 @@ class FieldType extends AbstractType
             ? null
             : (array)$options['validation_groups'];
 
+        $renderer = new ThemeRenderer($this->themeFactory, $this->template);
+        $renderer->setBlock($options['template']);
+
         $builder->setRequired($options['required'])
             ->setReadOnly($options['read_only'])
             ->setErrorBubbling($options['error_bubbling'])
@@ -60,7 +66,7 @@ class FieldType extends AbstractType
             ->setAttribute('validation_groups', $options['validation_groups'])
             ->setAttribute('error_mapping', $options['error_mapping'])
             ->setData($options['data'])
-            ->setRenderer(new ThemeRenderer($this->theme, $options['template']))
+            ->setRenderer($renderer)
             ->addRendererPlugin(new FieldPlugin())
             ->addValidator(new DefaultValidator())
             ->addValidator(new DelegatingValidator($this->validator));

+ 5 - 5
src/Symfony/Component/Form/Type/Loader/DefaultTypeLoader.php

@@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Type\Loader;
 use Symfony\Component\Form\FormFactoryInterface;
 use Symfony\Component\Form\Type;
 use Symfony\Component\Form\Type\FormTypeInterface;
-use Symfony\Component\Form\Renderer\Theme\FormThemeInterface;
+use Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface;
 use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface;
 use Symfony\Component\Validator\ValidatorInterface;
 use Symfony\Component\HttpFoundation\File\TemporaryStorage;
@@ -25,11 +25,11 @@ class DefaultTypeLoader implements TypeLoaderInterface
     private $types = array();
 
     public function initialize(FormFactoryInterface $factory,
-            FormThemeInterface $theme, CsrfProviderInterface $csrfProvider,
-            ValidatorInterface $validator, TemporaryStorage $storage,
-            EntityManager $em = null)
+            FormThemeFactoryInterface $themeFactory, $template,
+            CsrfProviderInterface $csrfProvider, ValidatorInterface $validator,
+            TemporaryStorage $storage, EntityManager $em = null)
     {
-        $this->addType(new Type\FieldType($theme, $validator));
+        $this->addType(new Type\FieldType($validator, $themeFactory, $template));
         $this->addType(new Type\FormType());
         $this->addType(new Type\BirthdayType());
         $this->addType(new Type\CheckboxType());

+ 8 - 3
tests/Symfony/Tests/Component/Form/Renderer/Theme/AbstractThemeFunctionalTest.php

@@ -25,11 +25,16 @@ abstract class AbstractThemeFunctionalTest extends \PHPUnit_Framework_TestCase
     /** @var FormFactory */
     private $factory;
 
-    abstract protected function createTheme();
+    abstract protected function createThemeFactory();
+
+    protected function getTemplate()
+    {
+    }
 
     public function setUp()
     {
-        $theme = $this->createTheme();
+        $themeFactory = $this->createThemeFactory();
+        $template = $this->getTemplate();
         $csrfProvider = new DefaultCsrfProvider('foo');
         $validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
         $storage = new \Symfony\Component\HttpFoundation\File\TemporaryStorage('foo', 1, \sys_get_temp_dir());
@@ -37,7 +42,7 @@ abstract class AbstractThemeFunctionalTest extends \PHPUnit_Framework_TestCase
         // ok more than 2 lines, see DefaultFormFactory.php for proposed simplication
         $typeLoader = new DefaultTypeLoader();
         $this->factory = new FormFactory($typeLoader);
-        $typeLoader->initialize($this->factory, $theme, $csrfProvider, $validator , $storage);
+        $typeLoader->initialize($this->factory, $themeFactory, $template, $csrfProvider, $validator , $storage);
         // this is the relevant bit about your own forms:
         $typeLoader->addType(new MyTestFormConfig());
         $typeLoader->addType(new MyTestSubFormConfig());

+ 39 - 0
tests/Symfony/Tests/Component/Form/Renderer/Theme/PhpThemeFactoryTest.php

@@ -0,0 +1,39 @@
+<?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\Tests\Component\Form\Renderer\Theme;
+
+use Symfony\Component\Form\Renderer\Theme\PhpThemeFactory;
+
+class PhpThemeFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    private $factory;
+
+    protected function setUp()
+    {
+        $this->factory = new PhpThemeFactory();
+    }
+
+    public function testCreate()
+    {
+        $theme = $this->factory->create();
+
+        $this->assertInstanceOf('Symfony\Component\Form\Renderer\Theme\PhpTheme', $theme);
+    }
+
+    /**
+     * @expectedException Symfony\Component\Form\Exception\FormException
+     */
+    public function testCreateDoesNotAcceptParams()
+    {
+        $this->factory->create('foobar');
+    }
+}

+ 3 - 3
tests/Symfony/Tests/Component/Form/Renderer/Theme/PhpThemeFunctionalTest.php

@@ -11,15 +11,15 @@
 
 namespace Symfony\Tests\Component\Form\Renderer\Theme;
 
-use Symfony\Component\Form\Renderer\Theme\PhpTheme;
+use Symfony\Component\Form\Renderer\Theme\PhpThemeFactory;
 
 /**
  * Test theme template files shipped with framework bundle.
  */
 class PhpThemeFunctionalTest extends AbstractThemeFunctionalTest
 {
-    protected function createTheme()
+    protected function createThemeFactory()
     {
-        return new PhpTheme();
+        return new PhpThemeFactory();
     }
 }

+ 42 - 0
tests/Symfony/Tests/Component/Form/Renderer/Theme/TwigThemeFactoryTest.php

@@ -0,0 +1,42 @@
+<?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\Tests\Component\Form\Renderer\Theme;
+
+use Symfony\Component\Form\Renderer\Theme\TwigThemeFactory;
+
+class TwigThemeFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    private $factory;
+
+    protected function setUp()
+    {
+        $environment = $this->getMockBuilder('Twig_Environment')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->factory = new TwigThemeFactory($environment);
+    }
+
+    public function testCreate()
+    {
+        $theme = $this->factory->create('template');
+
+        $this->assertInstanceOf('Symfony\Component\Form\Renderer\Theme\TwigTheme', $theme);
+    }
+
+    /**
+     * @expectedException Symfony\Component\Form\Exception\FormException
+     */
+    public function testCreateRequiresParams()
+    {
+        $this->factory->create();
+    }
+}

+ 6 - 3
tests/Symfony/Tests/Component/Form/Type/TestCase.php

@@ -18,7 +18,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
 
 abstract class TestCase extends \PHPUnit_Framework_TestCase
 {
-    protected $theme;
+    protected $themeFactory;
 
     protected $csrfProvider;
 
@@ -36,7 +36,10 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->theme = $this->getMock('Symfony\Component\Form\Renderer\Theme\FormThemeInterface');
+        $this->themeFactory = $this->getMock('Symfony\Component\Form\Renderer\Theme\FormThemeFactoryInterface');
+        $this->themeFactory->expects($this->any())
+            ->method('create')
+            ->will($this->returnValue($this->getMock('Symfony\Component\Form\Renderer\Theme\FormThemeInterface')));
         $this->csrfProvider = $this->getMock('Symfony\Component\Form\CsrfProvider\CsrfProviderInterface');
         $this->validator = $this->getMock('Symfony\Component\Validator\ValidatorInterface');
         $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
@@ -49,7 +52,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
             ->getMock();
         $loader = new DefaultTypeLoader();
         $this->factory = new FormFactory($loader);
-        $loader->initialize($this->factory, $this->theme, $this->csrfProvider,
+        $loader->initialize($this->factory, $this->themeFactory, null, $this->csrfProvider,
                 $this->validator, $this->storage, $this->em);
 
         $this->builder = new FormBuilder($this->dispatcher);