Skip to content

[Form] WIP Improved performance of form building #4882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 13, 2012
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[Form] Cached the form type hierarchy in order to improve performance
  • Loading branch information
webmozart committed Jul 13, 2012
commit cd7835d8d2f68de96d3d4d33e9b744c86d519a8f
28 changes: 28 additions & 0 deletions UPGRADE-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@
public function finishView(FormViewInterface $view, FormInterface $form, array $options)
```

* The method `createBuilder` was removed from `FormTypeInterface` for performance
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 previously inherited from `FieldType`, you should now inherit from
`FormType`. You should also set the option `compound` to `false` if your field
is not supposed to contain child fields.
Expand Down Expand Up @@ -1001,6 +1011,24 @@
));
```

* The methods `addType`, `hasType` and `getType` in `FormFactory` are deprecated
and will be removed in Symfony 2.3. You should use the methods with the same
name on the `FormRegistry` instead.

Before:

```
$this->get('form.factory')->addType(new MyFormType());
```

After:

```
$registry = $this->get('form.registry');

$registry->addType($registry->resolveType(new MyFormType()));
```

### Validator

* The methods `setMessage()`, `getMessageTemplate()` and
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Doctrine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ CHANGELOG
* added a default implementation of the ManagerRegistry
* added a session storage for Doctrine DBAL
* DoctrineOrmTypeGuesser now guesses "collection" for array Doctrine type
* DoctrineType now caches its choice lists in order to improve performance
10 changes: 8 additions & 2 deletions src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

<parameters>
<parameter key="form.extension.class">Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension</parameter>
<parameter key="form.registry.class">Symfony\Component\Form\FormRegistry</parameter>
<parameter key="form.factory.class">Symfony\Component\Form\FormFactory</parameter>
<parameter key="form.type_guesser.validator.class">Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser</parameter>
</parameters>

<services>
<!-- FormFactory -->
<service id="form.factory" class="%form.factory.class%">
<!-- FormRegistry -->
<service id="form.registry" class="%form.registry.class%">
<argument type="collection">
<!--
We don't need to be able to add more extensions.
Expand All @@ -23,6 +24,11 @@
</argument>
</service>

<!-- FormFactory -->
<service id="form.factory" class="%form.factory.class%">
<argument type="service" id="form.registry" />
</service>

<!-- DependencyInjectionExtension -->
<service id="form.extension" class="%form.extension.class%" public="false">
<argument type="service" id="service_container" />
Expand Down
34 changes: 16 additions & 18 deletions src/Symfony/Component/Form/AbstractType.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
abstract class AbstractType implements FormTypeInterface
{
/**
* The extensions for this type
* @var array An array of FormTypeExtensionInterface instances
* @var array
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
private $extensions = array();

Expand All @@ -46,14 +47,6 @@ public function finishView(FormViewInterface $view, FormInterface $form, array $
{
}

/**
* {@inheritdoc}
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return null;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -98,21 +91,26 @@ public function getParent()
}

/**
* {@inheritdoc}
* Sets the extensions for this type.
*
* @param array $extensions An array of FormTypeExtensionInterface
*
* @throws Exception\UnexpectedTypeException if any extension does not implement FormTypeExtensionInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3.
*/
public function setExtensions(array $extensions)
{
foreach ($extensions as $extension) {
if (!$extension instanceof FormTypeExtensionInterface) {
throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
}
}

$this->extensions = $extensions;
}

/**
* {@inheritdoc}
* Returns the extensions associated with this type.
*
* @return array An array of FormTypeExtensionInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link ResolvedFormTypeInterface::getTypeExtensions()} instead.
*/
public function getExtensions()
{
Expand Down
13 changes: 13 additions & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ CHANGELOG
* `hasAttribute`
* `getClientData`
* added FormBuilder methods
* `getTypes`
* `addViewTransformer`
* `getViewTransformers`
* `resetViewTransformers`
Expand Down Expand Up @@ -157,3 +158,15 @@ 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
* deprecated FormFactory methods
* `addType`
* `hasType`
* `getType`
* [BC BREAK] FormFactory now expects a FormRegistryInterface 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
* `getExtensions`
* `setExtensions`
* ChoiceType now caches its created choice lists to improve performance
13 changes: 2 additions & 11 deletions src/Symfony/Component/Form/Extension/Core/Type/FormType.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Symfony\Component\Form\Extension\Core\EventListener\BindRequestListener;
use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
Expand Down Expand Up @@ -93,8 +92,8 @@ public function buildView(FormViewInterface $view, FormInterface $form, array $o
}

$types = array();
foreach ($form->getConfig()->getTypes() as $type) {
$types[] = $type->getName();
for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
array_unshift($types, $type->getName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to duplicate Form::getTypes(). Is there any reason you're not just calling that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Form::getTypes() is deprecated.

}

if (!$translationDomain) {
Expand Down Expand Up @@ -211,14 +210,6 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
));
}

/**
* {@inheritdoc}
*/
public function createBuilder($name, FormFactoryInterface $factory, array $options)
{
return new FormBuilder($name, $options['data_class'], new EventDispatcher(), $factory, $options);
}

/**
* {@inheritdoc}
*/
Expand Down
39 changes: 9 additions & 30 deletions src/Symfony/Component/Form/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,17 @@ public function getPropertyPath()
* @return array An array of FormTypeInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link getConfig()} and {@link FormConfigInterface::getTypes()} instead.
* {@link getConfig()} and {@link FormConfigInterface::getType()} instead.
*/
public function getTypes()
{
return $this->config->getTypes();
$types = array();

for ($type = $this->config->getType(); null !== $type; $type = $type->getParent()) {
array_unshift($types, $type->getInnerType());
}

return $types;
}

/**
Expand Down Expand Up @@ -948,34 +954,7 @@ public function createView(FormViewInterface $parent = null)
$parent = $this->parent->createView();
}

$view = new FormView($this->config->getName());

$view->setParent($parent);

$types = (array) $this->config->getTypes();
$options = $this->config->getOptions();

foreach ($types as $type) {
$type->buildView($view, $this, $options);

foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->buildView($view, $this, $options);
}
}

foreach ($this->children as $child) {
$view->add($child->createView($view));
}

foreach ($types as $type) {
$type->finishView($view, $this, $options);

foreach ($type->getExtensions() as $typeExtension) {
$typeExtension->finishView($view, $this, $options);
}
}

return $view;
return $this->config->getType()->createView($this, $parent);
}

/**
Expand Down
23 changes: 21 additions & 2 deletions src/Symfony/Component/Form/FormBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ public function create($name, $type = null, array $options = array())
}

if (null !== $type) {
return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options, $this);
return $this->factory->createNamedBuilder($name, $type, null, $options, $this);
}

return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options, $this);
return $this->factory->createBuilderForProperty($this->getDataClass(), $name, null, $options, $this);
}

/**
Expand Down Expand Up @@ -266,4 +266,23 @@ public function getIterator()
{
return new \ArrayIterator($this->children);
}

/**
* Returns the types used by this builder.
*
* @return array An array of FormTypeInterface
*
* @deprecated Deprecated since version 2.1, to be removed in 2.3. Use
* {@link FormConfigInterface::getType()} instead.
*/
public function getTypes()
{
$types = array();

for ($type = $this->getType(); null !== $type; $type = $type->getParent()) {
array_unshift($types, $type->getInnerType());
}

return $types;
}
}
12 changes: 6 additions & 6 deletions src/Symfony/Component/Form/FormConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class FormConfig implements FormConfigEditorInterface
private $compound = false;

/**
* @var array
* @var ResolvedFormTypeInterface
*/
private $types = array();
private $type;

/**
* @var array
Expand Down Expand Up @@ -377,9 +377,9 @@ public function getCompound()
/**
* {@inheritdoc}
*/
public function getTypes()
public function getType()
{
return $this->types;
return $this->type;
}

/**
Expand Down Expand Up @@ -671,9 +671,9 @@ public function setCompound($compound)
/**
* {@inheritdoc}
*/
public function setTypes(array $types)
public function setType(ResolvedFormTypeInterface $type)
{
$this->types = $types;
$this->type = $type;

return $this;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Form/FormConfigEditorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,11 @@ public function setCompound($compound);
/**
* Set the types.
*
* @param array $types An array FormTypeInterface
* @param ResolvedFormTypeInterface $type The type of the form.
*
* @return self The configuration object.
*/
public function setTypes(array $types);
public function setType(ResolvedFormTypeInterface $type);

/**
* Sets the initial data of the form.
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Component/Form/FormConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ public function getCompound();
/**
* Returns the form types used to construct the form.
*
* @return array An array of {@link FormTypeInterface} instances.
* @return ResolvedFormTypeInterface The form's type.
*/
public function getTypes();
public function getType();

/**
* Returns the view transformers of the form.
Expand Down
Loading