Home > Software design >  How to create an optional global first URL segment in Laravel 8
How to create an optional global first URL segment in Laravel 8

Time:02-25

We have a website that has events each year, this year's events would be shown here:

example.com/events

Route::get('/events', [EventController::class, 'index']);

But we want to create an archive of last year's events which would be shown on the following URLs:

example.com/2021/events
example.com/2020/events

We are able to create the following route to the same method:

Route::get('{year}/events', [EventController::class, 'index']);

Or we can create a separate method for each archive, but it's showing the same page, different content.

Route::get('{year}/events', [EventController::class, 'yearIndex']);

It would be much cleaner if there was a global way to detect if '2021' or '2020' was present in segment 1 globally then tell Laravel to ignore segment 1 and use segment 2 as the new base for all routing. This would be much cleaner. How to do this and how to pass the global $year variable to the methods to filter the content correctly.

We want to use the same method for both the archive (2020, 2021) and present events.

CodePudding user response:

Opinion based questions are usually closed. Before this happenes, I like to give you my opinion.

If the endpoint is different, not only the method, but the controller should be different. I would have created PastEventController and use index method with year parameter there. Of course, both index methods will probably be quite similar. So, extract the index to an action like IndexEvents, and than use it in both controller by passing the year. If the year null make current year in the action like.

class IndexEvents
{
   public function __invoke($year = null)
   {
       return Event::where('year', $year ?? date("Y"))->get();
   }
}

EventController:

public function index()
{
    return (new IndexEvents)();
}

PastEventController:

public function index($year)
{
    return (new IndexEvents)($year);
}

CodePudding user response:

Pretty sure you can do this

routes

Route::get('/events', [EventController::class, 'index']);
Route::get('{year}/events', [EventController::class, 'index']);

then index method

public function index( Request $request, $year = false ) {
    $selectedYear = $year ? $year : now()->format('Y');
    return Event::whereYear('created_at', $selectedYear)->paginate(20);
}
  • Related