diff --git a/core/includes/batch.inc b/core/includes/batch.inc index 0b07d8e..c2a204d 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -15,6 +15,7 @@ */ use \Symfony\Component\HttpFoundation\JsonResponse; +use \Drupal\Core\Utility\RedirectResponse; /** * Loads a batch from the database. @@ -54,7 +55,7 @@ function _batch_page() { $batch = batch_load($_REQUEST['id']); if (!$batch) { drupal_set_message(t('No active batch.'), 'error'); - drupal_goto(); + return new RedirectResponse(); } } diff --git a/core/includes/common.inc b/core/includes/common.inc index 0b95dcd..73f6bb5 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -500,14 +500,14 @@ function drupal_http_build_query(array $query, $parent = '') { } /** - * Prepares a 'destination' URL query parameter for use with drupal_goto(). + * Prepares a 'destination' URL query parameter for use with RedirectResponse. * * Used to direct the user back to the referring page after completing a form. * By default the current URL is returned. If a destination exists in the * previous request, that destination is returned. As such, a destination can * persist across multiple pages. * - * @see drupal_goto() + * @see RedirectResponse() */ function drupal_get_destination() { $destination = &drupal_static(__FUNCTION__); @@ -561,7 +561,7 @@ function drupal_get_destination() { * - 'fragment': The fragment of $url, if existent. * * @see url() - * @see drupal_goto() + * @see RedirectResponse() * @ingroup php_wrappers */ function drupal_parse_url($url) { @@ -2568,8 +2568,6 @@ function drupal_deliver_html_page($page_callback_result) { * There should rarely be a reason to call exit instead of drupal_exit(); * * @param $destination - * If this function is called from drupal_goto(), then this argument - * will be a fully-qualified URL that is the destination of the redirect. * This should be passed along to hook_exit() implementations. */ function drupal_exit($destination = NULL) { diff --git a/core/includes/form.inc b/core/includes/form.inc index 66aff35..749ba2d 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -6,6 +6,7 @@ */ use Drupal\Core\Utility\Color; +use Drupal\Core\Utility\RedirectResponse; /** * @defgroup forms Form builder functions @@ -186,10 +187,10 @@ function drupal_get_form($form_id) { * errors. * - redirect: Used to redirect the form on submission. It may either be a * string containing the destination URL, or an array of arguments - * compatible with drupal_goto(). See drupal_redirect_form() for complete + * compatible with RedirectResponse(). See drupal_redirect_form() for complete * information. - * - no_redirect: If set to TRUE the form will NOT perform a drupal_goto(), - * even if 'redirect' is set. + * - no_redirect: If set to TRUE the form will NOT return a + * RedirectResponse(), even if 'redirect' is set. * - method: The HTTP form method to use for finding the input for this form. * May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method * forms do not use form ids so are always considered to be submitted, which @@ -1191,8 +1192,8 @@ function drupal_validate_form($form_id, &$form, &$form_state) { * is redirected. By default, we redirect to a new destination page. The path * of the destination page can be set in $form_state['redirect'], as either a * string containing the destination or an array of arguments compatible with - * drupal_goto(). If that is not set, the user is redirected to the current - * page to display a fresh, unpopulated copy of the form. + * RedirectResponse(). If that is not set, the user is redirected to the + * current page to display a fresh, unpopulated copy of the form. * * For example, to redirect to 'node': * @code @@ -1214,12 +1215,12 @@ function drupal_validate_form($form_id, &$form, &$form_state) { * There are several triggers that may prevent a redirection though: * - If $form_state['redirect'] is FALSE, a form builder function or form * validation/submit handler does not want a user to be redirected, which - * means that drupal_goto() is not invoked. For most forms, the redirection - * logic will be the same regardless of whether $form_state['redirect'] is - * undefined or FALSE. However, in case it was not defined and the current - * request contains a 'destination' query string, drupal_goto() will redirect - * to that given destination instead. Only setting $form_state['redirect'] to - * FALSE will prevent any redirection. + * means that RedirectResponse() is not invoked. For most forms, the + * redirection logic will be the same regardless of whether + * $form_state['redirect'] is undefined or FALSE. However, in case it was + * not defined and the current request contains a 'destination' query string, + * RedirectResponse() will redirect to that given destination instead. Only + * setting $form_state['redirect'] to FALSE will prevent any redirection. * - If $form_state['no_redirect'] is TRUE, then the callback that originally * built the form explicitly disallows any redirection, regardless of the * redirection value in $form_state['redirect']. For example, ajax_get_form() @@ -1251,21 +1252,26 @@ function drupal_redirect_form($form_state) { if (!empty($form_state['no_redirect'])) { return; } - // Only invoke drupal_goto() if redirect value was not set to FALSE. + // Only invoke RedirectResponse() if redirect value was not set to FALSE. if (!isset($form_state['redirect']) || $form_state['redirect'] !== FALSE) { if (isset($form_state['redirect'])) { if (is_array($form_state['redirect'])) { - call_user_func_array('drupal_goto', $form_state['redirect']); + $redirect_response = new RedirectResponse; + return call_user_func_array(array($redirect_response, '__construct'), $form_state['redirect']); } else { // This function can be called from the installer, which guarantees // that $redirect will always be a string, so catch that case here // and use the appropriate redirect function. - $function = drupal_installation_attempted() ? 'install_goto' : 'drupal_goto'; - $function($form_state['redirect']); + if (drupal_installation_attempted()) { + install_goto($form_state['redirect']); + } + else { + return new RedirectResponse($form_state['redirect']); + } } } - drupal_goto(current_path(), array('query' => request()->query->all())); + return new RedirectResponse(current_path(), array('query' => request()->query->all())); } } @@ -4792,7 +4798,7 @@ function batch_set($batch_definition) { * Processes the batch. * * Unless the batch has been marked with 'progressive' = FALSE, the function - * issues a drupal_goto and thus ends page execution. + * issues a RedirectResponse and thus ends page execution. * * This function is generally not needed in form submit handlers; * Form API takes care of batches that were set during form submission. @@ -4804,7 +4810,7 @@ function batch_set($batch_definition) { * URL of the batch processing page. * @param $redirect_callback * (optional) Specify a function to be called to redirect to the progressive - * processing page. By default drupal_goto() will be used to redirect to a + * processing page. By default RedirectResponse() will be used to redirect to a * page which will do the progressive page. Specifying another function will * allow the progressive processing to be processed differently. */ @@ -4849,8 +4855,9 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd $t = get_t(); $batch['error_message'] = $t('Please continue to the error page', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); - // Clear the way for the drupal_goto() redirection to the batch processing - // page, by saving and unsetting the 'destination', if there is any. + // Clear the way for the RedirectResponse() redirection to the batch + // processing page, by saving and unsetting the 'destination', if there + // is any. if (isset($_GET['destination'])) { $batch['destination'] = $_GET['destination']; unset($_GET['destination']); @@ -4870,6 +4877,7 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd $_SESSION['batches'][$batch['id']] = TRUE; // Redirect for processing. + // @todo for some reason replacing this results in batches breaking. $function = $batch['redirect_callback']; $function($batch['url'], array('query' => array('op' => 'start', 'id' => $batch['id']))); } diff --git a/core/lib/Drupal/Core/Utility/RedirectResponse.php b/core/lib/Drupal/Core/Utility/RedirectResponse.php new file mode 100644 index 0000000..5bc406a --- /dev/null +++ b/core/lib/Drupal/Core/Utility/RedirectResponse.php @@ -0,0 +1,82 @@ + "node/$node->nid"); + * $link = l(t('Log in'), 'user/login', array('query' => $query)); + * @endcode + * + * Drupal will ensure that messages set by drupal_set_message() and other + * session data are written to the database before the user is redirected. + * + * This function ends the request; use it instead of a return in your menu + * callback. + * + * @param $path + * (optional) A Drupal path or a full URL, which will be passed to url() to + * compute the redirect for the URL. + * @param $options + * (optional) An associative array of additional URL options to pass to + * url(). + * @param $http_response_code + * (optional) The HTTP status code to use for the redirection, defaults to + * 302. The valid values for 3xx redirection status codes are defined in + * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 RFC 2616 @endlink + * and the + * @link http://tools.ietf.org/html/draft-reschke-http-status-308-07 draft for the new HTTP status codes: @endlink + * - 301: Moved Permanently (the recommended value for most redirects). + * - 302: Found (default in Drupal and PHP, sometimes used for spamming search + * engines). + * - 303: See Other. + * - 304: Not Modified. + * - 305: Use Proxy. + * - 307: Temporary Redirect. + * + * @see drupal_get_destination() + * @see url() + * + * @todo convert options array to methods. + */ + public function __construct($path = '', array $options = array(), $status = 302) { + $destination = request()->query->get('destination', ''); + // A destination in $_GET always overrides the function arguments. + // We do not allow absolute URLs to be passed via $_GET, as this can be an + // attack vector. + if (!empty($destination)) { + $destination = drupal_parse_url($destination); + $path = $destination['path']; + $options['query'] = $destination['query']; + $options['fragment'] = $destination['fragment']; + } + + // @todo should this be renamed. + drupal_alter('drupal_goto', $path, $options, $status); + + // The 'Location' HTTP header must be absolute. + $options['absolute'] = TRUE; + + $url = url($path, $options); + + parent::__construct($url, $status, $headers = array()); + } +} diff --git a/core/modules/aggregator/aggregator.admin.inc b/core/modules/aggregator/aggregator.admin.inc index 0ee5ee6..2897eff 100644 --- a/core/modules/aggregator/aggregator.admin.inc +++ b/core/modules/aggregator/aggregator.admin.inc @@ -7,6 +7,7 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Drupal\aggregator\Plugin\FetcherManager; +use Drupal\Core\Utility\RedirectResponse; /** * Page callback: Displays the aggregator administration page. @@ -418,7 +419,7 @@ function aggregator_admin_refresh_feed($feed) { } aggregator_refresh($feed); - drupal_goto('admin/config/services/aggregator'); + return new RedirectResponse('admin/config/services/aggregator'); } /** diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc index 0a59897..ebe06e3 100644 --- a/core/modules/comment/comment.admin.inc +++ b/core/modules/comment/comment.admin.inc @@ -7,6 +7,7 @@ use Drupal\comment\Comment; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * Page callback: Presents an administrative comment listing. @@ -226,7 +227,7 @@ function comment_multiple_delete_confirm($form, &$form_state) { if (!$comment_counter) { drupal_set_message(t('There do not appear to be any comments to delete, or your selected comment was deleted by another administrator.')); - drupal_goto('admin/content/comment'); + return new RedirectResponse('admin/content/comment'); } else { return confirm_form($form, diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc index 5176846..935962d 100644 --- a/core/modules/comment/comment.pages.inc +++ b/core/modules/comment/comment.pages.inc @@ -8,6 +8,7 @@ use Drupal\node\Node; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * Form constructor for the comment reply form. @@ -48,7 +49,7 @@ function comment_reply(Node $node, $pid = NULL) { } else { drupal_set_message(t('You are not authorized to post comments.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } } else { @@ -63,7 +64,7 @@ function comment_reply(Node $node, $pid = NULL) { if ($comment->nid != $node->nid) { // Attempting to reply to a comment not belonging to the current nid. drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } // Display the parent comment $comment->node_type = 'comment_node_' . $node->type; @@ -73,12 +74,12 @@ function comment_reply(Node $node, $pid = NULL) { } else { drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } } else { drupal_set_message(t('You are not authorized to view comments.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } } // This is the case where the comment is in response to a node. Display the node. @@ -89,7 +90,7 @@ function comment_reply(Node $node, $pid = NULL) { // Should we show the reply box? if ($node->comment != COMMENT_NODE_OPEN) { drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } elseif (user_access('post comments')) { $comment = entity_create('comment', array('nid' => $node->nid, 'pid' => $pid)); @@ -97,7 +98,7 @@ function comment_reply(Node $node, $pid = NULL) { } else { drupal_set_message(t('You are not authorized to post comments.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse("node/$node->nid"); } } @@ -126,7 +127,7 @@ function comment_approve($cid) { comment_save($comment); drupal_set_message(t('Comment approved.')); - drupal_goto('node/' . $comment->nid); + return new RedirectResponse('node/' . $comment->nid); } throw new NotFoundHttpException(); } diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index d0ef114..5db5807 100644 --- a/core/modules/image/image.admin.inc +++ b/core/modules/image/image.admin.inc @@ -5,6 +5,8 @@ * Administration pages for image settings. */ +use Drupal\Core\Utility\RedirectResponse; + /** * Menu callback; Listing of all current image styles. */ @@ -339,7 +341,7 @@ function image_effect_form($form, &$form_state, $style, $effect) { // If no configuration for this image effect, return to the image style page. if (!isset($effect['form callback'])) { - drupal_goto('admin/config/media/image-styles/edit/' . $style['name']); + return new RedirectResponse('admin/config/media/image-styles/edit/' . $style['name']); } $form['#tree'] = TRUE; diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc index a601d00..c3708a6 100644 --- a/core/modules/language/language.admin.inc +++ b/core/modules/language/language.admin.inc @@ -6,6 +6,7 @@ */ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * User interface for the language overview screen. @@ -391,7 +392,7 @@ function language_admin_delete_form($form, &$form_state, $language) { if (language_default()->langcode == $langcode) { drupal_set_message(t('The default language cannot be deleted.')); - drupal_goto('admin/config/regional/language'); + return new RedirectResponse('admin/config/regional/language'); } // For other languages, warn the user that data loss is ahead. diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 5d60f7c..f0b1a1c 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -10,6 +10,7 @@ */ use Drupal\node\Node; +use Drupal\Core\Utility\RedirectResponse; /** * Page callback: Presents the node editing form. @@ -40,7 +41,7 @@ function node_add_page() { // Bypass the node/add listing if only one content type is available. if (count($content) == 1) { $type = array_shift($content); - drupal_goto('node/add/' . $type->type); + return new RedirectResponse('node/add/' . $type->type); } return array('#theme' => 'node_add_list', '#content' => $content); } diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module index 034c7c2..a13e871 100644 --- a/core/modules/openid/openid.module +++ b/core/modules/openid/openid.module @@ -5,6 +5,8 @@ * Implement OpenID Relying Party support for Drupal */ +use Drupal\Core\Utility\RedirectResponse; + /** * Implements hook_menu(). */ @@ -739,7 +741,7 @@ function openid_authentication($response) { } else { module_invoke_all('openid_response', $response, $form_state['user']); - drupal_goto(); + return new RedirectResponse(); } $messages = drupal_get_messages('error'); @@ -761,13 +763,13 @@ function openid_authentication($response) { // registration page and prefill with the values we received. $destination = drupal_get_destination(); unset($_GET['destination']); - drupal_goto('user/register', array('query' => $destination)); + return new RedirectResponse('user/register', array('query' => $destination)); } else { drupal_set_message(t('Only site administrators can create new user accounts.'), 'error'); module_invoke_all('openid_response', $response, NULL); } - drupal_goto(); + return new RedirectResponse(); } function openid_association_request($public) { diff --git a/core/modules/openid/openid.pages.inc b/core/modules/openid/openid.pages.inc index 885fe1d..87108d7 100644 --- a/core/modules/openid/openid.pages.inc +++ b/core/modules/openid/openid.pages.inc @@ -5,6 +5,8 @@ * User page callbacks for the openid module. */ +use Drupal\Core\Utility\RedirectResponse; + /** * Menu callback; Process an OpenID authentication. */ @@ -20,7 +22,7 @@ function openid_authentication_page() { drupal_set_message(t('OpenID login cancelled.')); break; } - drupal_goto(); + return new RedirectResponse(); } /** diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module index 89f3ddf..53ca691 100644 --- a/core/modules/openid/tests/openid_test.module +++ b/core/modules/openid/tests/openid_test.module @@ -20,7 +20,7 @@ * key is used for verifying the signed messages from the provider. */ -use Symfony\Component\HttpFoundation\RedirectResponse; +use Drupal\Core\Utility\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -228,7 +228,7 @@ function openid_test_redirect($count = 0) { $url = url('openid-test/redirect/' . --$count, array('absolute' => TRUE)); } $http_response_code = variable_get('openid_test_redirect_http_reponse_code', 301); - return new RedirectResponse($url, $http_response_code); + return new RedirectResponse($url, array(), $http_response_code); } /** @@ -306,7 +306,7 @@ function _openid_test_endpoint_authenticate() { 'openid.mode' => 'error', 'openid.error' => 'Unexpted identity', ); - return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE))); + return new RedirectResponse($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE)); } // Generate unique identifier for this authentication. @@ -346,7 +346,7 @@ function _openid_test_endpoint_authenticate() { // Put the signed message into the query string of a URL supplied by the // Relying Party, and redirect the user. - return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external', TRUE))); + return new RedirectResponse($_REQUEST['openid_return_to'], array('query' => $response, 'external', TRUE)); } /** diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module index e57ff5f..7687211 100644 --- a/core/modules/overlay/overlay.module +++ b/core/modules/overlay/overlay.module @@ -7,6 +7,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * Implements hook_help(). @@ -133,7 +134,7 @@ function overlay_init() { // #overlay=admin/modules to actually enable the overlay. if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) { unset($_SESSION['overlay_enable_redirect']); - drupal_goto('', array('fragment' => 'overlay=' . $current_path)); + return new RedirectResponse('', array('fragment' => 'overlay=' . $current_path)); } if (isset($_GET['render']) && $_GET['render'] == 'overlay') { @@ -343,7 +344,7 @@ function overlay_user_dismiss_message() { $account->save(); drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.')); // Destination is normally given. Go to the user profile as a fallback. - drupal_goto('user/' . $user->uid . '/edit'); + return new RedirectResponse('user/' . $user->uid . '/edit'); } /** diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc index c940223..4966032 100644 --- a/core/modules/search/search.pages.inc +++ b/core/modules/search/search.pages.inc @@ -5,6 +5,8 @@ * User page callbacks for the search module. */ +use Drupal\Core\Utility\RedirectResponse; + /** * Menu callback; presents the search form and/or search results. * @@ -40,7 +42,7 @@ function search_view($module = NULL, $keys = '') { if ($keys) { $path .= '/' . $keys; } - drupal_goto($path); + return new RedirectResponse($path); } // Default results output is an empty string. diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc index 3345c59..0675d71 100644 --- a/core/modules/shortcut/shortcut.admin.inc +++ b/core/modules/shortcut/shortcut.admin.inc @@ -6,6 +6,7 @@ */ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * Form callback: builds the form for switching shortcut sets. @@ -690,7 +691,7 @@ function shortcut_link_add_inline($shortcut_set) { else { drupal_set_message(t('Unable to add a shortcut for %title.', array('%title' => $link['link_title']))); } - drupal_goto(); + return new RedirectResponse(); } throw new AccessDeniedHttpException(); diff --git a/core/modules/simpletest/simpletest.pages.inc b/core/modules/simpletest/simpletest.pages.inc index a98b445..b6a6c1c 100644 --- a/core/modules/simpletest/simpletest.pages.inc +++ b/core/modules/simpletest/simpletest.pages.inc @@ -5,6 +5,8 @@ * Page callbacks for simpletest module. */ +use Drupal\Core\Utility\RedirectResponse; + /** * List tests arranged in groups that can be selected and run. */ @@ -208,8 +210,7 @@ function simpletest_result_form($form, &$form_state, $test_id) { $results = array(); if (is_numeric($test_id) && !$results = simpletest_result_get($test_id)) { drupal_set_message(t('No test results to display.'), 'error'); - drupal_goto('admin/config/development/testing'); - return $form; + return new RedirectResponse('admin/config/development/testing'); } // Load all classes and include CSS. diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 45ad10e..9394a65 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -8,6 +8,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Drupal\Core\Utility\RedirectResponse; /** * Menu callback; Provide the administration overview page. @@ -280,7 +281,7 @@ function system_theme_enable() { else { drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error'); } - drupal_goto('admin/appearance'); + return new RedirectResponse('admin/appearance'); } throw new AccessDeniedHttpException(); } @@ -308,7 +309,7 @@ function system_theme_disable() { else { drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error'); } - drupal_goto('admin/appearance'); + return new RedirectResponse('admin/appearance'); } throw new AccessDeniedHttpException(); } @@ -355,7 +356,7 @@ function system_theme_default() { else { drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error'); } - drupal_goto('admin/appearance'); + return new RedirectResponse('admin/appearance'); } throw new AccessDeniedHttpException(); } @@ -1329,7 +1330,7 @@ function system_modules_uninstall_validate($form, &$form_state) { // Form submitted, but no modules selected. if (!count(array_filter($form_state['values']['uninstall']))) { drupal_set_message(t('No modules selected.'), 'error'); - drupal_goto('admin/modules/uninstall'); + return new RedirectResponse('admin/modules/uninstall'); } } @@ -1646,7 +1647,7 @@ function system_run_cron_submit($form, &$form_state) { drupal_set_message(t('Cron run failed.'), 'error'); } - drupal_goto('admin/config/system/cron'); + return new RedirectResponse('admin/config/system/cron'); } /** @@ -2287,7 +2288,7 @@ function system_run_cron() { drupal_set_message(t('Cron run failed.'), 'error'); } - drupal_goto('admin/reports/status'); + return new RedirectResponse('admin/reports/status'); } /** @@ -3023,7 +3024,7 @@ function system_actions_manage_form_submit($form, &$form_state) { */ function system_actions_configure($form, &$form_state, $action = NULL) { if ($action === NULL) { - drupal_goto('admin/config/system/actions'); + return new RedirectResponse('admin/config/system/actions'); } $actions_map = actions_actions_map(actions_list()); @@ -3170,7 +3171,7 @@ function system_action_delete_orphans_post($orphaned) { */ function system_actions_remove_orphans() { actions_synchronize(TRUE); - drupal_goto('admin/config/system/actions/manage'); + return new RedirectResponse('admin/config/system/actions/manage'); } /** diff --git a/core/modules/system/system.module b/core/modules/system/system.module index a76e3ae..a6091a1 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -7,6 +7,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; +use Drupal\Core\Utility\RedirectResponse; /** * Maximum age of temporary files in seconds. @@ -1911,8 +1912,8 @@ function _system_themes_access($theme) { * or to call system_authorized_init() and then redirect to authorize.php, * using the URL from system_authorized_get_url(). Redirecting yourself is * necessary when your authorized operation is being triggered by a form - * submit handler, since calling drupal_goto() in a submit handler is a bad - * idea, and you should instead set $form_state['redirect']. + * submit handler, since calling new RedirectResponse in a submit handler is a + * bad idea, and you should instead set $form_state['redirect']. * * Once the SESSION is setup for the operation and the user is redirected to * authorize.php, they will be prompted for their connection credentials (core @@ -1999,7 +2000,7 @@ function system_authorized_batch_processing_url() { */ function system_authorized_run($callback, $file, $arguments = array(), $page_title = NULL) { system_authorized_init($callback, $file, $arguments, $page_title); - drupal_goto(system_authorized_get_url()); + return new RedirectResponse(system_authorized_get_url()); } /** @@ -3217,7 +3218,7 @@ function system_admin_compact_mode() { */ function system_admin_compact_page($mode = 'off') { user_cookie_save(array('admin_compact_mode' => ($mode == 'on'))); - drupal_goto(); + return new RedirectResponse(); } /** @@ -3624,7 +3625,7 @@ function system_goto_action_submit($form, $form_state) { * @ingroup actions */ function system_goto_action($entity, $context) { - drupal_goto(token_replace($context['url'], $context)); + return new RedirectResponse(token_replace($context['url'], $context)); } /** diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module index 187fee5..6bc13dd 100644 --- a/core/modules/system/tests/modules/common_test/common_test.module +++ b/core/modules/system/tests/modules/common_test/common_test.module @@ -5,6 +5,8 @@ * Helper module for the Common tests. */ +use Drupal\Core\Utility\RedirectResponse; + /** * Implements hook_menu(). */ @@ -35,8 +37,7 @@ function common_test_menu() { ); $items['common-test/drupal_goto/redirect_fail'] = array( 'title' => 'Drupal Goto Failure', - 'page callback' => 'drupal_goto', - 'page arguments' => array('common-test/drupal_goto/fail'), + 'page callback' => 'common_test_drupal_goto_redirect_fail', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); @@ -62,28 +63,35 @@ function common_test_menu() { } /** - * Redirect using drupal_goto(). + * Redirect using RedirectResponse. */ function common_test_drupal_goto_redirect() { - drupal_goto('common-test/drupal_goto'); + return new RedirectResponse('common-test/drupal_goto'); +} + +/** + * Redirect using RedirectResponse. + */ +function common_test_drupal_goto_redirect_fail() { + return new RedirectResponse('common-test/drupal_goto/fail'); } /** - * Redirect using drupal_goto(). + * Redirect using RedirectResponse. */ function common_test_drupal_goto_redirect_advanced() { - drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301); + return new RedirectResponse('common-test/drupal_goto', array('query' => array('foo' => '123')), 301); } /** - * Landing page for drupal_goto(). + * Landing page for RedirectResponse. */ function common_test_drupal_goto_land() { print "drupal_goto"; } /** - * Fail landing page for drupal_goto(). + * Fail landing page for RedirectResponse. */ function common_test_drupal_goto_land_fail() { print "drupal_goto_fail"; diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module index 444d54d..f7f69ef 100644 --- a/core/modules/system/tests/modules/system_test/system_test.module +++ b/core/modules/system/tests/modules/system_test/system_test.module @@ -1,5 +1,7 @@ uid . '/edit'); + return new RedirectResponse('user/' . $GLOBALS['user']->uid . '/edit'); } } } @@ -1866,7 +1867,7 @@ function user_login($form, &$form_state) { // If we are already logged on, go to the user page instead. if ($user->uid) { - drupal_goto('user/' . $user->uid); + return new RedirectResponse('user/' . $user->uid); } // Display login form: @@ -3051,7 +3052,7 @@ function user_multiple_cancel_confirm($form, &$form_state) { drupal_set_message($message, $redirect ? 'error' : 'warning'); // If only user 1 was selected, redirect to the overview. if ($redirect) { - drupal_goto('admin/people'); + return new RedirectResponse('admin/people'); } } @@ -3512,7 +3513,7 @@ function user_register_form($form, &$form_state) { // If we aren't admin but already logged on, go to the user page instead. if (!$admin && $user->uid) { - drupal_goto('user/' . $user->uid); + return new RedirectResponse('user/' . $user->uid); } $form['#user'] = entity_create('user', array()); diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc index b568f66..4976a82 100644 --- a/core/modules/user/user.pages.inc +++ b/core/modules/user/user.pages.inc @@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; +use Drupal\Core\Utility\RedirectResponse; /** * Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users. @@ -115,7 +116,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a drupal_set_message(t('The one-time login link you clicked is invalid.')); } } - drupal_goto(); + return new RedirectResponse(); } else { // Time out, in seconds, until login URL expires. Defaults to 24 hours = @@ -128,7 +129,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a // No time out for first time login. if ($account->login && $current - $timestamp > $timeout) { drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.')); - drupal_goto('user/password'); + return new RedirectResponse('user/password'); } elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) { // First stage is a confirmation form, then login @@ -143,7 +144,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a // Let the user's password be changed without the current password check. $token = drupal_hash_base64(drupal_random_bytes(55)); $_SESSION['pass_reset_' . $user->uid] = $token; - drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token))); + return new RedirectResponse('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token))); } else { $form['message'] = array('#markup' => t('

This is a one-time login for %user_name and will expire on %expiration_date.

Click on this button to log in to the site and change your password.

', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout)))); @@ -156,7 +157,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a } else { drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.')); - drupal_goto('user/password'); + return new RedirectResponse('user/password'); } } else { @@ -180,7 +181,7 @@ function user_logout() { // Destroy the current session, and reset $user to the anonymous user. session_destroy(); - drupal_goto(); + return new RedirectResponse(); } /** @@ -482,7 +483,7 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') { } else { drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.')); - drupal_goto("user/$account->uid/cancel"); + return new RedirectResponse("user/$account->uid/cancel"); } } throw new AccessDeniedHttpException();