diff --git a/core/core.services.yml b/core/core.services.yml index cbe9d84..97c2dcb 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -282,7 +282,7 @@ services: arguments: ['@stream_wrapper_manager', '@settings', '@logger.channel.file'] form_builder: class: Drupal\Core\Form\FormBuilder - arguments: ['@form_validator', '@form_submitter', '@form_cache', '@module_handler', '@event_dispatcher', '@request_stack', '@class_resolver', '@element_info', '@theme.manager', '@string_translation', '@?csrf_token'] + arguments: ['@form_validator', '@form_submitter', '@form_cache', '@module_handler', '@event_dispatcher', '@request_stack', '@class_resolver', '@element_info', '@theme.manager', '@?csrf_token'] form_validator: class: Drupal\Core\Form\FormValidator arguments: ['@request_stack', '@string_translation', '@csrf_token', '@logger.channel.form', '@form_error_handler'] @@ -821,7 +821,7 @@ services: - { name: event_subscriber } form_ajax_subscriber: class: Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber - arguments: ['@form_ajax_response_builder', '@renderer'] + arguments: ['@form_ajax_response_builder', '@renderer', '@string_translation'] tags: - { name: event_subscriber } route_enhancer.lazy_collector: diff --git a/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php b/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php index 73fe812..09c68cd 100644 --- a/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php +++ b/core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php @@ -10,14 +10,16 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; +use Drupal\Core\Form\Exception\BrokenPostRequestException; use Drupal\Core\Form\FormAjaxException; use Drupal\Core\Form\FormAjaxResponseBuilderInterface; use Drupal\Core\Form\FormBuilderInterface; use Drupal\Core\Render\RendererInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslationInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\KernelEvents; /** @@ -25,6 +27,8 @@ */ class FormAjaxSubscriber implements EventSubscriberInterface { + use StringTranslationTrait; + /** * The form AJAX response builder. * @@ -46,10 +50,13 @@ class FormAjaxSubscriber implements EventSubscriberInterface { * The form AJAX response builder. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer service. + * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation + * The string translation. */ - public function __construct(FormAjaxResponseBuilderInterface $form_ajax_response_builder, RendererInterface $renderer) { + public function __construct(FormAjaxResponseBuilderInterface $form_ajax_response_builder, RendererInterface $renderer, TranslationInterface $string_translation) { $this->formAjaxResponseBuilder = $form_ajax_response_builder; $this->renderer = $renderer; + $this->stringTranslation = $string_translation; } /** @@ -83,8 +90,8 @@ public function onException(GetResponseForExceptionEvent $event) { // Render a nice error message in case we have a file upload which exceeds // the configured upload limit. - if ($exception instanceof BadRequestHttpException && $request->query->has(FormBuilderInterface::AJAX_FORM_REQUEST)) { - $this->drupalSetMessage($exception->getMessage(), 'error'); + if ($exception instanceof BrokenPostRequestException && $request->query->has(FormBuilderInterface::AJAX_FORM_REQUEST)) { + $this->drupalSetMessage($this->t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', ['@size' => $this->formatSize($exception->getSize())]), 'error'); $response = new AjaxResponse(); $status_messages = ['#type' => 'status_messages']; $response->addCommand(new ReplaceCommand(NULL, $this->renderer->renderRoot($status_messages))); @@ -141,6 +148,16 @@ protected function getFormAjaxException(\Exception $e) { } /** + * Wraps format_size() + * + * @return string + * The formatted size. + */ + protected function formatSize($size) { + return format_size($size); + } + + /** * {@inheritdoc} */ public static function getSubscribedEvents() { diff --git a/core/lib/Drupal/Core/Form/Exception/BrokenPostRequestException.php b/core/lib/Drupal/Core/Form/Exception/BrokenPostRequestException.php new file mode 100644 index 0000000..c6cbba8 --- /dev/null +++ b/core/lib/Drupal/Core/Form/Exception/BrokenPostRequestException.php @@ -0,0 +1,54 @@ +size = $max_upload_size; + } + + /** + * Returns the maximum upload size. + * + * @return string + * A translated string representation of the size of the file size limit + * based on the PHP upload_max_filesize and post_max_size. + */ + public function getSize() { + return $this->size; + } + + +} diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index 733618e..10b2153 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -16,6 +16,7 @@ use Drupal\Core\DependencyInjection\ClassResolverInterface; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Form\Exception\BrokenPostRequestException; use Drupal\Core\Render\Element; use Drupal\Core\Render\ElementInfoManagerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; @@ -24,7 +25,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** * Provides form building and processing. @@ -129,12 +129,10 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS * The element info manager. * @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager * The theme manager. - * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation - * The string translation service. * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token * The CSRF token generator. */ - public function __construct(FormValidatorInterface $form_validator, FormSubmitterInterface $form_submitter, FormCacheInterface $form_cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, RequestStack $request_stack, ClassResolverInterface $class_resolver, ElementInfoManagerInterface $element_info, ThemeManagerInterface $theme_manager, TranslationInterface $string_translation, CsrfTokenGenerator $csrf_token = NULL) { + public function __construct(FormValidatorInterface $form_validator, FormSubmitterInterface $form_submitter, FormCacheInterface $form_cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, RequestStack $request_stack, ClassResolverInterface $class_resolver, ElementInfoManagerInterface $element_info, ThemeManagerInterface $theme_manager, CsrfTokenGenerator $csrf_token = NULL) { $this->formValidator = $form_validator; $this->formSubmitter = $form_submitter; $this->formCache = $form_cache; @@ -145,7 +143,6 @@ public function __construct(FormValidatorInterface $form_validator, FormSubmitte $this->elementInfo = $element_info; $this->csrfToken = $csrf_token; $this->themeManager = $theme_manager; - $this->stringTranslation = $string_translation; } /** @@ -276,7 +273,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) { // (post_max_size), the post request is potentially broken. Add some // protection against that and at the same time have a nice error message. if ($ajax_form_request && !isset($form_state->getUserInput()['form_id'])) { - throw new BadRequestHttpException($this->t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', ['@size' => $this->getFormattedFileUploadMaxSize()])); + throw new BrokenPostRequestException($this->getFileUploadMaxSize()); } // After processing the form, if this is an AJAX form request, interrupt @@ -1167,14 +1164,14 @@ protected function buttonWasClicked($element, FormStateInterface &$form_state) { } /** - * Wraps format_size() and file_upload_max_size(). + * Wraps file_upload_max_size(). * * @return string * A translated string representation of the size of the file size limit * based on the PHP upload_max_filesize and post_max_size. */ - protected function getFormattedFileUploadMaxSize() { - return format_size(file_upload_max_size()); + protected function getFileUploadMaxSize() { + return file_upload_max_size(); } /** diff --git a/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php index de67c43..390f517 100644 --- a/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php +++ b/core/tests/Drupal/Tests/Core/Form/EventSubscriber/FormAjaxSubscriberTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber; +use Drupal\Core\Form\Exception\BrokenPostRequestException; use Drupal\Core\Form\FormAjaxException; use Drupal\Core\Form\FormBuilderInterface; use Drupal\Core\Form\FormState; @@ -49,6 +50,13 @@ class FormAjaxSubscriberTest extends UnitTestCase { protected $renderer; /** + * The mocked string translation. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $stringTranslation; + + /** * {@inheritdoc} */ protected function setUp() { @@ -57,7 +65,8 @@ protected function setUp() { $this->httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); $this->formAjaxResponseBuilder = $this->getMock('Drupal\Core\Form\FormAjaxResponseBuilderInterface'); $this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface'); - $this->subscriber = new FormAjaxSubscriber($this->formAjaxResponseBuilder, $this->renderer); + $this->stringTranslation = $this->getStringTranslationStub(); + $this->subscriber = new FormAjaxSubscriber($this->formAjaxResponseBuilder, $this->renderer, $this->stringTranslation); } /** @@ -147,22 +156,26 @@ public function testOnExceptionResponseBuilderException() { /** * @covers ::onException */ - public function testOnExceptionBadRequest() { + public function testOnExceptionBrokenPostRequest() { $this->formAjaxResponseBuilder->expects($this->never()) ->method('buildResponse'); $this->subscriber = $this->getMockBuilder('\Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber') - ->setConstructorArgs([$this->formAjaxResponseBuilder, $this->renderer]) - ->setMethods(['drupalSetMessage']) + ->setConstructorArgs([$this->formAjaxResponseBuilder, $this->renderer, $this->getStringTranslationStub()]) + ->setMethods(['drupalSetMessage', 'formatSize']) ->getMock(); $this->subscriber->expects($this->once()) ->method('drupalSetMessage') ->willReturn('asdf'); + $this->subscriber->expects($this->once()) + ->method('formatSize') + ->with(32 * 1e6) + ->willReturn('32M'); $rendered_output = 'the rendered output'; $this->renderer->expects($this->once()) ->method('renderRoot') ->willReturn($rendered_output); - $exception = new BadRequestHttpException(); + $exception = new BrokenPostRequestException(32 * 1e6); $request = new Request([FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]); $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception); diff --git a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php index 69c50da..6044570 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php +++ b/core/tests/Drupal/Tests/Core/Form/FormBuilderTest.php @@ -429,20 +429,19 @@ public function testFormCacheDeletionUncached() { /** * @covers ::buildForm * - * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException - * @expectedExceptionMessage The uploaded file likely exceeded the maximum file size (32M) that this server supports. + * @expectedException \Drupal\Core\Form\Exception\BrokenPostRequestException */ public function testExceededFileSize() { $request = new Request([FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]); $request_stack = new RequestStack(); $request_stack->push($request); $this->formBuilder = $this->getMockBuilder('\Drupal\Core\Form\FormBuilder') - ->setConstructorArgs([$this->formValidator, $this->formSubmitter, $this->formCache, $this->moduleHandler, $this->eventDispatcher, $request_stack, $this->classResolver, $this->elementInfo, $this->themeManager, $this->getStringTranslationStub(), $this->csrfToken]) - ->setMethods(['getFormattedFileUploadMaxSize']) + ->setConstructorArgs([$this->formValidator, $this->formSubmitter, $this->formCache, $this->moduleHandler, $this->eventDispatcher, $request_stack, $this->classResolver, $this->elementInfo, $this->themeManager, $this->csrfToken]) + ->setMethods(['getFileUploadMaxSize']) ->getMock(); $this->formBuilder->expects($this->once()) - ->method('getFormattedFileUploadMaxSize') - ->willReturn('32M'); + ->method('getFileUploadMaxSize') + ->willReturn(33554432); $form_arg = $this->getMockForm('test_form_id'); $form_state = new FormState(); diff --git a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php index fb48edf..bbda6f8 100644 --- a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php +++ b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php @@ -150,13 +150,6 @@ protected $themeManager; /** - * The string translation service. - * - * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $stringTranslation; - - /** * {@inheritdoc} */ protected function setUp() { @@ -200,9 +193,8 @@ protected function setUp() { ->setMethods(array('batchGet', 'drupalInstallationAttempted')) ->getMock(); $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))); - $this->stringTranslation = $this->getStringTranslationStub(); - $this->formBuilder = new FormBuilder($this->formValidator, $this->formSubmitter, $this->formCache, $this->moduleHandler, $this->eventDispatcher, $this->requestStack, $this->classResolver, $this->elementInfo, $this->themeManager, $this->stringTranslation, $this->csrfToken); + $this->formBuilder = new FormBuilder($this->formValidator, $this->formSubmitter, $this->formCache, $this->moduleHandler, $this->eventDispatcher, $this->requestStack, $this->classResolver, $this->elementInfo, $this->themeManager, $this->csrfToken); } /**