Developers
Redirect
A task that changes something should not render a page. It should redirect,
so that reloading the browser does not repeat the change. App::redirect()
is how, and it is the last line of nearly every save, delete, publish
and state task in the tree.
use App;
use Route;
use Lang;
App::redirect(
Route::url('index.php?option=com_bookings&controller=instruments'),
Lang::txt('COM_BOOKINGS_BOOKING_SAVED'),
'success'
);
The member lands on the list, sees the message, and the URL in their address
bar is a GET they can reload, bookmark or share. Render the list directly
instead and the URL is still the POST that saved the booking, so a refresh
offers to save it again — and a member who says yes gets two.
The arguments
App::redirect($url, $message = null, $type = 'success')
| Argument | Notes |
|---|---|
$url |
Where to go. Build it with Route::url() rather than by hand |
$message |
Optional. Shown to the member on the page they land on |
$type |
success, error, warning or info |
The message is queued through the notification service, which stores it in
the session; the template on the next page renders and clears it. That is
why the message survives the redirect. On a client with no notification
service — the API, the command line — the message is dropped and only the
redirect happens.
The types match the Notify facade's methods,
so these two are equivalent:
App::redirect($url, $msg, 'error');
Notify::error($msg);
App::redirect($url);
Use the second form when you have several messages to queue, or when the redirect target is decided later.
It does not return
App::redirect() builds a Hubzero\Http\RedirectResponse, sends it, and
calls App::close(), which is exit(). Nothing after the call runs:
App::redirect(Route::url('index.php?option=com_bookings'));
// never reached
$this->doSomethingElse();
That makes it safe to use as an early exit, and it makes return after it
redundant — though return is written in a lot of places anyway, and does
no harm.
What happens to the URL
RedirectResponse::send() normalises the target before sending it:
- A URL starting
index.phporindex2.phpgetsRequest::base()prepended. - Everything after the first line break is discarded, which is what stops a header injection through a redirect parameter.
- A URL with no scheme is made absolute: one starting
/against the current scheme, user info and host; anything else against the current path as well.
So a relative route result reaches the browser as an absolute URL, and you do not have to build one.
Redirecting from a controller
Controllers extending Hubzero\Component\SiteController or
AdminController also carry setRedirect($url, $msg = null, $type = null),
which stores the target, and redirect($url = null, $msg = null, $type = null), which sends whatever was stored. Both are marked @deprecated and
both end up in App::redirect(); you will meet them in older controllers,
but write App::redirect() in new code.
Sending one yourself
The rare case — a middleware, or a redirect that must carry extra headers — constructs the response directly:
$redirect = new Hubzero\Http\RedirectResponse($url);
$redirect->setRequest(App::get('request'));
$redirect->header('X-Reason', 'moved');
$redirect->send();
App::close();
setRequest() is what enables the URL normalisation above; without it the
target is sent exactly as given.
Rewritten and checked against 2.4-main @ 348f0057c2 on 2026-09-10.