[Form] Fixed FormValidator::findClickedButton() not to be called exponentially

This commit is contained in:
Bernhard Schussek 2013-09-10 15:56:14 +02:00
parent a672bba5cb
commit b65a51519d
2 changed files with 80 additions and 1 deletions

View File

@ -22,6 +22,11 @@ use Symfony\Component\Validator\ConstraintValidator;
*/
class FormValidator extends ConstraintValidator
{
/**
* @var \SplObjectStorage
*/
private static $clickedButtons;
/**
* @var ServerParams
*/
@ -47,6 +52,16 @@ class FormValidator extends ConstraintValidator
return;
}
if (null === static::$clickedButtons) {
static::$clickedButtons = new \SplObjectStorage();
}
// If the form was previously validated, remove it from the cache in
// case the clicked button has changed
if (static::$clickedButtons->contains($form)) {
static::$clickedButtons->detach($form);
}
/* @var FormInterface $form */
$config = $form->getConfig();
@ -172,7 +187,17 @@ class FormValidator extends ConstraintValidator
*/
private static function getValidationGroups(FormInterface $form)
{
$button = self::findClickedButton($form->getRoot());
$root = $form->getRoot();
// Determine the clicked button of the complete form tree
if (!static::$clickedButtons->contains($root)) {
// Only call findClickedButton() once to prevent an exponential
// runtime
// https://github.com/symfony/symfony/issues/8317
static::$clickedButtons->attach($root, self::findClickedButton($root));
}
$button = static::$clickedButtons->offsetGet($root);
if (null !== $button) {
$groups = $button->getConfig()->getOption('validation_groups');

View File

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Tests\Extension\Validator\Constraints;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\Test\FormPerformanceTestCase;
use Symfony\Component\Validator\Validation;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class FormValidatorPerformanceTest extends FormPerformanceTestCase
{
protected function getExtensions()
{
return array(
new ValidatorExtension(Validation::createValidator()),
);
}
/**
* findClickedButton() used to have an exponential number of calls
*
* @group benchmark
*/
public function testValidationPerformance()
{
$this->setMaxRunningTime(1);
$builder = $this->factory->createBuilder('form');
for ($i = 0; $i < 100; ++$i) {
$builder->add($i, 'form');
$builder->get($i)
->add('a')
->add('b')
->add('c');
}
$form = $builder->getForm();
$form->submit(null);
}
}