Skip to content

🧭 Routing in PageBlocks

Routes define which code should execute when a specific URL is accessed on your site.

Example: if a user visits /about, you can set up a route to display the "About Us" page.

🔰 Basic Example

PageBlocks uses the Route facade to define routes:

php
use Boshnik\PageBlocks\Facades\Route;

Route::get('/about', function () {
    return 'This is the About page';
});

📥 When someone opens https://example.com/about, this function runs, and the user sees its output.

You can return the following from a route:

TypeResult
stringPlain text
arrayJSON
objectJSON or HTML (depending on content and headers)
ResponseExplicit response object using the Response class

Everything returned from a route automatically passes through Response::dispatchResponse, which determines how to properly send the result to the client.

📂 Where Are Routes Located?

All routes are stored in the core/App/routes folder of your project:

core/
└── App/
    └── routes/
        ├── web.php
        ├── api.php
        └── ...

🔄 All .php files in this folder are automatically loaded, and their routes are registered when the application starts.

📝 You can split routes into multiple files:

  • web.php — Main website routes
  • api.php — API routes
  • admin.php, auth.php, blog.php — Any additional route groups

The filename doesn’t matter as long as it’s in core/App/routes and has a .php extension.

⚙️ Route Methods

Each route is associated with an HTTP method—the way a browser or client sends a request to the server. Here are the main methods:

📄 Route::get($uri, $callback)

Responds to GET requests—when a user simply opens a page.

php
Route::get('/contact', function () {
    return 'Contact information';
});

📩 Route::post($uri, $callback)

Handles POST requests—commonly used when submitting forms.

php
Route::post('/feedback', function () {
    return 'Thank you for your feedback!';
});

📝 Route::put($uri, $callback)

Used for full resource updates.

php
Route::put('/profile', function () {
    return 'Profile updated';
});

🔧 Route::patch($uri, $callback)

Partial resource updates—for example, changing a single field.

php
Route::patch('/profile/email', function () {
    return 'Email updated';
});

🗑 Route::delete($uri, $callback)

Deletes a resource.

php
Route::delete('/account', function () {
    return 'Account deleted';
});

⚙️ Route::options($uri, $callback)

Handles OPTIONS requests—useful for CORS and APIs.

php
Route::options('/api/data', function () {
    return response('', 204)
        ->header('Allow', 'GET, POST, OPTIONS')
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
});

🔀 Route::match(array $methods, string $uri, $callback)

Defines a route that responds to multiple methods.
For example, if the same URL should handle both GET and POST:

php
Route::match(['GET', 'POST'], '/subscribe', function () {
    return 'Subscription form or its processing';
});

👆 This route will work for:

  • Opening /subscribe in a browser (GET);
  • Submitting a form to the same URL (POST).

Methods must be in uppercase (GET, POST, PUT, etc.).

🧮 Route::any(string $uri, $callback)

Responds to all HTTP request types: GET, POST, PUT, DELETE, PATCH, OPTIONS.

php
Route::any('/ping', function () {
    return 'pong';
});

This route will work regardless of the client’s method—useful if the request type doesn’t matter.

🔁 Redirect Routes

Sometimes, instead of processing a request, you just need to redirect the user to another URL. Use the redirect method for this.

🔁 Route::redirect($from, $to, $status = 302)

php
Route::redirect('/old-link', '/new-link');

👆 Anyone who opens /old-link will be automatically redirected to /new-link.

By default, this uses status code 302 (temporary redirect), but you can specify another:

php
Route::redirect('/moved', '/here', 301); // permanent redirect

📦 Useful for site reorganization or URL renaming.

🖼 Quick Route for Displaying a Template

If you just need to display a template without logic, use the Route::view method.

🖼 Route::view($uri, $view, $data = [])

php
Route::view('/about', 'pages/about');

👆 This route will render the pages/about.tpl template.

You can also pass data:

php
Route::view('/thanks', 'pages/thanks', ['title' => 'Thank you for your order']);

Internally, this method calls response()->view(...), so the result is identical to manually returning a template.

🧩 Route Parameters

Routes can contain variables—parameters that are automatically extracted from the URL and passed to the handler.

🎯 Required Parameters

php
Route::get('/user/{id}', function ($id) {
    return "User profile #$id";
});

👆 Visiting /user/42 will output: User profile #42.

❔ Optional Parameters

To make a parameter optional, add ? and specify a default value:

php
Route::get('/user/{name?}', function ($name = 'Guest') {
    return "Hello, $name!";
});

📥 /userHello, Guest!
📥 /user/AnnaHello, Anna!

🔍 Parameter Constraints — where()

Allows you to set regular expressions to validate parameters:

php
Route::get('/user/{id}', function ($id) {
    return "User #$id";
})->where('id', '\\d+');

👆 Now /user/abc won’t work—only digits (\d+).

Constraints can be set for multiple parameters:

php
Route::get('/post/{slug}/{id}', function ($slug, $id) {
    return "$slug: $id";
})->where([
    'slug' => '[a-z\-]+',
    'id' => '\\d+',
]);

📦 Accessing Request Inside a Route

To access request data, use dependency injection with Request:

php
use Boshnik\PageBlocks\Http\Request;

Route::post('/submit', function (Request $request) {
    $email = $request->input('email');
    return "You entered: $email";
});

🧃 Named Routes

Named routes are useful for generating links and redirects:

php
Route::get('/profile/{id}', function ($id) {
    return "Profile #$id";
})->name('profile.show');

Now you can generate a link to this route:

php
route('profile.show', ['id' => 7]); // /profile/7

🧭 This is especially helpful when generating links in templates or using redirects:

php
response()->redirect(route('profile.show', ['id' => $user->id]));

📦 Route Groups

The group() method lets you group routes and apply shared settings: prefix, middleware, controller, etc.

🔹 Basic Example

php
Route::group(function () {
    Route::get('/a', fn() => 'A');
    Route::get('/b', fn() => 'B');
});

Routes inside the group will be registered normally—without a prefix or additional parameters.

🏁 Prefix

Adds a common prefix to all routes in the group:

php
Route::prefix('/admin')->group(function () {
    Route::get('/dashboard', fn() => 'Dashboard');
    Route::get('/users', fn() => 'Users');
});

📥 Registered routes:

  • /admin/dashboard
  • /admin/users

🛡 Shared Middleware

php
Route::middleware('auth')->group(function () {
    Route::get('/cabinet', fn() => 'Personal account');
});

All routes in the group will be processed via the auth middleware.

👨‍🏫 Default Controller

Sets a shared controller for routes in the group:

php
Route::controller(ProfileController::class)->group(function () {
    Route::get('/edit', 'edit');
    Route::post('/update', 'update');
});

🔁 Calls the methods:

  • ProfileController->edit()
  • ProfileController->update()

🛡 Middleware

Middleware are intermediate handlers that run before the controller or closure executes. Examples include auth checks, CSRF protection, etc.

📌 Usage Example

php
Route::get('/dashboard', fn() => 'Dashboard')->middleware('auth');

🧩 Multiple Middleware

php
Route::middleware(['auth', 'admin'])->group(function () {
    Route::get('/admin', fn() => 'Admin');
});

🚫 Excluding Middleware

You can disable middleware applied earlier:

php
Route::get('/open', fn() => 'Open')->withoutMiddleware('auth');

🧾 Where Are Aliases Configured?

Middleware can be referenced by names (aliases) or full class names. Aliases are configured in app.php:

php
'middleware' => [
    'auth' => \App\Middleware\Auth::class,
],

🛑 Fallback Routes

If no route matches, you can define a fallback route that runs as a last resort.

🚨 Route::fallback($callback)

php
Route::fallback(function () {
    return response()->view('errors/404')->send();
});

📌 This route only triggers if no other route matches.

✅ Useful for custom 404 pages or other global handlers.

Always place fallback routes at the end of all other routes, or they might "catch" unintended requests.

🔐 CSRF Protection

All routes with POST, PUT, PATCH, or DELETE methods are automatically protected against CSRF attacks.

To pass the check, forms must include a hidden token field.

✅ Method 1: {csrf()}

You can use a convenient function in templates:

html
<form method="POST">
    {csrf()}
    <button>Submit</button>
</form>

This generates:

html
<input type="hidden" name="_token" value="{csrf_token}">

Also supports spoofing if _method is manually added:

html
<form method="POST">
    {csrf()}
    <input type="hidden" name="_method" value="PUT">
    <button>Update</button>
</form>

🛠 Method 2: Manually Insert the Token

You can manually add the hidden field:

html
<input type="hidden" name="_token" value="{csrf_token}">

Useful if you want full control over the HTML.

⚙️ Method 3: Meta Tag with Token

If you use pbFetch, it automatically looks for the CSRF token in a meta tag:

html
<meta name="csrf-token" content="{csrf_token}">

Then, pbFetch will include this token in the X-CSRF-TOKEN header when sending requests.

🔐 Token validation is handled by the VerifyCsrfToken middleware, which is automatically applied to all POST, PUT, PATCH, and DELETE routes.

If the token is missing or invalid, a 419 Page Expired error will be shown.

© PageBlocks 2019-present