Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
33.33% |
2 / 6 |
CRAP | |
71.79% |
28 / 39 |
| FormAjaxSubscriber | |
0.00% |
0 / 1 |
|
42.86% |
3 / 7 |
18.40 | |
71.79% |
28 / 39 |
| __construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| onView | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
| onException | |
100.00% |
1 / 1 |
5 | |
100.00% |
21 / 21 |
|||
| getFormAjaxException | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
| formatSize | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| getSubscribedEvents | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| drupalSetMessage | |
100.00% |
1 / 1 |
1 | |
100.00% |
0 / 0 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Core\Form\EventSubscriber\FormAjaxSubscriber. | |
| */ | |
| namespace Drupal\Core\Form\EventSubscriber; | |
| 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\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\KernelEvents; | |
| /** | |
| * Wraps AJAX form submissions that are triggered via an exception. | |
| */ | |
| class FormAjaxSubscriber implements EventSubscriberInterface { | |
| use StringTranslationTrait; | |
| /** | |
| * The form AJAX response builder. | |
| * | |
| * @var \Drupal\Core\Form\FormAjaxResponseBuilderInterface | |
| */ | |
| protected $formAjaxResponseBuilder; | |
| /** | |
| * Constructs a new FormAjaxSubscriber. | |
| * | |
| * @param \Drupal\Core\Form\FormAjaxResponseBuilderInterface $form_ajax_response_builder | |
| * The form AJAX response builder. | |
| * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation | |
| * The string translation. | |
| */ | |
| public function __construct(FormAjaxResponseBuilderInterface $form_ajax_response_builder, TranslationInterface $string_translation) { | |
| $this->formAjaxResponseBuilder = $form_ajax_response_builder; | |
| $this->stringTranslation = $string_translation; | |
| } | |
| /** | |
| * Alters the wrapper format if this is an AJAX form request. | |
| * | |
| * @param \Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event | |
| * The event to process. | |
| */ | |
| public function onView(GetResponseForControllerResultEvent $event) { | |
| // To support an AJAX form submission of a form within a block, make the | |
| // later VIEW subscribers process the controller result as though for | |
| // HTML display (i.e., add blocks). During that block building, when the | |
| // submitted form gets processed, an exception gets thrown by | |
| // \Drupal\Core\Form\FormBuilderInterface::buildForm(), allowing | |
| // self::onException() to return an AJAX response instead of an HTML one. | |
| $request = $event->getRequest(); | |
| if ($request->query->has(FormBuilderInterface::AJAX_FORM_REQUEST)) { | |
| $request->query->set(MainContentViewSubscriber::WRAPPER_FORMAT, 'html'); | |
| } | |
| } | |
| /** | |
| * 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) { | |
| $exception = $event->getException(); | |
| $request = $event->getRequest(); | |
| // Render a nice error message in case we have a file upload which exceeds | |
| // the configured upload limit. | |
| 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, $status_messages)); | |
| $response->headers->set('X-Status-Code', 200); | |
| $event->setResponse($response); | |
| return; | |
| } | |
| // Extract the form AJAX exception (it may have been passed to another | |
| // exception before reaching here). | |
| if ($exception = $this->getFormAjaxException($exception)) { | |
| $request = $event->getRequest(); | |
| $form = $exception->getForm(); | |
| $form_state = $exception->getFormState(); | |
| // Set the build ID from the request as the old build ID on the form. | |
| $form['#build_id_old'] = $request->get('form_build_id'); | |
| try { | |
| $response = $this->formAjaxResponseBuilder->buildResponse($request, $form, $form_state, []); | |
| // Since this response is being set in place of an exception, explicitly | |
| // mark this as a 200 status. | |
| $response->headers->set('X-Status-Code', 200); | |
| $event->setResponse($response); | |
| } | |
| catch (\Exception $e) { | |
| // Otherwise, replace the existing exception with the new one. | |
| $event->setException($e); | |
| } | |
| } | |
| } | |
| /** | |
| * Extracts a form AJAX exception. | |
| * | |
| * @param \Exception $e | |
| * A generic exception that might contain a form AJAX exception. | |
| * | |
| * @return \Drupal\Core\Form\FormAjaxException|null | |
| * Either the form AJAX exception, or NULL if none could be found. | |
| */ | |
| protected function getFormAjaxException(\Exception $e) { | |
| $exception = NULL; | |
| while ($e) { | |
| if ($e instanceof FormAjaxException) { | |
| $exception = $e; | |
| break; | |
| } | |
| $e = $e->getPrevious(); | |
| } | |
| return $exception; | |
| } | |
| /** | |
| * Wraps format_size() | |
| * | |
| * @return string | |
| * The formatted size. | |
| */ | |
| protected function formatSize($size) { | |
| return format_size($size); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public static function getSubscribedEvents() { | |
| // Run before exception.logger. | |
| $events[KernelEvents::EXCEPTION] = ['onException', 51]; | |
| // Run before main_content_view_subscriber. | |
| $events[KernelEvents::VIEW][] = ['onView', 1]; | |
| return $events; | |
| } | |
| /** | |
| * Wraps drupal_set_message(). | |
| * | |
| * @codeCoverageIgnore | |
| */ | |
| protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) { | |
| drupal_set_message($message, $type, $repeat); | |
| } | |
| } |