Skip to main content

FullUrlController

The FullUrlController is a fallback controller that resolves any unmatched request path against the versioned urls table. It provides smart URL resolution with automatic 301 redirects for legacy URLs.

Namespace​

JobMetric\Url\Http\Controllers\FullUrlController

Overview​

The controller handles:

  • Active URL matching: Finds active URLs and fires UrlMatched event
  • Legacy redirects: Automatically redirects (301) old URLs to canonical versions
  • 404 handling: Returns translated 404 when no match is found

Configuration​

Enable/disable the fallback route in config/url.php:

return [
'register_fallback' => env('URL_REGISTER_FALLBACK', true),
'fallback_middleware' => ['web'],
];

How It Works​

Request Flow​

  1. Normalize path: Builds candidate paths from request
  2. Check active URLs: Looks for active URL match
  3. Check legacy URLs: If no active match, checks soft-deleted URLs
  4. Redirect or 404: Redirects legacy URLs or returns 404

Path Candidates​

For a request like GET /shop/laptops/mbp-14, the controller checks:

  • shop/laptops/mbp-14
  • shop/laptops/mbp-14/
  • /shop/laptops/mbp-14
  • /shop/laptops/mbp-14/
  • / (for root paths)

Usage​

Basic Setup​

The controller is automatically registered when register_fallback is true:

// In routes (automatically registered)
Route::fallback(FullUrlController::class)
->name('JobMetric.url.fallback');

Event Handling​

Listen to UrlMatched event to handle active URLs:

use Illuminate\Support\Facades\Event;
use JobMetric\Url\Events\UrlMatched;

Event::listen(UrlMatched::class, function (UrlMatched $event) {
if ($event->urlable instanceof Product) {
$event->respond(view('products.show', ['product' => $event->urlable]));
}
});

Complete Examples​

Example 1: Product Page Handler​

Event::listen(UrlMatched::class, function (UrlMatched $event) {
if ($event->urlable instanceof Product) {
$event->respond(view('products.show', ['product' => $event->urlable]));
}
});

Example 2: Category Page Handler​

Event::listen(UrlMatched::class, function (UrlMatched $event) {
if ($event->urlable instanceof Category) {
$page = (int) $event->request->query('page', 1);
$products = $event->urlable->products()->paginate(24, ['*'], 'page', $page);
$event->respond(view('categories.show', [
'category' => $event->urlable,
'products' => $products,
]));
}
});

Example 3: API Response​

Event::listen(UrlMatched::class, function (UrlMatched $event) {
if ($event->request->wantsJson()) {
$event->respond(response()->json([
'url' => $event->url->full_url,
'model' => $event->urlable->toArray(),
]));
}
});

Example 4: Multiple Model Types​

Event::listen(UrlMatched::class, function (UrlMatched $event) {
$model = $event->urlable;

if ($model instanceof Product) {
$event->respond(view('products.show', ['product' => $model]));
} elseif ($model instanceof Category) {
$event->respond(view('categories.show', ['category' => $model]));
} elseif ($model instanceof Page) {
$event->respond(view('pages.show', ['page' => $model]));
}
});

Automatic Redirects​

Legacy URLs automatically redirect (301) to their canonical versions:

  • Request: /shop/old-path
  • Redirect: 301 → /shop/new-path
  • Query strings: Preserved in redirect