FormAjaxResponseBuilder.php 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. namespace Drupal\Core\Form;
  3. use Drupal\Core\Ajax\AjaxResponse;
  4. use Drupal\Core\Ajax\UpdateBuildIdCommand;
  5. use Drupal\Core\Render\MainContent\MainContentRendererInterface;
  6. use Drupal\Core\Routing\RouteMatchInterface;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpKernel\Exception\HttpException;
  9. /**
  10. * Builds an AJAX form response.
  11. *
  12. * Given the current request, a form render array, its form state, and any AJAX
  13. * commands to apply to the form, build a response object.
  14. */
  15. class FormAjaxResponseBuilder implements FormAjaxResponseBuilderInterface {
  16. /**
  17. * The main content to AJAX Response renderer.
  18. *
  19. * @var \Drupal\Core\Render\MainContent\MainContentRendererInterface
  20. */
  21. protected $ajaxRenderer;
  22. /**
  23. * The current route match.
  24. *
  25. * @var \Drupal\Core\Routing\RouteMatchInterface
  26. */
  27. protected $routeMatch;
  28. /**
  29. * Constructs a new FormAjaxResponseBuilder.
  30. *
  31. * @param \Drupal\Core\Render\MainContent\MainContentRendererInterface $ajax_renderer
  32. * The ajax renderer.
  33. * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
  34. * The current route match.
  35. */
  36. public function __construct(MainContentRendererInterface $ajax_renderer, RouteMatchInterface $route_match) {
  37. $this->ajaxRenderer = $ajax_renderer;
  38. $this->routeMatch = $route_match;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function buildResponse(Request $request, array $form, FormStateInterface $form_state, array $commands) {
  44. // If the form build ID has changed, issue an Ajax command to update it.
  45. if (isset($form['#build_id_old']) && $form['#build_id_old'] !== $form['#build_id']) {
  46. $commands[] = new UpdateBuildIdCommand($form['#build_id_old'], $form['#build_id']);
  47. }
  48. // We need to return the part of the form (or some other content) that needs
  49. // to be re-rendered so the browser can update the page with changed
  50. // content. It is up to the #ajax['callback'] function of the element (may
  51. // or may not be a button) that triggered the Ajax request to determine what
  52. // needs to be rendered.
  53. $callback = NULL;
  54. if (($triggering_element = $form_state->getTriggeringElement()) && isset($triggering_element['#ajax']['callback'])) {
  55. $callback = $triggering_element['#ajax']['callback'];
  56. }
  57. $callback = $form_state->prepareCallback($callback);
  58. if (empty($callback) || !is_callable($callback)) {
  59. throw new HttpException(500, 'The specified #ajax callback is empty or not callable.');
  60. }
  61. $result = call_user_func_array($callback, [&$form, &$form_state, $request]);
  62. // If the callback is an #ajax callback, the result is a render array, and
  63. // we need to turn it into an AJAX response, so that we can add any commands
  64. // we got earlier; typically the UpdateBuildIdCommand when handling an AJAX
  65. // submit from a cached page.
  66. if ($result instanceof AjaxResponse) {
  67. $response = $result;
  68. }
  69. else {
  70. // At this point we know callback returned a render element. If the
  71. // element is part of the group (#group is set on it) it won't be rendered
  72. // unless we remove #group from it. This is caused by
  73. // \Drupal\Core\Render\Element\RenderElement::preRenderGroup(), which
  74. // prevents all members of groups from being rendered directly.
  75. if (!empty($result['#group'])) {
  76. unset($result['#group']);
  77. }
  78. /** @var \Drupal\Core\Ajax\AjaxResponse $response */
  79. $response = $this->ajaxRenderer->renderResponse($result, $request, $this->routeMatch);
  80. }
  81. foreach ($commands as $command) {
  82. $response->addCommand($command, TRUE);
  83. }
  84. return $response;
  85. }
  86. }