diff --git a/core/core.services.yml b/core/core.services.yml index 3e00fcb..71eb009 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -804,6 +804,11 @@ services: class: Drupal\Core\EventSubscriber\AjaxSubscriber tags: - { name: event_subscriber } + form_ajax_subscriber: + class: Drupal\Core\EventSubscriber\FormAjaxSubscriber + arguments: ['@form_ajax_response_handler'] + tags: + - { name: event_subscriber } route_enhancer.lazy_collector: class: Drupal\Core\Routing\LazyRouteEnhancer tags: @@ -828,11 +833,6 @@ services: class: Drupal\Core\EventSubscriber\ContentControllerSubscriber tags: - { name: event_subscriber } - route_form_controller_subscriber: - class: Drupal\Core\EventSubscriber\FormControllerSubscriber - arguments: ['@form_ajax_response_handler'] - tags: - - { name: event_subscriber } route_special_attributes_subscriber: class: Drupal\Core\EventSubscriber\SpecialAttributesRouteSubscriber tags: diff --git a/core/lib/Drupal/Core/EventSubscriber/FormControllerSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FormAjaxSubscriber.php similarity index 73% rename from core/lib/Drupal/Core/EventSubscriber/FormControllerSubscriber.php rename to core/lib/Drupal/Core/EventSubscriber/FormAjaxSubscriber.php index e5b6338..f4cde1e 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FormControllerSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FormAjaxSubscriber.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\Core\EventSubscriber\FormControllerSubscriber. + * Contains \Drupal\Core\EventSubscriber\FormAjaxSubscriber. */ namespace Drupal\Core\EventSubscriber; @@ -17,7 +17,7 @@ /** * Wraps controllers that return forms for their response. */ -class FormControllerSubscriber implements EventSubscriberInterface { +class FormAjaxSubscriber implements EventSubscriberInterface { /** * Request key for a form that will post to original URL on AJAX submission. @@ -25,11 +25,6 @@ class FormControllerSubscriber implements EventSubscriberInterface { const POST_TO_ORIGINAL_URL = 'post_to_original_url'; /** - * Request value for an AJAX form submission. - */ - const DRUPAL_AJAX_POST = 'drupal_ajax_post'; - - /** * The form AJAX handler. * * @var \Drupal\Core\Form\FormAjaxResponseHandlerInterface @@ -37,7 +32,7 @@ class FormControllerSubscriber implements EventSubscriberInterface { protected $formAjaxResponseHandler; /** - * Constructs a new FormControllerSubscriber. + * Constructs a new FormAjaxSubscriber. * * @param \Drupal\Core\Form\FormAjaxResponseHandlerInterface $form_ajax_response_handler * The form AJAX handler. @@ -47,10 +42,14 @@ public function __construct(FormAjaxResponseHandlerInterface $form_ajax_response } /** + * Catches a form AJAX exception and build a response from it. + * * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event + * The event to process. */ public function onException(GetResponseForExceptionEvent $event) { - if ($exception = $this->getFormAjaxException($event->getException())) { + $exception = $event->getException(); + if ($exception instanceof FormAjaxException) { $request = $event->getRequest(); $form = $exception->getForm(); $form_state = $exception->getFormState(); @@ -70,25 +69,7 @@ public function onException(GetResponseForExceptionEvent $event) { } /** - * @param \Exception $e - * - * @return \Drupal\Core\Form\FormAjaxException|null - */ - protected function getFormAjaxException(\Exception $e) { - while ($e) { - if ($e instanceof FormAjaxException) { - return $e; - } - - $e = $e->getPrevious(); - } - } - - /** - * Registers the methods in this class that should be listeners. - * - * @return array - * An array of event listener definitions. + * {@inheritdoc} */ public static function getSubscribedEvents() { // Run before exception.logger. diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php index 8418faf..953cb2b 100644 --- a/core/lib/Drupal/Core/Form/FormBuilder.php +++ b/core/lib/Drupal/Core/Form/FormBuilder.php @@ -14,7 +14,7 @@ use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Access\CsrfTokenGenerator; use Drupal\Core\DependencyInjection\ClassResolverInterface; -use Drupal\Core\EventSubscriber\FormControllerSubscriber; +use Drupal\Core\EventSubscriber\FormAjaxSubscriber; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Render\Element; use Drupal\Core\Render\ElementInfoManagerInterface; @@ -247,7 +247,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) { // If this form should post to the original URL, disable all form redirects. $request = $this->requestStack->getCurrentRequest(); - if ($post_to_original_url = ($request->query->get(FormControllerSubscriber::POST_TO_ORIGINAL_URL) === FormControllerSubscriber::DRUPAL_AJAX_POST)) { + if ($post_to_original_url = $request->query->has(FormAjaxSubscriber::POST_TO_ORIGINAL_URL)) { $form_state->disableRedirect(); } @@ -266,7 +266,7 @@ public function buildForm($form_id, FormStateInterface &$form_state) { // After processing the form, if this is to be posted to the original URL, // interrupt form rendering and return. - // @see \Drupal\Core\EventSubscriber\FormControllerSubscriber::onException() + // @see \Drupal\Core\EventSubscriber\FormAjaxSubscriber::onException() if ($post_to_original_url) { throw new FormAjaxException($form, $form_state); } diff --git a/core/lib/Drupal/Core/Render/Element/RenderElement.php b/core/lib/Drupal/Core/Render/Element/RenderElement.php index 1c788e9..0df954e 100644 --- a/core/lib/Drupal/Core/Render/Element/RenderElement.php +++ b/core/lib/Drupal/Core/Render/Element/RenderElement.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Render\Element; -use Drupal\Core\EventSubscriber\FormControllerSubscriber; +use Drupal\Core\EventSubscriber\FormAjaxSubscriber; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\PluginBase; use Drupal\Core\Render\Element; @@ -242,7 +242,7 @@ public static function preRenderAjaxForm($element) { // re-rendering. For that, we have a special 'system/ajax' route. if (isset($settings['callback']) && !isset($settings['url'])) { $settings['url'] = Url::fromRoute(''); - $settings['options']['query'][FormControllerSubscriber::POST_TO_ORIGINAL_URL] = FormControllerSubscriber::DRUPAL_AJAX_POST; + $settings['options']['query'][FormAjaxSubscriber::POST_TO_ORIGINAL_URL] = TRUE; } $settings += array( 'url' => NULL, diff --git a/core/modules/system/src/Tests/Ajax/DialogTest.php b/core/modules/system/src/Tests/Ajax/DialogTest.php index 359eb6f..3093fd9 100644 --- a/core/modules/system/src/Tests/Ajax/DialogTest.php +++ b/core/modules/system/src/Tests/Ajax/DialogTest.php @@ -7,7 +7,7 @@ namespace Drupal\system\Tests\Ajax; -use Drupal\Core\EventSubscriber\FormControllerSubscriber; +use Drupal\Core\EventSubscriber\FormAjaxSubscriber; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Url; @@ -166,7 +166,7 @@ public function testDialog() { 'edit-preview' => [ 'callback' => '::preview', 'event' => 'click', - 'url' => Url::fromRoute('ajax_test.dialog_form')->setOption('query', [FormControllerSubscriber::POST_TO_ORIGINAL_URL => FormControllerSubscriber::DRUPAL_AJAX_POST])->toString(), + 'url' => Url::fromRoute('ajax_test.dialog_form')->setOption('query', [FormAjaxSubscriber::POST_TO_ORIGINAL_URL => TRUE])->toString(), 'dialogType' => 'ajax', 'submit' => [ '_triggering_element_name' => 'op', diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/FormAjaxSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/FormAjaxSubscriberTest.php new file mode 100644 index 0000000..483c677 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/EventSubscriber/FormAjaxSubscriberTest.php @@ -0,0 +1,118 @@ +httpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $this->formAjaxResponseHandler = $this->getMock('Drupal\Core\Form\FormAjaxResponseHandlerInterface'); + $this->subscriber = new FormAjaxSubscriber($this->formAjaxResponseHandler); + } + + /** + * @covers ::onException + */ + public function testOnException() { + $form = ['#type' => 'form', '#build_id' => 'the_build_id']; + $form_state = new FormState(); + $exception = new FormAjaxException($form, $form_state); + + $request = new Request([], ['form_build_id' => 'the_build_id']); + $commands = []; + $response = new Response(''); + + $this->formAjaxResponseHandler->expects($this->once()) + ->method('buildResponse') + ->with($request, $form, $form_state, $commands) + ->willReturn($response); + + $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception); + $this->subscriber->onException($event); + + $this->assertSame($response, $event->getResponse()); + $this->assertSame(200, $event->getResponse()->headers->get('X-Status-Code')); + } + + /** + * @covers ::onException + */ + public function testOnExceptionNewBuildId() { + $form = ['#type' => 'form', '#build_id' => 'the_build_id']; + $form_state = new FormState(); + $exception = new FormAjaxException($form, $form_state); + + $request = new Request([], ['form_build_id' => 'a_new_build_id']); + $commands = []; + $commands[] = new UpdateBuildIdCommand('a_new_build_id', 'the_build_id'); + $response = new Response(''); + + $this->formAjaxResponseHandler->expects($this->once()) + ->method('buildResponse') + ->with($request, $form, $form_state, $commands) + ->willReturn($response); + + + $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception); + $this->subscriber->onException($event); + + $this->assertSame($response, $event->getResponse()); + $this->assertSame(200, $event->getResponse()->headers->get('X-Status-Code')); + } + + /** + * @covers ::onException + */ + public function testOnExceptionOtherClass() { + $request = new Request(); + $exception = new \Exception(); + + $this->formAjaxResponseHandler->expects($this->never()) + ->method('buildResponse'); + + $event = new GetResponseForExceptionEvent($this->httpKernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception); + $this->subscriber->onException($event); + + $this->assertNull($event->getResponse()); + } + +} diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/FormControllerSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/FormControllerSubscriberTest.php deleted file mode 100644 index 44d3e51..0000000 --- a/core/tests/Drupal/Tests/Core/EventSubscriber/FormControllerSubscriberTest.php +++ /dev/null @@ -1,56 +0,0 @@ -getMock('Drupal\Core\Form\FormAjaxResponseHandlerInterface'); - $subscriber = new FormControllerSubscriber($form_ajax_response_handler); - - $http_kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); - $form = ['#type' => 'form', '#build_id' => 'the_build_id']; - $form_state = new FormState(); - $request = new Request([FormControllerSubscriber::POST_TO_ORIGINAL_URL => FormControllerSubscriber::DRUPAL_AJAX_POST], ['form_build_id' => 'a_new_build_id']); - $exception = new FormAjaxException($form, $form_state); - $commands = []; - $commands[] = new UpdateBuildIdCommand('a_new_build_id', 'the_build_id'); - - $response = new Response(''); - $form_ajax_response_handler->expects($this->once()) - ->method('buildResponse') - ->with($request, $form, $form_state, $commands) - ->willReturn($response); - - $controller = NULL; - $expected = $response; - $event = new GetResponseForExceptionEvent($http_kernel, $request, HttpKernelInterface::MASTER_REQUEST, $exception); - $subscriber->onException($event); - $this->assertSame($expected, $event->getResponse()); - $this->assertSame(200, $event->getResponse()->headers->get('X-Status-Code')); - } - -}