laravel advanced routing to multiple controllers - laravel

I have in a middleware those two routes so they stay on top of all other routes
Route::get('{slug?}', array(
'as' => 'homeIndex',
'uses' => 'Modules\\Pages\\Controllers\\Pages#index'
))->where('slug', '(.*)?');
Route::get('{company?}', array(
'as' => 'companyProfile',
'uses' => 'Modules\\Company\\Controllers\\Profile#index'
))->where('company', '(.*)?');
what I'm trying to achieve is route all pages through homeIndex and all companies profile through companyProfile all on the first segment.
Is working fine for pages, but for companies profile I get 404.
It's same like facebook if you go on facebook.com/about the result is about page if you replace about with your unique name you get your profile.
Any ideas how to make it work?

Facebook works because about is a route. This works because your unique name can never be about. So they look for the about route first, and if the segment isn't about, they know it's probably a unique name.
Yours is different because your app doesn't know if your first segment is a slug or a company so you need some way to tell it the difference. If you redirected everything to a single function, then in that function did some queries or whatever you need to do to figure out if the first segment is a slug or a company name, then redirect that appropriately, it would work.
Laravel reads routes from the top to the bottom. When you hit the route /some-random-company, Laravel has no idea this is a company. All it knows is it happens to match the first route so it hits the slug route with your company. So another solution would be to update the wheres on your routes so Laravel has some idea if the incoming route parameter is a slug or a company and will know where to route that request to.
I'm terrible at regular expressions and I don't know how you are making slugs or if there is any rules you have setup on what a company name can or can not consist of. What you would have to do is figure out if there is anyway where you can accurately determine if the route parameter is a slug or company. For example, if it has one or more of -, it might be a slug.
Then you'd have to write a regular expression pattern to look for multiple - and then put that pattern into the where for the slug route. Then if the route parameter is a company and it does not match that pattern which was looking for one or more of -, Laravel will know to match this request with the company route.
If there is nothing which you can use to determine if a string is a slug or a company, you will have to update your routes so it looks like company/{company?} and slug/{slug?} and then output your links appropriately. This way Laravel will know for sure where to route that traffic.

Related

Laravel. Conflict when building routes

There are two routes:
Route::get('/{article:slug}', [ArticleController::class, 'showArticlePage']);
and
Route::get('/{user:nickname}', [ProfileInfoController::class, 'getUserByNickname']);
Is there any way for each of the routes to perform its function?You can't change uri
For example:
domain.com/nickname => I have to get the user
There is a search in the table "users"
2.domain.com/my-first-article => I have to get the article
There is a search in the table "articles"
Note that each routes has its own controller and action, but they have a similar uri
You need something to distinguish them it'll be a lot more helpful. E.g use an # in front of usernames.
Another approach would be if you know for sure all slugs will have a hyphen, then you can chain ->where('slug', '...')
See https://pineco.de/handy-regex-constraints-in-laravel-routes/
Otherwise, it'll go through the first defined route.

Laravel 8 route order from bottom to top

I have installed Laravel 8 and work perfectly, and then i tried to learn about routing and try to make some routes like this
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing',[TestingController::class, 'noParameter'])->name('testingNoParam');
Route::view('testing', 'dashboard')->name('testingDashboard');
Some post in here said that routes in web.php work from top to bottom. But, thats not what i get when i called in url http://localhost/laraps/public/testing. it always called the bottom one. i tried to change the order, but still the last one always get called.
Any explanation for this one? or am i made any wrong configuration?
thanks for any help
A short explanation for this would be that each call to Route::{verb} creates a new route entry under your route collection (relevant code). {verb} ban be any HTTP verb e.g. get, or post etc. This entry is created under an array entry [{verb}][domain/url].
This means that when a new route is registered that matches the same URL with the same method it will overwrite the old one.
So in the case
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing',[TestingController::class, 'noParameter'])->name('testingNoParam');
Route::view('testing', 'dashboard')->name('testingDashboard');
Only the 3rd declaration actually "sticks". There are cases where multiple route definitions can match the same URL for example assume you have these routes:
Route::view('testing', 'welcome')->name('testingWelcome');
Route::get('testing/{optionalParameter?}',[TestingController::class, 'parameter'])->name('testingNoParam');
Route::view('testing/{otherParameter?}', 'dashboard')->name('testingDashboard');
In this case all 3 routes are added to the route collection, however when accessing URL example.com/testing the first matched route will be the one that will be called in this case the welcome view. This is because since all 3 routes are declared, once the router finds one matching route, it stops looking for more matches.
Note: There's generally no point in declaring multiple routes with the exact same URL so this is mainly an academic exercise. However there is often a use case for cases like e.g. model/{id} and model/list` to differentiate between getting info for a specific model and getting a list of models. In this case it's important to declare the routes as:
Route::get('model/list', [ ModelController::class, 'list' ]);
Route::get('model/{id}', [ ModelController::class, 'view' ]);
However you can be more explicit in route declarations using:
Route::get('model/{id}', [ ModelController::class, 'view' ])->where('id',
'\d+');
Route::get('model/list', [ ModelController::class, 'list' ]);
in this case the order does not matter because Laravel knows id can only be a number and therefore will not match model/list

Product And Category Separation In Route (Laravel)

I'm setting up a new route system.
Route::get('/{cat1Url}', 'CategoryController#showCat1')->name('showCat1');
Route::get('/{productUrl}', 'ProductController#showProduct')->name('showProduct');
My sef link is after "/"
But,
{{ route('showProduct',[$p->pr_url]) }}
This method not working with route name. Working only upside route.
I don't want use
"/cat/myVariable"
or
"/product/myVariable"
Can't I use route name to work this way?
What is the solution to this?
In this way, if you make a get request to /something the laravel you start from top of web.php file looking to a route that follows the pattern. Your both routes will follow that pattern, but the laravel will always, pass the first one to controller.
You have two options:
Put only one route, and inside the controller you switch to the appropriate function. But this isn't a great ideia, because this is the function of the Web.php.
Use the routes like the documentation recommend:
Route::get('/cat/{catId}', 'CategoryController#showCat')->name('showCat');
Route::get('/prod/{productId}', 'ProductController#showProduct')->name('showProduct');
and in Controller you make the appropriate handler of your Category or Product.
You will have to have a way to tell Laravel which url to be mapped to what otherwise it will always use the last defined route. So in your case calling /myVariable and /myVariable it will use the latest definition which is showProduct. The only other way is if you use regular expression to differentiate the variables. For example:
Route::get('/{cat1Url}', 'CategoryController#showCat1')
->name('showCat1')->where('cat1Url', 'cat-*');
Route::get('/{productUrl}', 'ProductController#showProduct')
->name('showProduct')->where('productUrl', 'prod-*');
This way your slugs need to start with what you define, but you cannot use just id as a numeric value for both.

Laravel: Automatically add parameter to urls

I have an application in which you can create a service and a service can have its own partial view.
So I created a route group with {service} prefix:
Route::group(['prefix' => '{service}', ... ], ... ).
// http://.../my-service/my-url
However, in order to know in which service the user is I need to add the service in every single route I have in my application. So I have done a middleware that shares $service to every view:
view()->share(['service' => $service])
But I don't know how to add $service prefix to every route without explicitly adding it. I would like doing something like
route()->prefix(['service' => $service])
and then every route have the prefix $service:
url("myurl") // -> url("$service/my-url") or
route('my-route')
Any idea?
EDIT:
Finally I decided to create a ServiceType model, create a middleware with a parameter and set to my route groups. Then in view I offer the user to switch between services of the same type.
Not is what I was looking but it's OK for now.
Question is still open if anyone knows the answer.
Put all your routes you want prefixed in a group and then add the prefix
Laravel docs on route prefixes

Why my routes are not ordered?

in my routes file I use a route group with segment like:
Route::group(['prefix' => request()->segment(1) ], function(){
//routes
});
Normally, my routes are in the order they were written at, but when using the group with request()->segment(1) routes just get disarranged (not just inside the group itself, but all of them), I need to use segment so every customer will have their own slug as the first segment in the URL.
so how can I fix this issue?
Use middleware to validate the user and allow them based on their slug
Please Make own middleware like jwt.auth
I developed my own middleware to filter slug based

Resources