dragon-code/extended-routes
A small Laravel package that extends the native router with extra helper methods and macros, letting you declare routes more concisely while staying fully compatible with standard Laravel routing, middleware, and route caching.
Install it like any small Laravel helper:
composer require dragon-code/extended-routes
There is no config file to publish and no migration step. Laravel package auto-discovery registers the service provider. After install, the first thing to inspect is the package source (src/) and the README, because the value of this package is a thin routing macro layer rather than a large framework. Then run:
php artisan route:list
to see exactly which routes the macro adds to your application. That is the fastest way to verify the package's behavior against your Laravel version.
The first realistic use case is a soft-deletable resource. Instead of hand-writing restore and force-delete routes next to Route::resource(), you register the resource and let the package add the trashed endpoints:
// routes/web.php
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
Route::resource('posts', PostController::class)->withTrashed();
The resulting resource now includes the normal CRUD routes plus the trashed operations, typically:
PATCH /posts/{post}/restore → posts.restoreDELETE /posts/{post}/force → posts.forceDeleteYour controller then implements the corresponding actions:
public function restore(Post $post)
{
$post->restore();
return back()->with('status', 'Post restored.');
}
public function forceDelete(Post $post)
{
$post->forceDelete();
return redirect()->route('posts.index');
}
That is the day-to-day win: fewer hand-maintained routes, consistent naming, and soft-delete behavior expressed directly in the route definition.
The current release line is 4.x; 4.0.1 is a patch that only adjusts Composer dependency constraints. It adds no routes, options, or config, so the install and first-use flow above is unchanged from 4.0.0. Treat the upgrade from 4.0.x as a routine composer update and re-run route:list afterwards to confirm nothing shifted.
Use resource routes as the default, not the exception. The package is most useful when your application already follows Laravel resource conventions. Register the resource once and chain the trashed behavior:
Route::resource('posts', PostController::class)->withTrashed();
For API-only controllers, keep the same pattern with apiResource so you do not accidentally expose create and edit HTML routes:
Route::apiResource('posts', PostController::class)->withTrashed();
Confirm the exact chained method names against the package README/source for your installed version, then standardize on one form across the codebase so route definitions stay predictable. The 4.0.1 patch did not change this surface, so any snippets you collected for 4.0.0 remain valid.
Pair the routes with route model binding that can see trashed models. The restore and force-delete endpoints receive a model that is soft-deleted, so implicit binding will normally return 404. Resolve it explicitly:
public function restore(Post $post)
{
// If the route binding does not already include trashed models:
// $post = Post::withTrashed()->findOrFail($post->id);
$post->restore();
return response()->noContent();
}
A cleaner pattern is a dedicated route binding for the trashed actions, or a small base controller method that resolves with withTrashed(). Do this consistently so restore/force-delete never fail because of binding behavior.
Authorize the trashed actions separately. Policies usually need restore and forceDelete abilities in addition to update and delete. Wire them through middleware or authorize() calls:
public function restore(Post $post)
{
$this->authorize('restore', $post);
$post->restore();
return back();
}
If you use Route::resource(...)->withTrashed() inside a group with auth middleware, the authorization still belongs in the controller or policy — routing does not enforce it.
Keep URL design consistent across nested resources. For nested soft-deletable resources, use shallow nesting or explicit parameters so restore/force-delete URLs remain readable:
Route::resource('users.posts', PostController::class)
->shallow()
->withTrashed();
Check route:list afterward; nested resource parameter names and generated route names are the most common source of surprises.
Expose trashed listings deliberately. A common workflow is a normal index for active records and a query flag or separate endpoint for trashed ones:
public function index(Request $request)
{
$posts = $request->boolean('trashed')
? Post::onlyTrashed()->paginate()
: Post::paginate();
return view('posts.index', compact('posts'));
}
If the package provides a trashed-index helper in your version, prefer it; otherwise keep the filter in the controller so the route surface stays small.
Use form method spoofing in Blade. Restore and force-delete are PATCH/DELETE routes, so forms need @method:
<form method="POST" action="{{ route('posts.restore', $post) }}">
@csrf
@method('PATCH')
<button type="submit">Restore</button>
</form>
Test the generated routes, not just the controller. Feature tests should hit the restore and force-delete endpoints and assert both the database state and the authorization behavior. Route-level tests catch naming and parameter regressions early.
composer update previously failed or resolved oddly, this release is the fix. If you are pinned to 4.0.0, upgrading is low risk — but still re-run your route tests, since a composer.lock churn can pull a different Laravel/Illuminate minor that affects routing internals.withTrashed() support on resource registrations. Avoid chaining both a native and package-provided trashed helper, or you may register duplicate routes and get name collisions.php artisan route:clear and php artisan route:cache in deployment. Macros registered too late in the boot cycle may not appear in the cached route table.restore and forceDelete before writing controller logic.route('posts.restore', $post) depends on the resource parameter being {post}. If you customize ->parameters() or use nested resources, regenerate URLs through the helper rather than hard-coding paths.restore/forceDelete policy methods and test them; otherwise any authenticated user with the URL can act.route:list. Use php artisan route:list --name=posts and --columns=method,uri,name,action,middleware to verify exactly what the package registered. This is more reliable than assuming from the README.AppServiceProvider::boot(). For a package this size, a local macro is often the cleanest long-term answer.How can I help you explore Laravel packages today?