diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
index bf63332ced..7980131433 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
@@ -151,8 +151,11 @@
+
+
+
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 6da2034731..b417afdbcb 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -56,8 +56,7 @@ class FormType extends BaseType
->setDataLocked($isDataOptionSet)
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
->setMethod($options['method'])
- ->setAction($options['action'])
- ;
+ ->setAction($options['action']);
if ($options['trim']) {
$builder->addEventSubscriber(new TrimListener());
@@ -170,25 +169,26 @@ class FormType extends BaseType
));
$resolver->setDefaults(array(
- 'data_class' => $dataClass,
- 'empty_data' => $emptyData,
- 'trim' => true,
- 'required' => true,
- 'read_only' => false,
- 'max_length' => null,
- 'pattern' => null,
- 'property_path' => null,
- 'mapped' => true,
- 'by_reference' => true,
- 'error_bubbling' => $errorBubbling,
- 'label_attr' => array(),
- 'virtual' => null,
- 'inherit_data' => $inheritData,
- 'compound' => true,
- 'method' => 'POST',
+ 'data_class' => $dataClass,
+ 'empty_data' => $emptyData,
+ 'trim' => true,
+ 'required' => true,
+ 'read_only' => false,
+ 'max_length' => null,
+ 'pattern' => null,
+ 'property_path' => null,
+ 'mapped' => true,
+ 'by_reference' => true,
+ 'error_bubbling' => $errorBubbling,
+ 'label_attr' => array(),
+ 'virtual' => null,
+ 'inherit_data' => $inheritData,
+ 'compound' => true,
+ 'method' => 'POST',
// According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
// section 4.2., empty URIs are considered same-document references
- 'action' => '',
+ 'action' => '',
+ 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
));
$resolver->setAllowedTypes(array(
diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
index 08bd89c9e4..33e9c1c4d4 100644
--- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
+++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationExtension.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\HttpFoundation;
use Symfony\Component\Form\AbstractExtension;
+use Symfony\Component\Form\Util\ServerParams;
/**
* Integrates the HttpFoundation component with the Form library.
@@ -20,10 +21,20 @@ use Symfony\Component\Form\AbstractExtension;
*/
class HttpFoundationExtension extends AbstractExtension
{
+ /**
+ * @var ServerParams
+ */
+ private $serverParams;
+
+ public function __construct(ServerParams $serverParams = null)
+ {
+ $this->serverParams = $serverParams;
+ }
+
protected function loadTypeExtensions()
{
return array(
- new Type\FormTypeHttpFoundationExtension(),
+ new Type\FormTypeHttpFoundationExtension($this->serverParams),
);
}
}
diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
index 2094699481..03805fef52 100644
--- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
+++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
@@ -12,8 +12,10 @@
namespace Symfony\Component\Form\Extension\HttpFoundation;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
+use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\RequestHandlerInterface;
+use Symfony\Component\Form\Util\ServerParams;
use Symfony\Component\HttpFoundation\Request;
/**
@@ -24,6 +26,19 @@ use Symfony\Component\HttpFoundation\Request;
*/
class HttpFoundationRequestHandler implements RequestHandlerInterface
{
+ /**
+ * @var ServerParams
+ */
+ private $serverParams;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ServerParams $serverParams = null)
+ {
+ $this->serverParams = $serverParams ?: new ServerParams();
+ }
+
/**
* {@inheritdoc}
*/
@@ -53,6 +68,25 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface
$data = $request->query->get($name);
}
} else {
+ // Mark the form with an error if the uploaded size was too large
+ // This is done here and not in FormValidator because $_POST is
+ // empty when that error occurs. Hence the form is never submitted.
+ $contentLength = $this->serverParams->getContentLength();
+ $maxContentLength = $this->serverParams->getPostMaxSize();
+
+ if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
+ // Submit the form, but don't clear the default values
+ $form->submit(null, false);
+
+ $form->addError(new FormError(
+ $form->getConfig()->getOption('post_max_size_message'),
+ null,
+ array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
+ ));
+
+ return;
+ }
+
if ('' === $name) {
$params = $request->request->all();
$files = $request->files->all();
diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
index 9b09b05c39..4596f06b98 100644
--- a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
+++ b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
@@ -15,6 +15,7 @@ use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Form\Util\ServerParams;
/**
* @author Bernhard Schussek
@@ -31,10 +32,10 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
*/
private $requestHandler;
- public function __construct()
+ public function __construct(ServerParams $serverParams = null)
{
$this->listener = new BindRequestListener();
- $this->requestHandler = new HttpFoundationRequestHandler();
+ $this->requestHandler = new HttpFoundationRequestHandler($serverParams);
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
index 154e865923..2851016f40 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\Form\Extension\Validator\Constraints;
use Symfony\Component\Form\FormInterface;
-use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
@@ -21,22 +20,6 @@ use Symfony\Component\Validator\ConstraintValidator;
*/
class FormValidator extends ConstraintValidator
{
- /**
- * @var ServerParams
- */
- private $serverParams;
-
- /**
- * Creates a validator with the given server parameters.
- *
- * @param ServerParams $params The server parameters. Default
- * parameters are created if null.
- */
- public function __construct(ServerParams $params = null)
- {
- $this->serverParams = $params ?: new ServerParams();
- }
-
/**
* {@inheritdoc}
*/
@@ -113,21 +96,6 @@ class FormValidator extends ConstraintValidator
$form->getExtraData()
);
}
-
- // Mark the form with an error if the uploaded size was too large
- $length = $this->serverParams->getContentLength();
-
- if ($form->isRoot() && null !== $length) {
- $max = $this->serverParams->getPostMaxSize();
-
- if (!empty($max) && $length > $max) {
- $this->context->addViolation(
- $config->getOption('post_max_size_message'),
- array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
- $length
- );
- }
- }
}
/**
diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
index 344bddadc1..ae39af66fc 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
@@ -66,7 +66,6 @@ class FormTypeValidatorExtension extends BaseValidatorExtension
'invalid_message' => 'This value is not valid.',
'invalid_message_parameters' => array(),
'extra_fields_message' => 'This form should not contain extra fields.',
- 'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
));
$resolver->setNormalizers(array(
diff --git a/src/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php b/src/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
index 58fdc25e22..c058d60cae 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Util/ServerParams.php
@@ -14,59 +14,6 @@ namespace Symfony\Component\Form\Extension\Validator\Util;
/**
* @author Bernhard Schussek
*/
-class ServerParams
+class ServerParams extends \Symfony\Component\Form\Util\ServerParams
{
- /**
- * Returns maximum post size in bytes.
- *
- * @return null|int The maximum post size in bytes
- */
- public function getPostMaxSize()
- {
- $iniMax = strtolower($this->getNormalizedIniPostMaxSize());
-
- if ('' === $iniMax) {
- return;
- }
-
- $max = ltrim($iniMax, '+');
- if (0 === strpos($max, '0x')) {
- $max = intval($max, 16);
- } elseif (0 === strpos($max, '0')) {
- $max = intval($max, 8);
- } else {
- $max = intval($max);
- }
-
- switch (substr($iniMax, -1)) {
- case 't': $max *= 1024;
- case 'g': $max *= 1024;
- case 'm': $max *= 1024;
- case 'k': $max *= 1024;
- }
-
- return $max;
- }
-
- /**
- * Returns the normalized "post_max_size" ini setting.
- *
- * @return string
- */
- public function getNormalizedIniPostMaxSize()
- {
- return strtoupper(trim(ini_get('post_max_size')));
- }
-
- /**
- * Returns the content length of the request.
- *
- * @return mixed The request content length.
- */
- public function getContentLength()
- {
- return isset($_SERVER['CONTENT_LENGTH'])
- ? (int) $_SERVER['CONTENT_LENGTH']
- : null;
- }
}
diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php
index fefe546af8..9df9066886 100644
--- a/src/Symfony/Component/Form/NativeRequestHandler.php
+++ b/src/Symfony/Component/Form/NativeRequestHandler.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
+use Symfony\Component\Form\Util\ServerParams;
/**
* A request handler using PHP's super globals $_GET, $_POST and $_SERVER.
@@ -20,6 +21,19 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException;
*/
class NativeRequestHandler implements RequestHandlerInterface
{
+ /**
+ * @var ServerParams
+ */
+ private $serverParams;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(ServerParams $params = null)
+ {
+ $this->serverParams = $params ?: new ServerParams();
+ }
+
/**
* The allowed keys of the $_FILES array.
*
@@ -62,6 +76,25 @@ class NativeRequestHandler implements RequestHandlerInterface
$data = $_GET[$name];
}
} else {
+ // Mark the form with an error if the uploaded size was too large
+ // This is done here and not in FormValidator because $_POST is
+ // empty when that error occurs. Hence the form is never submitted.
+ $contentLength = $this->serverParams->getContentLength();
+ $maxContentLength = $this->serverParams->getPostMaxSize();
+
+ if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
+ // Submit the form, but don't clear the default values
+ $form->submit(null, false);
+
+ $form->addError(new FormError(
+ $form->getConfig()->getOption('post_max_size_message'),
+ null,
+ array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize())
+ ));
+
+ return;
+ }
+
$fixedFiles = array();
foreach ($_FILES as $name => $file) {
$fixedFiles[$name] = self::stripEmptyFiles(self::fixPhpFilesArray($file));
diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
index fbba16ba17..b017db90d0 100644
--- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
@@ -11,21 +11,38 @@
namespace Symfony\Component\Form\Tests;
+use Symfony\Component\Form\FormError;
+use Symfony\Component\Form\FormFactory;
+use Symfony\Component\Form\Forms;
+use Symfony\Component\Form\RequestHandlerInterface;
+
/**
* @author Bernhard Schussek
*/
abstract class AbstractRequestHandlerTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var \Symfony\Component\Form\RequestHandlerInterface
+ * @var RequestHandlerInterface
*/
protected $requestHandler;
+ /**
+ * @var FormFactory
+ */
+ protected $factory;
+
protected $request;
+ protected $serverParams;
+
protected function setUp()
{
+ $this->serverParams = $this->getMock(
+ 'Symfony\Component\Form\Util\ServerParams',
+ array('getNormalizedIniPostMaxSize', 'getContentLength')
+ );
$this->requestHandler = $this->getRequestHandler();
+ $this->factory = Forms::createFormFactoryBuilder()->getFormFactory();
$this->request = null;
}
@@ -249,6 +266,50 @@ abstract class AbstractRequestHandlerTest extends \PHPUnit_Framework_TestCase
$this->requestHandler->handleRequest($form, $this->request);
}
+ /**
+ * @dataProvider getPostMaxSizeFixtures
+ */
+ public function testAddFormErrorIfPostMaxSizeExceeded($contentLength, $iniMax, $shouldFail, array $errorParams = array())
+ {
+ $this->serverParams->expects($this->once())
+ ->method('getContentLength')
+ ->will($this->returnValue($contentLength));
+ $this->serverParams->expects($this->any())
+ ->method('getNormalizedIniPostMaxSize')
+ ->will($this->returnValue($iniMax));
+
+ $options = array('post_max_size_message' => 'Max {{ max }}!');
+ $form = $this->factory->createNamed('name', 'text', null, $options);
+ $this->setRequestData('POST', array(), array());
+
+ $this->requestHandler->handleRequest($form, $this->request);
+
+ if ($shouldFail) {
+ $errors = array(new FormError($options['post_max_size_message'], null, $errorParams));
+
+ $this->assertEquals($errors, $form->getErrors());
+ $this->assertTrue($form->isSubmitted());
+ } else {
+ $this->assertCount(0, $form->getErrors());
+ $this->assertFalse($form->isSubmitted());
+ }
+ }
+
+ public function getPostMaxSizeFixtures()
+ {
+ return array(
+ array(pow(1024, 3) + 1, '1G', true, array('{{ max }}' => '1G')),
+ array(pow(1024, 3), '1G', false),
+ array(pow(1024, 2) + 1, '1M', true, array('{{ max }}' => '1M')),
+ array(pow(1024, 2), '1M', false),
+ array(1024 + 1, '1K', true, array('{{ max }}' => '1K')),
+ array(1024, '1K', false),
+ array(null, '1K', false),
+ array(1024, '', false),
+ array(1024, 0, false),
+ );
+ }
+
abstract protected function setRequestData($method, $data, $files = array());
abstract protected function getRequestHandler();
diff --git a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php
index cf5d63d90e..dcd26891c1 100644
--- a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php
@@ -43,7 +43,7 @@ class HttpFoundationRequestHandlerTest extends AbstractRequestHandlerTest
protected function getRequestHandler()
{
- return new HttpFoundationRequestHandler();
+ return new HttpFoundationRequestHandler($this->serverParams);
}
protected function getMockFile()
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
index 19d5cec9f4..8032d6273d 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php
@@ -542,69 +542,6 @@ class FormValidatorTest extends AbstractConstraintValidatorTest
), 'property.path', array('foo' => 'bar'));
}
- /**
- * @dataProvider getPostMaxSizeFixtures
- */
- public function testPostMaxSizeViolation($contentLength, $iniMax, $nbViolation, array $params = array())
- {
- $this->serverParams->expects($this->once())
- ->method('getContentLength')
- ->will($this->returnValue($contentLength));
- $this->serverParams->expects($this->any())
- ->method('getNormalizedIniPostMaxSize')
- ->will($this->returnValue($iniMax));
-
- $options = array('post_max_size_message' => 'Max {{ max }}!');
- $form = $this->getBuilder('name', null, $options)->getForm();
-
- $this->validator->validate($form, new Form());
-
- $violations = array();
-
- for ($i = 0; $i < $nbViolation; ++$i) {
- $violations[] = $this->createViolation($options['post_max_size_message'], $params, 'property.path', $contentLength);
- }
-
- $this->assertViolations($violations);
- }
-
- public function getPostMaxSizeFixtures()
- {
- return array(
- array(pow(1024, 3) + 1, '1G', 1, array('{{ max }}' => '1G')),
- array(pow(1024, 3), '1G', 0),
- array(pow(1024, 2) + 1, '1M', 1, array('{{ max }}' => '1M')),
- array(pow(1024, 2), '1M', 0),
- array(1024 + 1, '1K', 1, array('{{ max }}' => '1K')),
- array(1024, '1K', 0),
- array(null, '1K', 0),
- array(1024, '', 0),
- array(1024, 0, 0),
- );
- }
-
- public function testNoViolationIfNotRoot()
- {
- $this->serverParams->expects($this->once())
- ->method('getContentLength')
- ->will($this->returnValue(1025));
- $this->serverParams->expects($this->never())
- ->method('getNormalizedIniPostMaxSize');
-
- $parent = $this->getBuilder()
- ->setCompound(true)
- ->setDataMapper($this->getDataMapper())
- ->getForm();
- $form = $this->getForm();
- $parent->add($form);
-
- $this->expectNoValidate();
-
- $this->validator->validate($form, new Form());
-
- $this->assertNoViolation();
- }
-
/**
* Access has to be public, as this method is called via callback array
* in {@link testValidateFormDataCanHandleCallbackValidationGroups()}
diff --git a/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php
index 02b0a4ed74..eac767f8c8 100644
--- a/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php
+++ b/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php
@@ -203,7 +203,7 @@ class NativeRequestHandlerTest extends AbstractRequestHandlerTest
protected function getRequestHandler()
{
- return new NativeRequestHandler();
+ return new NativeRequestHandler($this->serverParams);
}
protected function getMockFile()
diff --git a/src/Symfony/Component/Form/Util/ServerParams.php b/src/Symfony/Component/Form/Util/ServerParams.php
new file mode 100644
index 0000000000..3b1f835182
--- /dev/null
+++ b/src/Symfony/Component/Form/Util/ServerParams.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Util;
+
+/**
+ * @author Bernhard Schussek
+ */
+class ServerParams
+{
+ /**
+ * Returns maximum post size in bytes.
+ *
+ * @return null|int The maximum post size in bytes
+ */
+ public function getPostMaxSize()
+ {
+ $iniMax = strtolower($this->getNormalizedIniPostMaxSize());
+
+ if ('' === $iniMax) {
+ return;
+ }
+
+ $max = ltrim($iniMax, '+');
+ if (0 === strpos($max, '0x')) {
+ $max = intval($max, 16);
+ } elseif (0 === strpos($max, '0')) {
+ $max = intval($max, 8);
+ } else {
+ $max = intval($max);
+ }
+
+ switch (substr($iniMax, -1)) {
+ case 't': $max *= 1024;
+ case 'g': $max *= 1024;
+ case 'm': $max *= 1024;
+ case 'k': $max *= 1024;
+ }
+
+ return $max;
+ }
+
+ /**
+ * Returns the normalized "post_max_size" ini setting.
+ *
+ * @return string
+ */
+ public function getNormalizedIniPostMaxSize()
+ {
+ return strtoupper(trim(ini_get('post_max_size')));
+ }
+
+ /**
+ * Returns the content length of the request.
+ *
+ * @return mixed The request content length.
+ */
+ public function getContentLength()
+ {
+ return isset($_SERVER['CONTENT_LENGTH'])
+ ? (int) $_SERVER['CONTENT_LENGTH']
+ : null;
+ }
+}