FormSubmitter.php 5.7 KB

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