Blacking's avatar

How to insert multiple pages into one route?

Good afternoon everyone!

I'm creating this post as there is something I'd like to do in Laravel which I did before in CodeIgniter but I'm not being able to figure out how,

I've developed my company's website in CodeIgniter and to avoid creating a Controller/Method for each page/route, I created a function that could iterate each one of these dynamically,

So my router in CodeIgniter looks like this:

$route['((\w{2})/)?(property-snagging|utilities-connections|insurance|off-plan-updates|key-holding|contact-us|coming-soon)'] = 'pages/view/';

So the same router loads a method according to each of these pages being requested in the URL and runs a function with the given page name as the parameter - how can I do the same in Laravel?

Thank you in advance

0 likes
10 replies
kokoshneta's avatar

You can use regex constraints on route definitions in Laravel, so you could do this:

Route::get('{lang?}/{page}', function ($lang = NULL, $page) {
	// Return your view or do whatever you need to here
	// The matched page name is available as $page, e.g.:
	return view("layout.$page", ['language' => $lang]);
})->where([
	'page' => 'property-snagging|utilities-connections|insurance|off-plan-updates|key-holding|contact-us|coming-soon',
	'lang' => 'en|de' // If you want to limit that too
]);
Tray2's avatar

In my book that defeats the purpose of a mvc with a router. I suggest using the KISS method here and follow the standard way of doing things. You will thank me later if you keep your controller methods small and DRY.

kokoshneta's avatar

@Tray2 I’m not sure I agree with that. If you have ten different routes who all do precisely the same thing – return a view whose name is identical to the route parameter, for example – then I think it’s more DRY not to create ten separate routes (with or without controllers).

Sure, you need to be careful that you’re not overworking it. If you need all manner of random extra logic to make it work, then separate routes and separate controllers (where needed) is clearly the way to do. But there are, I think, perfectly valid cases for doing this as well.

1 like
Tray2's avatar

@kokoshneta Maybe, but you would violate the S in SOLID, and what if the customer wants it to do something else all of a sudden, then you are up shit creek.

kokoshneta's avatar

@Tray2 Depends what you mean by ‘it’ – what if the customer wants what to do something else?

If they want to change what all ten routes do in ten different ways, then yes, you’ll have to add separate routes and controllers (where needed). But that would be no different if you’d already separated them – if the customer wants them all to change, you’d still have to modify all ten routes/controllers to their new desired behaviour.

If the customer wants all ten routes to change their behaviour in the same way – say, by having them all redirect to a help page instead of loading dynamic views – you’d be better off, since you’d only have to change one controller/function instead of ten.

If the customer wants just one or two routes to change their behaviour, you remove them from the regular expression and make a separate route for those.

I don’t think you’d be violating any SOLID principles really, since you’re not changing the responsibility of any classes. The only class that comes into play is the controller – if you even have one – and that controller’s responsibility remains the same: to return a view whose name matches the parameter passed to the function. Unless the customer wants it to do something else, like redirect to a help page, in which case its responsibility is completely nulled and reset, and I wouldn’t say that violates S either (if you think it does, you could always just make a new class for this responsibility and point the route to that class instead).

Blacking's avatar

Thank you for your reply @kokoshneta,

The thing is you're returning a view from within the route whereas I'd like to call a method inside a controller and pass an argument to it, such as

Route::get('{lang?}/{page}', function ($lang = NULL, $page) {
	// Return your view or do whatever you need to here
	// The matched page name is available as $page, e.g.:
	[App\Http\Controllers\PagesController::class, 'getPage($page)']
})->where([
	'page' => 'property-snagging|utilities-connections|insurance|off-plan-updates|key-holding|contact-us|coming-soon',
]);

Is it possible to do this?

Cheers

Tray2's avatar

@Blacking I would in that case create a method for each of the pages in the PagesController and have each action named after the page it's supposed to serve.

Blacking's avatar

@Tray2 I see, have you experienced doing the same and can you share in how it can be something negative and in what aspect? Or is it just a matter of good practice?

Tray2's avatar

@Blacking I have not attempted to do what you are trying, but I like to keep my code as simple as possible. Here is an example on how it might look

<?php

namespace App\Http\Controllers;

use App\Models\Book;
use App\Models\Record;
use Illuminate\Support\Facades\Auth;

class StaticPagesController extends Controller
{
    public function about()
    {
        return view('static_pages.about');
    }

    public function contact()
    {
        return view('static_pages.contact');
    }

    public function start()
    {
        if (Auth::check()) {
            return redirect(route('home'));
        }
        return view('static_pages.start')->with([
            'bookCounter' => Book::count(),
            'recordCounter' => Record::count()
        ]);
    }
}

Simple and pretty clean.

And the routes for it (Beware of the older syntax)

Route::get('about', 'StaticPagesController@about')->name('about');
Route::get('contact', 'StaticPagesController@contact')->name('contact');
Route::get('/', 'StaticPagesController@start')->name('start');
kokoshneta's avatar

@Blacking Route parameters are automatically passed to the controller function, so you just need to make sure the function expects those two parameters (and they need to be listed after any typehinted parameters you want the service provider to resolve for you).

Please or to participate in this conversation.