Grouping all the laravel application routes using dynamic prefix - php

We have multiple client portal each one has a unique url like
xyz.com/ClientPotal123
xyz.com/ClientPotal234
xyz.com/ClientPotalXXX
We will be routing all these url's to
/var/www/html/Laravelapp/public
Laravelapp is our codebase which we use for all the clients.
Since ClientPotalXXX is dynamic and unique for all the clients, I need to get the value of ClientPotalXXX for loading client specific settings like url generation, database connection (We have different database for each client).
To achieve above I've done below changes..
My Web.php file is as below..
Route::pattern('ClientPortal','^ClientPortal([0-9]+)?');
Route::prefix('/{ClientPortal}')->group(function () {
Route::get('/user/list', 'UserController#list')->name('list');
Route::get('/user/edit/{id}', 'UserController#edit');
});
I've created Middleware with below code written in it..
public function handle($request, Closure $next)
{
$database_name = strtolower($request->ClientPortal).'_db';
config(['database.connections.mysql.database'=>$database_name]);
config(['app_settings.client'=>$request->ClientPortal]);
return $next($request);
}
And it's working fine but previously I used to access $id in edit function directly
public function edit($id){
echo $id; // 12
}
But now $id return the value of ClientPortalXX everytime.
If I access id from Request it works fine
public function edit(Request $request){
$id = $request->id; // 12
}
This is happening with all of the other routes where I'm using route parameters.
So I'm not sure if this happened because I'm using dynamic prefix for grouping all the routes?
And now for every route() method which I've used in blade files for url generation I have to pass the second parameter ie. Value of {ClientPortal}
{{route('register',['ClientPortal'=>config('app_settings.client')])}}
Is this right implementation? I know we can make any varibale accessible globally using service provider but will it be right to do so?
My Laravel Version is 5.5.xx.. I'm just a beginner so any Help/Suggestion/Advice will be appreciated Thanks :)
Update:
Nikola Gavric and Oluwafemi Sule had already clarified my doubt in comments below.
But since the group prefix is dynamic, How do I handle the route naming case?
If I had to generate user list url using list route name which is mentioned in above web.php file.
Now I've to change this line..
{{ route('list') }}
To
{{ route('list',['ClientPortal'=> 'ClientPortalXXX' ]) }}
Since prefix is also a route param.
Is this feasible option? Because I've to do this change everywhere where I've used route method for url generation.

Related

Naming routes different from Controller / Database

In a Laravel 5.8 app i want my url's to be in Dutch, however, for consistency and just general easier use, i want to name everything else by their English names. Eloquent will ( as far as i know ) only pass me the proper vars if my Model, Controller, table etc. are all named the same.
Right now, i have a route named /backend/facturen which in English would be /backend/invoices. I have tried using names routes, however, i found that this wasn't what i was looking for.
My route:
Route::resource('/backend/facturen', 'InvoicesController');
My show method inside the InvoicesController:
public function show(Invoice $invoice) {
return view('backend.invoice.show', compact('invoice'));
}
The database table is named 'invoices'.
The only way so far i have got this to work is by renaming my route to:
Route::resource('/backend/invoices', 'InvoicesController');
But, of course, this is not a solution to my problem.
I would like to see all data from the invoices show up on my ( Dutch ) /facturen route.
Resource controllers by default look for a variable with the same name as the (last part of the) URL, so renaming the URL changes that variable as well.
But you can tell Laravel to use a different name:
Route::resource('/backend/facturen', 'InvoicesController')->parameters([
'facturen' => 'invoice'
]);
You could also get the variable itself from the id, without using the laravel magic to correctly detecting the variable from the url:
public function show($id) {
$invoice = Invoice::findOrFail($id);
return view('backend.invoice.show', compact('invoice'));
}
No, you have registered a route pointing to the URL /backend/facturen, to name it, use the name function:
Route::resource('/backend/facturen', 'InvoicesController')->name('backend.invoice.show');
Even then, it won't show that route, when using the view function you need to pass the path to your template, not the route.

Laravel access route parameter in route web.php file

The parameter is posted to some_name like this:
{{ route('some_name', $id = '1'}}
How can I access it in the if condition?
Route::group(['prefix' => '/'], function()
{
if ( condition )
{
Route::get('/route/{id}', 'ControllerA#methodA')->name('some_name');
} else{
Route::get('/route{id}', 'ControllerB#methodB')->name('some_name');;
}
});
How can I use the {id} parameter in the if (condition)?
I tried
Route::group(['prefix' => '/'], function($id)
{
if ( $id == 1)
And it's not working.
I think the best thing you can do is a Middleware, for example:
public function handle($request, Closure $next)
{
if ($request->id == 'some_value') {
redirect action('ControllerA#methodA');
}
else {
redirect action('ControllerB#methodB');
}
return $next($request);
}
Check the docs, personally i've never done an if inside my routes folder, besides that, it's really dangerous to practice stuff like that, make everything happen in the views, if you are messing up with user logged in or not, do auth::check() or something like that, but never play with the routes web.php to ensure security in your app, everything else is made on the controllers and views.
I don't think it's a good practice to validate the id in the route file to redirect to different controllers, and heres why:
You'll send a request to that endpoint and send an ID.
Is that ID valid? How do you know?
Is the ID an integer or a string?
Does ID exists in the request?
and with these 3 questions, you'll end up having validations + redirect to different methods and if it's an ID of interest to a database query, you'll have database code in there aswell.
The normal procedure I like to think is when it hits the route, it should hit Authorization and Authentication (middleware as Bak87 said). In there, you can validate if he's authenticated, if he's a certain user, whatever you'd like.
Afterwards this initial validation, you can redirect it to a certain method in a certain controller depending on your needs, however, I wouldn't advise as a class should have a single purpose according to some standards (but in the end, you can build the application how you want it).
I believe a route or a group of routes should have an middleware (for whatever primary validation you require of the person making the request), and each route should point to a single method in a controller. Once it reaches the controller, instead of having (Request $request) as the parameters for the method, you can have your own custom FormRequest, where you can validate the ID if you'd like.
If FormRequest isn't of interest, you can use Eloquent (if the ID you're looking for is related to it) FindOrFail to validate if it exists (if it doesn't, returns a 404 error not found, if you have a 404.blade.php file). This way, by the time it reaches the controller's method, it has been validated by sections, where routes are then protected by the main Authorization and Authentication, FormRequest to do the input's validation and you can specifically return whatever you'd like from the controller's method.
Obviously we don't know what is the view your returning but if slighty differs from each other, consider refactoring it in order to return only 1 view, composed of other blades

Laravel. conflict with routes

I have a problemwith my routes. When I call 'editPolicy' I dont know what execute but is not method editPolicy. I think I have got problem beteweeb this two routes:
My web.php ##
Route::get('admin/edit/{user_id}', 'PolicyController#listPolicy')->name('listPolicy');
Route::put('/admin/edit/{policy_id}','PolicyController#editPolicy')->name('editPolicy');
I call listPolicy route in all.blade.php view like this:
{{ $user->name }}
And call editPolicy route in edit.blade.php view like this:
Remove</td>
My PolicyController.php is:
public function listPolicy($user_id)
{
$policies = Policy::where('user_id', $user_id)->get();
return view('admin/edit',compact('policies'));
}
public function editPolicy($policy_id)
{
dd($policy_id);
}
But I dont know what happend when I call editPolicy route but editPolicy method not executing.
Any help please?
Best regards
Clicking an anchor will always trigger a GET request.
route('listPolicy', $user->id) and route('editPolicy', $policy->id) will both return admin/edit/{an_id} so when you click your anchor, listPolicy will be executed. If you want to call editPolicy, you have to send a PUT request via a form, as defined when you declared your route with Route::put.
Quick note, your two routes have the same URL but seem to do very different things, you should differentiate them to avoid disarray. It's ok to have multiple routes with the same url if they have an impact on the same resource and different methods. For example for showing, deleting or updating the same resource.
Have a look at the documentation.

Final Route URL Change Laravel 5.5

I am working on a school project. while working on a schools detail page I am facing an issue with the URL. My client needs a clean URL to run AdWords. My school detail page URL: http://edlooker.com/schools/detail/4/Shiksha-Juniors-Ganapathy. But he needs it like http://edlooker.com/Shiksha-Juniors-Ganapathy. If anyone helps me out it will be helpful, thanks in advance.
You need to define this route after all routes in your web.php (if laravel 5.x) or in routes.php (if it is laravel 4.2).
Route::get('{school}','YourController#getIndex');
And your controller should be having getIndex method like this,
public function getIndex($school_name)
{
print_r($school_name);die; // This is just to print on page,
//otherwise you can write your logic or code to fetch school data and pass the data array to view from here.
}
This way, you don't need to use the database to get URL based on the URL segment and you can directly check for the school name in the database and after fetching the data from DB, you can pass it to the school details view. And it will serve your purpose.
Check Route Model Binding section in docs.
Customizing The Key Name
If you would like model binding to use a database column other than id when retrieving a given model class, you may override the getRouteKeyName method on the Eloquent model:
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'slug';
}
In this case, you will have to use one front controller for all requests and get data by slugs, for example:
public function show($slug)
{
$page = Page::where('slug', $slug)->first();
....
}
Your route could look like this:
Route::get('{slug}', 'FrontController#show');

Laravel Route Controller with Forced Parameter

So i have checked out
PHP - Routing with Parameters in Laravel
and
Laravel 4 mandatory parameters error
However using what is said - I cannot seem to make a simple routing possible unless im not understanding how filter/get/parameters works.
So what I would like to do is have a route a URL of /display/2
where display is an action and the 2 is an id but I would like to restrict it to numbers only.
I thought
Route::get('displayproduct/(:num)','SiteController#display');
Route::get('/', 'SiteController#index');
class SiteController extends BaseController {
public function index()
{
return "i'm with index";
}
public function display($id)
{
return $id;
}
}
The problem is that it throws a 404
if i use
Route::get('displayproduct/{id}','SiteController#display');
it will pass the parameter however the URL can be display/ABC and it will pass the parameter.
I would like to restrict it to numbers only.
I also don't want it to be restful because index I would ideally would like to mix this controller with different actions.
Assuming you're using Laravel 4 you can't use (:num), you need to use a regular expression to filter.
Route::get('displayproduct/{id}','SiteController#display')->where('id', '[0-9]+');
You may also define global route patterns
Route::pattern('id', '\d+');
How/When this is helpful?
Suppose you have multiple Routes that require a parameter (lets say id):
Route::get('displayproduct/{id}','SiteController#display');
Route::get('editproduct/{id}','SiteController#edit');
And you know that in all cases an id has to be a digit(s).
Then simply setting a constrain on ALL id parameter across all routes is possible using Route patterns
Route::pattern('id', '\d+');
Doing the above will make sure that all Routes that accept id as a parameter will apply the constrain that id needs to be a digit(s).

Categories