Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ecb52bc

Browse filesBrowse files
Merge branch '3.4' into 4.2
* 3.4: fix translating file validation error message [Validator] Add missing Hungarian translations [3.4] [Validator] Add missing french validation translations. [Validator] Only traverse arrays that are cascaded into Handle case where no translations were found [Validator] Translate unique collection message to Hungarian fix tests Run test in separate process Use a class name that does not actually exist fix horizontal spacing of inlined Bootstrap forms [Translator] Warm up the translations cache in dev turn failed file uploads into form errors
2 parents ff3649b + c82e2df commit ecb52bc
Copy full SHA for ecb52bc

File tree

21 files changed

+455
-51
lines changed
Filter options

21 files changed

+455
-51
lines changed

‎src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@
112112
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
113113
{%- endif -%}
114114
<div class="form-group{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
115-
{{- form_label(form) -}}
116-
{{- form_widget(form, widget_attr) -}}
117-
{{- form_help(form) -}}
118-
{{- form_errors(form) -}}
119-
</div>
115+
{{- form_label(form) }} {# -#}
116+
{{ form_widget(form, widget_attr) }} {# -#}
117+
{{ form_widget(form) }} {# -#}
118+
{{ form_errors(form) }} {# -#}
119+
</div> {# -#}
120120
{%- endblock form_row %}
121121

122122
{% block button_row -%}

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
<tag name="form.type" />
7171
<argument type="service" id="form.choice_list_factory"/>
7272
</service>
73+
<service id="form.type.file" class="Symfony\Component\Form\Extension\Core\Type\FileType" public="true">
74+
<argument type="service" id="translator" on-invalid="ignore" />
75+
</service>
7376

7477
<service id="form.type_extension.form.transformation_failure_handling" class="Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension">
7578
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />

‎src/Symfony/Component/BrowserKit/Tests/ClientTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/BrowserKit/Tests/ClientTest.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,9 @@ public function testRestart()
778778
$this->assertEquals([], $client->getCookieJar()->all(), '->restart() clears the cookies');
779779
}
780780

781+
/**
782+
* @runInSeparateProcess
783+
*/
781784
public function testInsulatedRequests()
782785
{
783786
$client = new TestClient();

‎src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ public function testHandleFatalError()
481481

482482
public function testHandleErrorException()
483483
{
484-
$exception = new \Error("Class 'Foo' not found");
484+
$exception = new \Error("Class 'IReallyReallyDoNotExistAnywhereInTheRepositoryISwear' not found");
485485

486486
$handler = new ErrorHandler();
487487
$handler->setExceptionHandler(function () use (&$args) {
@@ -491,7 +491,7 @@ public function testHandleErrorException()
491491
$handler->handleException($exception);
492492

493493
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
494-
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
494+
$this->assertStringStartsWith("Attempted to load class \"IReallyReallyDoNotExistAnywhereInTheRepositoryISwear\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
495495
}
496496

497497
/**

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+7-3Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2626
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
2727
use Symfony\Component\DependencyInjection\Reference;
28+
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
2829
use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic;
2930
use Symfony\Component\DependencyInjection\TypedReference;
30-
use Symfony\Component\HttpKernel\HttpKernelInterface;
3131

3232
require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php';
3333

@@ -547,13 +547,17 @@ public function testSetterInjection()
547547
);
548548
}
549549

550+
/**
551+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
552+
* @exceptedExceptionMessage Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy": method "setLogger()" does not exist.
553+
*/
550554
public function testWithNonExistingSetterAndAutowiring()
551555
{
552556
$container = new ContainerBuilder();
553557

554-
$definition = $container->register(HttpKernelInterface::class, HttpKernelInterface::class)->setAutowired(true);
558+
$definition = $container->register(CaseSensitiveClass::class, CaseSensitiveClass::class)->setAutowired(true);
555559
$definition->addMethodCall('setLogger');
556-
$this->expectException(RuntimeException::class);
560+
557561
(new ResolveClassPass())->process($container);
558562
(new AutowireRequiredMethodsPass())->process($container);
559563
(new AutowirePass())->process($container);

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php
+5-28Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@
1717
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
1919
use Symfony\Component\DependencyInjection\Definition;
20-
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2120
use Symfony\Component\DependencyInjection\Reference;
2221
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
2322
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
2423
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
2524
use Symfony\Component\DependencyInjection\TypedReference;
26-
use Symfony\Component\HttpKernel\HttpKernelInterface;
2725

2826
require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php';
2927

@@ -115,6 +113,10 @@ public function testScalarSetter()
115113
$this->assertEquals([['setDefaultLocale', ['fr']]], $definition->getMethodCalls());
116114
}
117115

116+
/**
117+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
118+
* @exceptedExceptionMessage Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy": method "setLogger()" does not exist.
119+
*/
118120
public function testWithNonExistingSetterAndBinding()
119121
{
120122
$container = new ContainerBuilder();
@@ -123,36 +125,11 @@ public function testWithNonExistingSetterAndBinding()
123125
'$c' => (new Definition('logger'))->setFactory('logger'),
124126
];
125127

126-
$definition = $container->register(HttpKernelInterface::class, HttpKernelInterface::class);
127-
$definition->addMethodCall('setLogger');
128-
$definition->setBindings($bindings);
129-
$this->expectException(RuntimeException::class);
130-
131-
$pass = new ResolveBindingsPass();
132-
$pass->process($container);
133-
}
134-
135-
public function testTupleBinding()
136-
{
137-
$container = new ContainerBuilder();
138-
139-
$bindings = [
140-
'$c' => new BoundArgument(new Reference('bar')),
141-
CaseSensitiveClass::class.'$c' => new BoundArgument(new Reference('foo')),
142-
];
143-
144128
$definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class);
145-
$definition->addMethodCall('setSensitiveClass');
146-
$definition->addMethodCall('setAnotherC');
129+
$definition->addMethodCall('setLogger');
147130
$definition->setBindings($bindings);
148131

149132
$pass = new ResolveBindingsPass();
150133
$pass->process($container);
151-
152-
$expected = [
153-
['setSensitiveClass', [new Reference('foo')]],
154-
['setAnotherC', [new Reference('bar')]],
155-
];
156-
$this->assertEquals($expected, $definition->getMethodCalls());
157134
}
158135
}

‎src/Symfony/Component/Form/Extension/Core/Type/FileType.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/Core/Type/FileType.php
+129Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,33 @@
1313

1414
use Symfony\Component\Form\AbstractType;
1515
use Symfony\Component\Form\FormBuilderInterface;
16+
use Symfony\Component\Form\FormError;
1617
use Symfony\Component\Form\FormEvent;
1718
use Symfony\Component\Form\FormEvents;
1819
use Symfony\Component\Form\FormInterface;
1920
use Symfony\Component\Form\FormView;
2021
use Symfony\Component\OptionsResolver\Options;
2122
use Symfony\Component\OptionsResolver\OptionsResolver;
23+
use Symfony\Component\Translation\TranslatorInterface;
2224

2325
class FileType extends AbstractType
2426
{
27+
const KIB_BYTES = 1024;
28+
const MIB_BYTES = 1048576;
29+
30+
private static $suffixes = [
31+
1 => 'bytes',
32+
self::KIB_BYTES => 'KiB',
33+
self::MIB_BYTES => 'MiB',
34+
];
35+
36+
private $translator;
37+
38+
public function __construct(TranslatorInterface $translator = null)
39+
{
40+
$this->translator = $translator;
41+
}
42+
2543
/**
2644
* {@inheritdoc}
2745
*/
@@ -43,6 +61,10 @@ public function buildForm(FormBuilderInterface $builder, array $options)
4361
foreach ($files as $file) {
4462
if ($requestHandler->isFileUpload($file)) {
4563
$data[] = $file;
64+
65+
if (method_exists($requestHandler, 'getUploadFileError') && null !== $errorCode = $requestHandler->getUploadFileError($file)) {
66+
$form->addError($this->getFileUploadError($errorCode));
67+
}
4668
}
4769
}
4870

@@ -54,6 +76,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5476
}
5577

5678
$event->setData($data);
79+
} elseif ($requestHandler->isFileUpload($event->getData()) && method_exists($requestHandler, 'getUploadFileError') && null !== $errorCode = $requestHandler->getUploadFileError($event->getData())) {
80+
$form->addError($this->getFileUploadError($errorCode));
5781
} elseif (!$requestHandler->isFileUpload($event->getData())) {
5882
$event->setData(null);
5983
}
@@ -116,4 +140,109 @@ public function getBlockPrefix()
116140
{
117141
return 'file';
118142
}
143+
144+
private function getFileUploadError($errorCode)
145+
{
146+
$messageParameters = [];
147+
148+
if (UPLOAD_ERR_INI_SIZE === $errorCode) {
149+
list($limitAsString, $suffix) = $this->factorizeSizes(0, self::getMaxFilesize());
150+
$messageTemplate = 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.';
151+
$messageParameters = [
152+
'{{ limit }}' => $limitAsString,
153+
'{{ suffix }}' => $suffix,
154+
];
155+
} elseif (UPLOAD_ERR_FORM_SIZE === $errorCode) {
156+
$messageTemplate = 'The file is too large.';
157+
} else {
158+
$messageTemplate = 'The file could not be uploaded.';
159+
}
160+
161+
if (null !== $this->translator) {
162+
$message = $this->translator->trans($messageTemplate, $messageParameters);
163+
} else {
164+
$message = strtr($messageTemplate, $messageParameters);
165+
}
166+
167+
return new FormError($message, $messageTemplate, $messageParameters);
168+
}
169+
170+
/**
171+
* Returns the maximum size of an uploaded file as configured in php.ini.
172+
*
173+
* This method should be kept in sync with Symfony\Component\HttpFoundation\File\UploadedFile::getMaxFilesize().
174+
*
175+
* @return int The maximum size of an uploaded file in bytes
176+
*/
177+
private static function getMaxFilesize()
178+
{
179+
$iniMax = strtolower(ini_get('upload_max_filesize'));
180+
181+
if ('' === $iniMax) {
182+
return PHP_INT_MAX;
183+
}
184+
185+
$max = ltrim($iniMax, '+');
186+
if (0 === strpos($max, '0x')) {
187+
$max = \intval($max, 16);
188+
} elseif (0 === strpos($max, '0')) {
189+
$max = \intval($max, 8);
190+
} else {
191+
$max = (int) $max;
192+
}
193+
194+
switch (substr($iniMax, -1)) {
195+
case 't': $max *= 1024;
196+
// no break
197+
case 'g': $max *= 1024;
198+
// no break
199+
case 'm': $max *= 1024;
200+
// no break
201+
case 'k': $max *= 1024;
202+
}
203+
204+
return $max;
205+
}
206+
207+
/**
208+
* Converts the limit to the smallest possible number
209+
* (i.e. try "MB", then "kB", then "bytes").
210+
*
211+
* This method should be kept in sync with Symfony\Component\Validator\Constraints\FileValidator::factorizeSizes().
212+
*/
213+
private function factorizeSizes($size, $limit)
214+
{
215+
$coef = self::MIB_BYTES;
216+
$coefFactor = self::KIB_BYTES;
217+
218+
$limitAsString = (string) ($limit / $coef);
219+
220+
// Restrict the limit to 2 decimals (without rounding! we
221+
// need the precise value)
222+
while (self::moreDecimalsThan($limitAsString, 2)) {
223+
$coef /= $coefFactor;
224+
$limitAsString = (string) ($limit / $coef);
225+
}
226+
227+
// Convert size to the same measure, but round to 2 decimals
228+
$sizeAsString = (string) round($size / $coef, 2);
229+
230+
// If the size and limit produce the same string output
231+
// (due to rounding), reduce the coefficient
232+
while ($sizeAsString === $limitAsString) {
233+
$coef /= $coefFactor;
234+
$limitAsString = (string) ($limit / $coef);
235+
$sizeAsString = (string) round($size / $coef, 2);
236+
}
237+
238+
return [$limitAsString, self::$suffixes[$coef]];
239+
}
240+
241+
/**
242+
* This method should be kept in sync with Symfony\Component\Validator\Constraints\FileValidator::moreDecimalsThan().
243+
*/
244+
private static function moreDecimalsThan($double, $numberOfDecimals)
245+
{
246+
return \strlen((string) $double) > \strlen(round($double, $numberOfDecimals));
247+
}
119248
}

‎src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Form\RequestHandlerInterface;
1818
use Symfony\Component\Form\Util\ServerParams;
1919
use Symfony\Component\HttpFoundation\File\File;
20+
use Symfony\Component\HttpFoundation\File\UploadedFile;
2021
use Symfony\Component\HttpFoundation\Request;
2122

2223
/**
@@ -115,4 +116,16 @@ public function isFileUpload($data)
115116
{
116117
return $data instanceof File;
117118
}
119+
120+
/**
121+
* @return int|null
122+
*/
123+
public function getUploadFileError($data)
124+
{
125+
if (!$data instanceof UploadedFile || $data->isValid()) {
126+
return null;
127+
}
128+
129+
return $data->getError();
130+
}
118131
}

‎src/Symfony/Component/Form/NativeRequestHandler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/NativeRequestHandler.php
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,30 @@ public function isFileUpload($data)
135135
return \is_array($data) && isset($data['error']) && \is_int($data['error']);
136136
}
137137

138+
/**
139+
* @return int|null
140+
*/
141+
public function getUploadFileError($data)
142+
{
143+
if (!\is_array($data)) {
144+
return null;
145+
}
146+
147+
if (!isset($data['error'])) {
148+
return null;
149+
}
150+
151+
if (!\is_int($data['error'])) {
152+
return null;
153+
}
154+
155+
if (UPLOAD_ERR_OK === $data['error']) {
156+
return null;
157+
}
158+
159+
return $data['error'];
160+
}
161+
138162
/**
139163
* Returns the method used to submit the request to the server.
140164
*

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.