Skip to content

Conversation

@iam-subho
Copy link

Summary

This PR adds a new Artisan command php artisan route:conflicts that analyzes registered routes and detects potential routing conflicts where two routes could match the same incoming request.

The Problem

Route conflicts are a common source of subtle bugs in Laravel applications. When a parameterized route is defined before a literal route, the parameter route may "shadow" the literal one:

// This route will match /users/admin with id="admin"
Route::get('/users/{id}', [UserController::class, 'show']);

// This route will NEVER be reached!
Route::get('/users/admin', [AdminController::class, 'dashboard']);

These conflicts are difficult to detect manually in large applications with hundreds of routes, and often only surface in production when users report unexpected behavior.

The Solution

The new route:conflicts command provides:

  • Automatic conflict detection - Scans all routes and identifies potential conflicts
  • Constraint awareness - Respects where() constraints (e.g., ->where('id', '[0-9]+') won't conflict with /users/admin)
  • HTTP method checking - Only flags routes that share HTTP methods
  • Detailed output - Shows URIs, route names, and controller actions for each conflict
  • JSON output - --json flag for CI/CD pipeline integration
  • Proper exit codes - Returns 0 for no conflicts, 1 when conflicts are found

Usage

# Basic usage - human-readable output
php artisan route:conflicts

# JSON output for CI/CD pipelines
php artisan route:conflicts --json

Example Output

CLI format:

🚨 Route conflicts found:
[GET,HEAD]
  Earlier: users/{id} (App\Http\Controllers\UserController@show)
  Later:   users/admin (App\Http\Controllers\AdminController@dashboard)

JSON format:

[
  {
    "methods": "GET,HEAD",
    "earlier": {
      "uri": "users/{id}",
      "name": "users.show",
      "action": "App\\Http\\Controllers\\UserController@show"
    },
    "later": {
      "uri": "users/admin",
      "name": "admin.dashboard",
      "action": "App\\Http\\Controllers\\AdminController@dashboard"
    }
  }
]

Conflict Detection Logic

The command detects conflicts when:

  1. Two routes share at least one HTTP method
  2. Routes have the same number of URI segments
  3. For each segment position:
    • Both are literals and match, OR
    • At least one is a parameter that could match the other's value

The command correctly handles:

  • Parameter constraints via where() clauses
  • Multiple HTTP methods on a single route
  • Closure and controller-based routes
  • Named and unnamed routes

Why This Matters

  • Development - Catch routing issues early during development
  • Code Review - Quickly audit route files for potential problems
  • CI/CD - Integrate into pipelines to prevent deployment of conflicting routes
  • Debugging - Diagnose unexpected routing behavior in existing applications

Test Plan

  • Test no conflicts detected with non-overlapping routes
  • Test parameter vs literal conflict detection (/users/{id} vs /users/admin)
  • Test parameter constraints prevent false positives
  • Test parameter vs parameter conflict detection (/posts/{slug} vs /posts/{id})
  • Test different HTTP methods don't conflict
  • Test shared HTTP methods trigger conflict detection
  • Test different segment counts don't conflict
  • Test JSON output format and structure
  • Test CLI output format
  • Test multiple conflicts detection
  • Test named routes included in output
  • Test complex non-overlapping URIs
  • Test controller-based routes
  • Test literal-first ordering doesn't report false conflicts

Files Changed

  • src/Illuminate/Foundation/Console/RouteConflictsCommand.php - New command implementation
  • src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php - Command registration
  • tests/Foundation/Console/RouteConflictsCommandTest.php - Comprehensive test suite

Now developers can also verify route integrity with route:conflicts.

@taylorotwell
Copy link
Member

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants