Nesting resource controllers with additional URL params in Laravel 5 - laravel

I am trying to create routes for nested resource controllers in Laravel 5 like..
/customers/{customer}/modulename/clients/{client}
In the application I'm developing I have customers who are logging in to the application, but also sys-admins. Every customer can select multiple modules to use and within those modules there are sometimes the same models, but they're using different controllers.
I have used the following solutions, but they have some problems.
Route::resource('customers', 'CustomerController');
Route::resource('customers.clients', 'CustomerController');
I can't go for different modules in this solution, so I tried to make groups...
Route::group(['prefix' => 'customers/{customer}', ''], function(){
Route::group(['prefix' => 'module1', ''], function(){
Route::resource('clients', 'Module1\ClientAController');
});
Route::group(['prefix' => 'module2', ''], function(){
Route::resource('clients', 'Module2\ClientBController');
});
});
Route::resource('customers', 'CustomerController');
But the routes are getting annoying. When building the menu hierarchy this following route is quite difficult to create.
route('customers.{customer}.module1.clients.index');
Is what it should be, but I would like to get to go to...
route('customers.module1.clients.index');
Is there an option for the Route::group() function I'm missing or can I make a group within a route resource? Or should I just write out all the different Route::get and Route::post functions with the the $options = ['uses' => '...', 'as' => 'customers.module1.clients.*']

You can declare the following two routes:
Route::resource('customer','CustomerController');
Route::resource('customer.module.client','ClientController');
Then your routes would be like so:

Related

Multiple routes for the same controller function

I need to have 2 routes managed by the same controller function.
Instead of creating to different rules, I would like to create 1 rule.
So instead of something like this:
Route::get('/', ['uses' => 'MyController#index']);
Route::get('dashboard', ['uses' => 'MyController#index']);
I want to use 1 rule. I found out this multiple routes in single Route::get() call Laravel 4 but that code not works for me.
This is what I tried without success:
// THEY BOTH DO NOT WORK
Route::get('/{name}', ['uses' => 'MyController#index'])->where('name', 'dashboard|');
Route::get('/{name}', ['uses' => 'MyController#index'])->where('name', '(dashboard)?');
With these rules, if I go to / route I get 404 error.
If I go to dashboard route it works.
Making name a optional route parameter should work:
Route::get('/{name?}', ['uses' => 'MyController#index'])->where('name', 'dashboard');
Not sure why you are using uses, the shorter version would be:
Route::get('/{name?}', 'MyController#index')->where('name', 'dashboard');

What does 'as' method do in Laravel

In the example from the tutorial, it shows up.
Route::group([
'prefix' => 'admin',
'as' => 'admin.'
], function () {}
Can someone tells me what 'as' does? Also, is the dot next to the 'admin' neccessary?
Thank you.
Let's say, for example, that you have this route:
Route::get('admin', [
'as' => 'admin', 'uses' => 'AdminController#index'
]);
By using as you assign custom name to your route. So now, Laravel will allow you to reference said route by using:
$route = route('admin');
So you don't have to build the URL manually over and over again in your code. You don't really need . notation if you only want to call your route admin. If you want a more detailed name of your route, lets say for ex. admin product route, then you use the . notation, like this:
Route::get('admin/product', [
'as' => 'admin.product', 'uses' => 'AdminController#showProduct'
]);
So now, you will be able to call this route by the assigned name:
$route = route('admin.product');
Update:
The previous answer I provided is valid for a single routes. For the route groups, the procedure is very similar. In the route groups you need the . notation when you add a custom name, since you will be referencing another route after that . notation. This will allow you to set a common route name prefix for all routes within the group. So by your example, lets say you have a dashboard route inside your admin route group:
Route::group(['as' => 'admin.'], function () {
Route::get('dashboard', ['as' => 'dashboard', function () {
//Some logic
}]);
});
Now, you will be able to call the dashboard route like this:
$route = route(admin.dashboard);
You can read more about this in Laravel official documentation.
you may specify an as keyword in the route group attribute array, allowing you to set a common route name prefix for all routes within the group.
For Example
Route::group(['as' => 'admin::'], function () {
// Route named "admin::"
});
UseRoute Name like {{route(admin::)}} or route('admin::')
you can use an 'as' as a named route. if you do not prefix your route name in group route than you may add custom route name like this.
Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'roles'], 'roles' => ['2']], function () {
Route::post('/changeProfile', ['uses' => 'UserController#changeProfile',
'as' => 'changeProfile']);
});

Laravel 5.4 route simplification

I've been trying to find some documentation on how to accomplish the following, but it seems like maybe I'm not using the correct search terms.
I would like to implement some simplified routes in Laravel 5.4 by omitting the route name from the path – for example:
/{page} instead of /pages/{page}
/profile instead of /users/{user}/edit
/{exam}/{question} (or even /exams/{exam}/{question}) instead of /exams/{exam}/questions/{question}
Example of current routes
Route::resource('exams.questions', 'ExamQuestionController', ['only' => ['show']]);
// exams/{exam}/question/{question}
I know how to do this with route closures and one-off routes (e.g.: Route::get...) but is there a way to do this using Route::resource?
In rails the above could be accomplished with:
resources :exams, path: '', only: [:index, :show] do
resources :question, path: '', only: [:show]
end
// /:exam_id/:id
While I haven't yet found a way to accomplish my test cases using strictly Route::resource, here is what I implemented to accomplish what I was trying to do:
// For: `/{exam}/{question}`
Route::group(['as' => 'exams.', 'prefix' => '{exam}'], function() {
Route::get('{question}', [
'as' => 'question.show',
'uses' => 'QuestionController#show'
]);
});
// For: `/exams/{exam}/{question}`
Route::group(['as' => 'exams.', 'prefix' => 'exams/{exam}'], function() {
Route::get('{question}', [
'as' => 'question.show',
'uses' => 'QuestionController#show'
]);
});
// For: `/profile`
Route::get('profile', function() {
$controller = resolve('App\Http\Controllers\UserController');
return $controller->callAction('edit', $user = [ Auth::user() ]);
})->middleware('auth')->name('users.edit');
// For: `/{page}`
// --------------
// Note that the above `/profile` route must come before
// this route if using both methods as this route
// will capture `/profile` as a `{page}` otherwise
Route::get('{page}', [
'as' => 'page.show',
'uses' => 'PageController#show'
]);
No, you cannot and should not be trying to do this with Route::resource.
The whole purpose of Route::resource is that it creates the routes in a specific way that matches the common "RESTful Routing" pattern.
There is nothing wrong with wanting simpler routes (no one is forcing you to use RESTful routing), but you will need to make them yourself with Route::get, etc. as you already know.
From the documentation (not exactly your case, but related to it - showing that Route::resource is not meant to be super-configurable):
Supplementing Resource Controllers
If you need to add additional routes to a resource controller beyond the default set of resource routes, you should define those routes before your call to Route::resource; otherwise, the routes defined by the resource method may unintentionally take precedence over your supplemental routes:
Route::get('photos/popular', 'PhotoController#method');
Route::resource('photos', 'PhotoController');

Laravel grouping routes what is best prefix or middleware

When I start thinking grouping my routes and check the documentation. I lost there. There are too many things like prefix, middleware etc.
What is the best way to group routes?
Route::group(['middleware' => 'admin'], function () {});
Route::group(['prefix' => 'admin'], function () {});
Route::group(['namespace' => 'admin'], function () {})
Which approach is best? And why? When to use what approach?
Wait. Prefix and middleware are two different things
prefix is a way to Prefix your routes and avoid unnecessary typing e.g:
Route::get('post/all','Controller#post');
Route::get('post/user','Controller#post');
This can be grouped using prefix post
Route::group(['prefix' => 'post'], function(){
Route::get('all','Controller#post');
Route::get('user','Controller#post');
})
In the other hand, Middleware :
Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.
For example using last example now i want the users to be authenticated in my post routes. I can apply a middleware to this group like this:
Route::group(['prefix' => 'post', 'middleware' => ['auth']], function(){
Route::get('all','Controller#post');
Route::get('user','Controller#post');
})
You should check the docs to get more informed.
https://laravel.com/docs/5.5/middleware
https://laravel.com/docs/5.5/routing#route-groups
Both are different But to use both at the same time Best technique for grouping route middleware and prefix your route avoid unnecessary typing
Route::group(['prefix' => 'admin','middleware' => ['auth:admin']], function() {
Route::get('dashboard','AdminController#dashboard');
});
It may not be related to the current question, but if anyone is wondering how to use grouping prefix and middleware as well as controller in a scenario where you need auth check and then need a prefix to avoid repeat typing for the specific controller group, you may try the following way.
Route::middleware(['auth', 'verified'])
->controller(\App\Http\Controllers\AdminController::class)
->prefix('dashboard')->group(function() {
Route::get('/', 'adminIndex')->name('admin.index');
});
Or,
Route::group(['middleware' => ['auth', 'verified'], 'prefix' => 'dashboard'], function () {
Route::controller(\App\Http\Controllers\AdminController::class)->group(function (){
Route::get('/', 'adminIndex')->name('admin.index');
});
});

Using content ID and Slug in URI in Laravel route

Currently I have routes of the type:
lesson/{id}
and I would like to be able to use a slug as well in the path:
lesson/learn-how-to-play
so that both lesson/1 and lesson/learn-how-to-play bring me to the same page.
I Store the slug as a field in the Lesson table.
I have seen ways to use either, or but not both at the same time.
Then is is possible to call route('lesson.index', $lesson_id) and have it render the URI with the slug rather then the lesson ID?
You can use a regular expression to filter your routes with numeric ids:
Route::get(
'lesson/{id}',
['as' => 'lesson.index', 'uses' => 'ControllerName#byId']
)->where('id', '[0-9]+');
and then use the slug one as a fallback:
Route::get(
'lesson/{slug}',
['as' => 'lesson.index', 'uses' => 'ControllerName#bySlug']
);

Resources