Skip to content

📤 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:

php
$response = new Response();
$response->json(['name' => 'Sasha']);

But it's more convenient to use the response() helper:

php
response(['name' => 'Sasha']);

It automatically detects the content type — array, object, or text — and returns the appropriate response.

🧪 Controller Usage Example

php
Route::get('/', function () {
    return response()->json([
        'message' => 'Welcome!',
        'version' => '1.0.0',
    ]);
});

🧾 Response Methods

📄 text($text, $status = 200, $headers = [])

Returns plain text.

php
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>.

php
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.

php
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.

php
Route::get('/user', function () {
    $user = $modx->getObject(\modUser::class, 1);
    // or $user = query(\modUser::class)->find(1)
    return response()->object($user);
});
php
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.

php
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:

php
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:

php
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:

php
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:

php
Route::post('/form', function () {  
    // Process data...  
    return redirect()->back();  
});

♻️ refresh($status = 302)

Refreshes the current URL.

Example:

php
Route::get('/refresh', function () {  
    return redirect()->refresh();  
});

🏠 home($status = 302)

Redirects to the homepage (/):

Example:

php
Route::get('/logout', function () {  
    // Clear session...  
    return redirect()->home();  
});

🧭 route($name, $parameters = [], $status = 302)

Redirects to a named route.

Example:

php
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:

php
Route::post('/login', function () {  
    // Login check...  
    return redirect()->intended('/');  
});

How it works:

If you previously saved $_SESSION['_intended'] when accessing a protected page:

php
// 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:

php
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():

php
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.

php
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:

  • 403unauthorized_page
  • 404error_page
  • 503site_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.tpl

Example usage without parameters (returns 404 Not Found):

php
Route::get('/admin', function () {
    if (!auth('mgr')) {
        abort(); // will return the 404 page
    }

    return view('admin.panel');
});

📦 response() Helper

php
function response($content = '', int $status = 200, array $headers = []): Response

Behavior:

  • Array → json(...)
  • Object → object(...)
  • String → text(...)

Examples:

php
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.

php
Route::get('/download', function () {
    return response()->download('assets/files/manual.pdf');
});

You can rename the file during download:

php
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:
json
{
  "success": true,
  "message": "Saved successfully",
  "errors": [],
  "redirect": "/dashboard"
}
  • 📦 If not → redirects back (back() or redirect(...)), adds flash message and old input (withInput()).
php
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:
json
{
  "success": false,
  "message": "Validation error",
  "errors": {
    "email": "Invalid format"
  },
  "redirect": ""
}
  • 📦 HTML: Redirects back with flash message, withErrors() and withInput().
php
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().

php
Route::post('/form', function () {
    return response()
        ->append(['debug' => true])
        ->success('OK');
});

Result:

json
{
  "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()

php
return response()
    ->withBag('auth')
    ->success('You have successfully logged in!');

In template:

tpl
{$success_message.auth}  {* Outputs: You have successfully logged in! *}

❌ Example for error()

php
return response()
    ->withBag('auth')
    ->error('Login error', [
        'email' => 'Email not found',
        'password' => 'Wrong password',
    ]);

In template:

tpl
{$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:

tpl
{$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()):

php
return response()
    ->text('OK')
    ->header('X-Custom-Header', 'value123');

⚙️ setHeader($name, $value)

Manually sets or overrides a header.

php
$response = response()->setHeader('Cache-Control', 'no-store');

🧩 withHeaders(array $headers)

Bulk header addition. Often used when formatting responses.

php
return response()
    ->json(['ok' => true])
    ->withHeaders([
        'X-Request-ID' => uniqid(),
        'X-Frame-Options' => 'DENY',
    ]);

🔍 getHeaders()

Returns all headers set in the response:

php
$headers = response()->getHeaders();
print_r($headers);

Example output:

php
[
    'Content-Type' => 'application/json; charset=utf-8',
    'X-Powered-By' => 'PageBlocks',
]

removeHeader($name)

Removes a header if it was set:

php
$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:

php
return response()
    ->back()
    ->with('success_message', 'Record created');

With group:

php
return response()
    ->back()
    ->with('message', 'User updated', 'admin');

👜 withBag($name)

Sets a default group that will be used by all subsequent with() calls:

php
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:

php
return response()->back()->withErrors([
    'email' => 'Invalid format',
    'name' => 'Required field',
]);

With group:

php
return response()->back()->withErrors(['required' => 'Field is required'], 'validation');

🔁 withInput($name = '')

Saves all user input (request()->all()). Used to restore values after redirect:

php
return response()
    ->back()
    ->withErrors($errors)
    ->withInput();

With group:

php
return response()->withInput('register_form');

📋 Template Examples

Without group:

html
{$errors.email}
<input type="text" name="name" value="{$old_input.name}" />

With register_form group:

html
{$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:

php
return response()->back()->withErrors($errors)->withInput();

In template:

html
<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:

php
return response()->setContent('<p>Direct HTML</p>')->setStatusCode(200);

📄 getContent()

Returns the current response content:

php
$content = response()->getContent();

📊 setStatusCode($code, $text = '')

Sets the HTTP status code and description text. Validates the code:

php
return response()
    ->setStatusCode(403)
    ->setContent('Access Denied');

If text isn't specified — uses standard text:

php
$response->setStatusCode(404); // "Not Found"

📊 getStatusCode()

Returns the set HTTP code:

php
$code = response()->getStatusCode(); // e.g., 200

📝 getStatusText()

Returns the status text description:

php
$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():

php
$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.

© PageBlocks 2019-present