FormSubmitter.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <?php
  2. namespace Drupal\Core\Form;
  3. use Drupal\Core\Url;
  4. use Symfony\Component\HttpFoundation\RedirectResponse;
  5. use Symfony\Component\HttpFoundation\RequestStack;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Drupal\Core\Routing\UrlGeneratorInterface;
  8. /**
  9. * Provides submission processing for forms.
  10. */
  11. class FormSubmitter implements FormSubmitterInterface {
  12. /**
  13. * The URL generator.
  14. *
  15. * @var \Drupal\Core\Routing\UrlGeneratorInterface
  16. */
  17. protected $urlGenerator;
  18. /**
  19. * The request stack.
  20. *
  21. * @var \Symfony\Component\HttpFoundation\RequestStack
  22. */
  23. protected $requestStack;
  24. /**
  25. * Constructs a new FormValidator.
  26. *
  27. * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
  28. * The request stack.
  29. * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
  30. */
  31. public function __construct(RequestStack $request_stack, UrlGeneratorInterface $url_generator) {
  32. $this->requestStack = $request_stack;
  33. $this->urlGenerator = $url_generator;
  34. }
  35. /**
  36. * {@inheritdoc}
  37. */
  38. public function doSubmitForm(&$form, FormStateInterface &$form_state) {
  39. if (!$form_state->isSubmitted()) {
  40. return;
  41. }
  42. // Execute form submit handlers.
  43. $this->executeSubmitHandlers($form, $form_state);
  44. // If batches were set in the submit handlers, we process them now,
  45. // possibly ending execution. We make sure we do not react to the batch
  46. // that is already being processed (if a batch operation performs a
  47. // \Drupal\Core\Form\FormBuilderInterface::submitForm).
  48. if ($batch = &$this->batchGet() && !isset($batch['current_set'])) {
  49. // Store $form_state information in the batch definition.
  50. $batch['form_state'] = $form_state;
  51. $batch['progressive'] = !$form_state->isProgrammed();
  52. $response = batch_process();
  53. if ($batch['progressive']) {
  54. return $response;
  55. }
  56. // Execution continues only for programmatic forms.
  57. // For 'regular' forms, we get redirected to the batch processing
  58. // page. Form redirection will be handled in _batch_finished(),
  59. // after the batch is processed.
  60. }
  61. // Set a flag to indicate the form has been processed and executed.
  62. $form_state->setExecuted();
  63. // If no response has been set, process the form redirect.
  64. if (!$form_state->getResponse() && $redirect = $this->redirectForm($form_state)) {
  65. $form_state->setResponse($redirect);
  66. }
  67. // If there is a response was set, return it instead of continuing.
  68. if (($response = $form_state->getResponse()) && $response instanceof Response) {
  69. return $response;
  70. }
  71. }
  72. /**
  73. * {@inheritdoc}
  74. */
  75. public function executeSubmitHandlers(&$form, FormStateInterface &$form_state) {
  76. // If there was a button pressed, use its handlers.
  77. $handlers = $form_state->getSubmitHandlers();
  78. // Otherwise, check for a form-level handler.
  79. if (!$handlers && !empty($form['#submit'])) {
  80. $handlers = $form['#submit'];
  81. }
  82. foreach ($handlers as $callback) {
  83. // Check if a previous _submit handler has set a batch, but make sure we
  84. // do not react to a batch that is already being processed (for instance
  85. // if a batch operation performs a
  86. // \Drupal\Core\Form\FormBuilderInterface::submitForm()).
  87. if (($batch = &$this->batchGet()) && !isset($batch['id'])) {
  88. // Some previous submit handler has set a batch. To ensure correct
  89. // execution order, store the call in a special 'control' batch set.
  90. // See _batch_next_set().
  91. $batch['sets'][] = ['form_submit' => $callback];
  92. $batch['has_form_submits'] = TRUE;
  93. }
  94. else {
  95. call_user_func_array($form_state->prepareCallback($callback), [&$form, &$form_state]);
  96. }
  97. }
  98. }
  99. /**
  100. * {@inheritdoc}
  101. */
  102. public function redirectForm(FormStateInterface $form_state) {
  103. $redirect = $form_state->getRedirect();
  104. // Allow using redirect responses directly if needed.
  105. if ($redirect instanceof RedirectResponse) {
  106. return $redirect;
  107. }
  108. $url = NULL;
  109. // Check for a route-based redirection.
  110. if ($redirect instanceof Url) {
  111. $url = $redirect->setAbsolute()->toString();
  112. }
  113. // If no redirect was specified, redirect to the current path.
  114. elseif ($redirect === NULL) {
  115. $request = $this->requestStack->getCurrentRequest();
  116. $url = $this->urlGenerator->generateFromRoute('<current>', [], ['query' => $request->query->all(), 'absolute' => TRUE]);
  117. }
  118. if ($url) {
  119. // According to RFC 7231, 303 See Other status code must be used to redirect
  120. // user agent (and not default 302 Found).
  121. // @see http://tools.ietf.org/html/rfc7231#section-6.4.4
  122. return new RedirectResponse($url, Response::HTTP_SEE_OTHER);
  123. }
  124. }
  125. /**
  126. * Wraps drupal_installation_attempted().
  127. *
  128. * @return bool
  129. */
  130. protected function drupalInstallationAttempted() {
  131. return drupal_installation_attempted();
  132. }
  133. /**
  134. * Wraps batch_get().
  135. */
  136. protected function &batchGet() {
  137. return batch_get();
  138. }
  139. }