skip to Main Content

I have competition website, where I use web routes like this:

Route::get('results/{year?}', 'Results')->where('year', '[0-9]+');

This allows to sneak-peak into current year "unpublished" results, just by "hacking" URL.
I’d like to create custom routes for every year, so after I want publish results – I change routes file only. Is it possible in Laravel?

I red Laravel docs and tried to search for this problem, yet I was unable to find exact query for my problem, as there is lots of other similar questions with extra parameters.

I tried to experiment with possible route definitions, something like this, which do not work:

Route::get('results_2023', 'Results', ['year' => 2023])->where('year', '[0-9]+');
Route::get('results_2024', 'Results', ['year' => 2024])->where('year', '[0-9]+');

What I do not want – it’s redirect (URL transformation), so anyone using URL results_2025 would be redirect to results/2025, which I want to avoid.

3

Answers


  1. You could use the defaults method of the Route object to set default parameters that will be passed to the action:

    Route::get('results_2023', 'Results')->defaults('year', 2023);
    
    Login or Signup to reply.
  2. I would advice not to always change the route nor the controller for that matter. But you can add a custom validation inside the controller’s method.

    web.php

    Route::get('results/{year}', [ResultController::class, 'result']);
    

    ResultController.php

        public function result(Request $request, $year)
        {
            $validateYear = $this->validateResultYear($year);
    
            if ($validateYear->fails()) {
                return response()->json(['error' => $validateYear->errors()], 400);
            }
    
            // Validation passed, proceed with your logic
            switch ($year) {
                // ... switch cases based on year value
                // do something based on year
                // again use custom methods here per year if needed so that code is cleaner
            }
    
            // Return response or render view
        }
    
        public function validateResultYear($year)
        {
            // rules
            $rules = [
                'year' => 'required|integer|min:1900|max:2100', // adjust rules
            ];
    
            // messages
            $messages = [
                'year.required' => 'The year is required.',
                'year.integer' => 'The year must be an integer.',
                'year.min' => 'The year must be at least :min.',
                'year.max' => 'The year must not be greater than :max.',
            ];
    
            // create new request with year param
            $request = new Request(['year' => $year]);
    
            // validate
            $validator = Validator::make($request->all(), $rules, $messages);
    
            return $validator;
        }
    

    Did not test code but it should be enough for you to edit and get the result you want.

    Login or Signup to reply.
  3. As mention by other answer, you can use defaults method for passing parameter value from your route to your controller.

    but just additional thing,
    assume you have in your controller

    public function index( Request $request, $year ) {
        return [
            'year' => $year
       ];
    } 
    

    you should either remove the optional year

    // only support year from 2000 - 2023, add 19d{2} if you want to support year from 1900-1999
    Route::get('results/{year}', [Result::class, 'index'])
        ->where('year', '(20[01]d|202[0-3])'); 
    

    or have the year optional but provide a default value if you want the /results to have a default year

    Route::get('results/{year?}', [Result::class, 'index'])
        ->where('year', '(20[01]d|202[0-3])')
        ->defaults('year', now()->format('Y') );
    

    Then for additional routes without year parameter, just provide a default year value

    Route::get('results_2023', [Result::class, 'index'])->defaults('year', 2023);
    Route::get('results_2024', [Result::class, 'index'])->defaults('year', 2024);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search