📤 Response Class
The Response class handles outputting data from controllers. It can return text, HTML, JSON, objects, templates, redirects, and error codes.
⚡ Quick Start
You can create a response manually:
$response = new Response();
$response->json(['name' => 'Sasha']);But it's more convenient to use the response() helper:
response(['name' => 'Sasha']);It automatically detects the content type — array, object, or text — and returns the appropriate response.
🧪 Controller Usage Example
Route::get('/', function () {
return response()->json([
'message' => 'Welcome!',
'version' => '1.0.0',
]);
});🧾 Response Methods
📄 text($text, $status = 200, $headers = [])
Returns plain text.
Route::get('/text', function () {
return response()->text('Simple text response');
});🌐 html($html, $status = 200, $headers = [])
Returns HTML content. Injects MODX scripts from $modx->getRegisteredClientStartupScripts() and $modx->getRegisteredClientScripts() into </head> and </body>.
Route::get('/html', function () {
return response()->html('<!DOCTYPE html><html><head></head><body><h1>Hello</h1></body></html>');
});🔢 json(array $data, $status = 200, $headers = [])
Returns JSON with automatic Content-Type: application/json header.
Route::get('/json', function () {
return response()->json([
'success' => true,
'user' => ['name' => 'Sasha', 'age' => 30],
]);
});🧱 object($object, $status = 200, $headers = [])
Converts an xPDOObject or collection to an array and returns as JSON. Supports single objects and xPDOIterator.
Route::get('/user', function () {
$user = $modx->getObject(\modUser::class, 1);
// or $user = query(\modUser::class)->find(1)
return response()->object($user);
});Route::get('/users', function () {
$users = $modx->getIterator(\modUser::class);
// or $users = query(\modUser::class)->get()
return response()->object($users);
});🖼️ view($template, array $data = [])
Renders a template using view() and returns it as HTML.
Route::get('/home', function () {
return response()->view('home', ['title' => 'Home Page']);
});Templates can be specified as
@INLINE,@FILE,file:, chunk, or path.
🔁 Redirects
In PageBlocks, you can create HTTP redirects using the redirect(...) method of the Response object:
return response()->redirect('/dashboard');However, the global redirect() helper is more commonly used—it's shorter and provides access to all methods of the Redirect class:
return redirect('/dashboard'); // simple redirect
return redirect()->route('profile.show'); // named route
return redirect()->back(); // back🔀 redirect($url, $status = 302)
A simple redirect to the specified URL.
Controller example:
Route::get('/go-home', function () {
return redirect('/');
});🔙 back($fallback = '/', $status = 302)
Redirects to the previous page (HTTP_REFERER), or to $fallback if REFERER is missing.
Example:
Route::post('/form', function () {
// Process data...
return redirect()->back();
});♻️ refresh($status = 302)
Refreshes the current URL.
Example:
Route::get('/refresh', function () {
return redirect()->refresh();
});🏠 home($status = 302)
Redirects to the homepage (/):
Example:
Route::get('/logout', function () {
// Clear session...
return redirect()->home();
});🧭 route($name, $parameters = [], $status = 302)
Redirects to a named route.
Example:
Route::get('/profile/{id}', ...)->name('profile.show');
Route::post('/profile/save', function () {
// Save data...
return redirect()->route('profile.show', ['id' => 42]);
});→ If the route /profile/{id} is found, it will redirect to /profile/42.
❗ If the specified route is not found, abort(500) will be triggered.
🧨 intended($defaultUrl = '/', $status = 302)
Redirects to the saved URL from $_SESSION['_intended'], or to $defaultUrl if not set.
Where it can be used:
Route::post('/login', function () {
// Login check...
return redirect()->intended('/');
});How it works:
If you previously saved $_SESSION['_intended'] when accessing a protected page:
// Middleware or security logic:
$_SESSION['_intended'] = $_SERVER['REQUEST_URI'];
return redirect()->route('login');🔐 secure($url, $status = 302)
Redirects to the HTTPS version of the URL. Useful for forcing a secure connection.
Example:
Route::get('/secure', function () {
return redirect()->secure('profile/edit');
});Result: https://example.com/profile/edit
❌ error($code = 404, $text = '')
A simple way to return an error via redirect():
Route::get('/admin', function () {
if (!auth('mgr')) {
return redirect()->error(403, 'Access denied');
}
});🛑 Immediate Termination — abort()
The global helper abort() calls response()->abort(...)->send() and immediately stops execution, returning a fully rendered error page with a template.
Route::get('/admin', function () {
if (!auth('mgr')) {
abort(403, 'Access denied');
}
return view('admin.panel');
});⚠️ No return is required, since it sends headers and renders the page right away.
📌 Standard HTTP codes are supported: 403, 404, 503, etc. They are mapped to MODX system pages:
- 403 →
unauthorized_page - 404 →
error_page - 503 →
site_unavailable_page
If the code does not match a system page, a temporary resource with the error text will be created.
📦 If an error template exists at core/App/elements/templates/errors/{code}.tpl, it will be used. Otherwise, the fallback template will be:
templates/base.tplExample usage without parameters (returns 404 Not Found):
Route::get('/admin', function () {
if (!auth('mgr')) {
abort(); // will return the 404 page
}
return view('admin.panel');
});📦 response() Helper
function response($content = '', int $status = 200, array $headers = []): ResponseBehavior:
- Array →
json(...) - Object →
object(...) - String →
text(...)
Examples:
return response(['ok' => true]); // JSON
return response($user); // xPDOObject → JSON
return response('Hello, world!'); // Text📎 File Downloads
📥 download($file, $name = null, $headers = [])
Allows downloading a file from the server. Sets proper Content-Type, Content-Disposition, Content-Length headers and reads the file contents.
Route::get('/download', function () {
return response()->download('assets/files/manual.pdf');
});You can rename the file during download:
Route::get('/download-invoice', function () {
return response()->download('assets/files/invoice_2025.pdf', 'invoice.pdf');
});If the file isn't found — returns 404 File not found..
✅ Universal Responses
These methods automatically choose the response format — HTML or JSON — based on request()->expectsJson().
✅ success($message = '', $redirect = '')
Returns a success response. Works in two modes:
- 🔁 If
expectsJson()→ returns JSON:
{
"success": true,
"message": "Saved successfully",
"errors": [],
"redirect": "/dashboard"
}- 📦 If not → redirects back (
back()orredirect(...)), adds flash message and old input (withInput()).
Route::post('/form', function () {
// Save data...
return response()->success('Data saved', '/profile');
});❌ error($message = '', $errors = [], $status = 422)
Returns an error response. Behavior is similar:
- 🔁 JSON:
{
"success": false,
"message": "Validation error",
"errors": {
"email": "Invalid format"
},
"redirect": ""
}- 📦 HTML: Redirects back with flash message,
withErrors()andwithInput().
Route::post('/form', function () {
$errors = ['email' => 'Invalid format'];
return response()->error('Check the form', $errors);
});➕ append(array $data)
Appends additional data to JSON response. Used with success() or error().
Route::post('/form', function () {
return response()
->append(['debug' => true])
->success('OK');
});Result:
{
"success": true,
"message": "OK",
"errors": [],
"redirect": "",
"debug": true
}👜 withBag
The withBag($name) method allows grouping flash data under a named bag. This is useful when you have multiple forms on a page.
✅ Example for success()
return response()
->withBag('auth')
->success('You have successfully logged in!');In template:
{$success_message.auth} {* Outputs: You have successfully logged in! *}❌ Example for error()
return response()
->withBag('auth')
->error('Login error', [
'email' => 'Email not found',
'password' => 'Wrong password',
]);In template:
{$error_message.auth} {* Main message *}
{$errors.auth.email} {* Field-specific message for email *}
{$errors.auth.password} {* Field-specific message for password *}
{$old_input.auth.email} {* Old value for email field *}Without withBag(), data would be available without nesting:
{$error_message}
{$errors.email}
{$old_input.email}🧾 Working with Headers
The Response class allows flexible HTTP header management: add, remove, retrieve.
➕ header($name, $value)
Adds a single header (short for setHeader()):
return response()
->text('OK')
->header('X-Custom-Header', 'value123');⚙️ setHeader($name, $value)
Manually sets or overrides a header.
$response = response()->setHeader('Cache-Control', 'no-store');🧩 withHeaders(array $headers)
Bulk header addition. Often used when formatting responses.
return response()
->json(['ok' => true])
->withHeaders([
'X-Request-ID' => uniqid(),
'X-Frame-Options' => 'DENY',
]);🔍 getHeaders()
Returns all headers set in the response:
$headers = response()->getHeaders();
print_r($headers);Example output:
[
'Content-Type' => 'application/json; charset=utf-8',
'X-Powered-By' => 'PageBlocks',
]❌ removeHeader($name)
Removes a header if it was set:
$response = response()->removeHeader('X-Powered-By');💾 Attaching Data to Responses
For regular (non-AJAX) requests, you can store data in flash session to use in templates after redirects — for example, to pass errors, old form values, and any other messages.
📎 with($key, $value, $name = '')
Stores data in flash session. Supports named "groups" ($name) for value separation:
return response()
->back()
->with('success_message', 'Record created');With group:
return response()
->back()
->with('message', 'User updated', 'admin');👜 withBag($name)
Sets a default group that will be used by all subsequent with() calls:
return response()
->withBag('form1')
->back()
->withErrors(['email' => 'Invalid format'])
->withInput();This approach is useful when you need to separate data between different forms on a page.
🐞 withErrors(array $errors, $name = '')
Stores errors in session. If a name is specified, errors will be placed in the corresponding group:
return response()->back()->withErrors([
'email' => 'Invalid format',
'name' => 'Required field',
]);With group:
return response()->back()->withErrors(['required' => 'Field is required'], 'validation');🔁 withInput($name = '')
Saves all user input (request()->all()). Used to restore values after redirect:
return response()
->back()
->withErrors($errors)
->withInput();With group:
return response()->withInput('register_form');📋 Template Examples
Without group:
{$errors.email}
<input type="text" name="name" value="{$old_input.name}" />With register_form group:
{$errors.register_form.email}
<input type="text" name="email" value="{$old_input.register_form.email}" />🔁 withInput()
Saves all user input (request()->all()) to restore after redirect:
return response()->back()->withErrors($errors)->withInput();In template:
<input type="text" name="name" value="{$old_input.name}" />🔧 Low-Level Methods
These methods manage core response parameters: content and status. They're typically used inside other methods (text, json, view, etc.), but can be useful for custom cases or extensions.
📄 setContent($content = '')
Sets the response "body" — the string that will be output to the user:
return response()->setContent('<p>Direct HTML</p>')->setStatusCode(200);📄 getContent()
Returns the current response content:
$content = response()->getContent();📊 setStatusCode($code, $text = '')
Sets the HTTP status code and description text. Validates the code:
return response()
->setStatusCode(403)
->setContent('Access Denied');If text isn't specified — uses standard text:
$response->setStatusCode(404); // "Not Found"📊 getStatusCode()
Returns the set HTTP code:
$code = response()->getStatusCode(); // e.g., 200📝 getStatusText()
Returns the status text description:
$text = response()->getStatusText(); // e.g., "OK"🚀 Sending the Response
All responses are finalized with:
📤 send()
This method:
- Writes flash data to
$_SESSION['pageblocks']['flash']; - Sets headers;
- Outputs content;
- Terminates execution with
exit.
This method is called automatically by the framework, but if you're building a response manually — don't forget to call send():
$response = response()->text('OK');
$response->send();🔚 Conclusion
The Response class is a universal and flexible component for PageBlocks controllers:
- 📄
text, 🌐html, 🔢json, 🧱object - 🖼️
view, 📥download - 🔁
redirect, 🔙back, 🛑abort - ✅
success, ❌error, ➕append - 🧾 Headers:
header(),setHeader(),withHeaders(),getHeaders(),removeHeader() - 💾 Flash data:
with(),withErrors(),withInput() - 🔧 Low-level control:
setContent(),setStatusCode(),getContent(),getStatusCode(),getStatusText() - 📤 Sending:
send()
With this tool, you can easily cover any scenario: from simple redirects to API responses and error handling.