laravel routing in web.php for self referring table - laravel

I am using laravel 5.6
I have a self referring table called "directory"
$table->increments('id');
$table->integer('parent_id')->unsigned()->default(null)->nullable();
$table->string('folder', 64);
$table->timestamps();
$table->unique(['parent_id', 'folder']);
For a root directory the "parent_id" will be null
How to create a resource route in web.php ? Something like:
Route::resource('directory.childdirectory','DirectoryController')->name('directory', 'dir_root_id', 'dir_child_id');
Is there any example CRUD for self referential relation?
How can a create a resource route in web.php for a self referential relationship?

The problem in short for a self referring table was how to pass the "parent" and "child" id to the controller. I did that by defining a resource controller in the routing table (web.php for laravel 5.6) with an additional parameter {id}
Route::resource('{id}/directory', 'directoryController');
Command php artisan route:list will look like the code below, where {id} is the parent directory and {directory} is the child directory
| POST | {id}/directory | directory.store
| GET|HEAD | {id}/directory | directory.index
| GET|HEAD | {id}/directory/create | directory.create
| GET|HEAD | {id}/directory/{directory} | directory.show
| PUT|PATCH | {id}/directory/{directory} | directory.update
| DELETE | {id}/directory/{directory} | directory.destroy
| GET|HEAD | {id}/directory/{directory}/edit | directory.edit

Related

API RESTful Laravel 6.x Best Practice for Many to Many Relatioship

I'm developing an API with Laravel 6.
I've got 2 models:
card -> table cards with card_id ecc.
user -> table users with user_id ecc.
I've defined into models many to many relationships
User.php
public function cards()
{
return $this->belongsToMany('App\Models\v1\Card');
}
Card.php
public function users() {
return $this->belongsToMany('App\Models\v1\User');
}
The pivot table is called card_user .
Now I've created routes for single entities:
Route::resource('v1/users', 'v1\UsersController');
Route::resource('v1/cards', 'v1\CardsController');
and I need to develop routes and controller for insert and delete rows from pivot table.
What is the best practice for this issue?
I try to solve this with a special controller that respond to a specific endpoint:
Route::resource('v1/cards/{id}/users', 'v1\CardsUsersController')->only([
'index', 'store', 'destroy'
]);
But when I need to store information I need to pass the ids of card and user into the URL and as object in post body like so:
[
'user_id' => $userId,
'card_id' => $cardId
]
Exists a better way to do this?
Thanks a lot!
You can use Nested Resources as described here:
https://laravel.com/docs/6.x/controllers#restful-nested-resources
"Sometimes you may need to define routes to a "nested" resource. For example, a photo resource may have multiple "comments" that may be attached to the photo. To "nest" resource controllers, use "dot" notation in your route declaration:
Route::resource('photos.comments', 'PhotoCommentController');
This route will register a "nested" resource that may be accessed with URLs like the following: photos/{photos}/comments/{comments}."
If you must have separate routes and controller for them, then it would be better to do
Route::resource('v1/card_user', 'v1\CardsUsersController')->only(['index', 'store','destroy']);
Keep the route clean, and don't overcomplicate it. Either You or someone else in the future who views code should be able to understand what it is for.
I would combine both answers. As a relationship, it is technically a nested resource. Also, you really have 2 RESTful actions: store and destroy (which correspond to attach and detach in Laravel). You may also want an index to view all of the relationship. I believe the "create" action is optional, depending on your UI.
// Ability_Role pivot routes
Route::resource('v1/user.cards', 'UserCardController')
->only(['index', 'create', 'store','destroy']);
This will give the following routes:
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| | GET|HEAD | v1/user/{user}/cards | user.cards.index | App\Http\Controllers\UserCardController#index | web |
| | POST | v1/user/{user}/cards | user.cards.store | App\Http\Controllers\UserCardController#store | web |
| | GET|HEAD | v1/user/{user}/cards/create | user.cards.create | App\Http\Controllers\UserCardController#create | web |
| | DELETE | v1/user/{user}/cards/{card} | user.cards.destroy | App\Http\Controllers\UserCardController#destroy | web |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
I chose to label the routes as user.cards because I would think you would more often want to start with the user model and attached the cards.
For the store method, you can post an array of cards to attached to the user.
If you also want to start with cards, and store an array of users, you can also define the inverse relationships (though it would require a 2nd controller with just the create and store routes:
// Inverse create and store routes
Route::get('v1/cards/{card}/users/create', 'CardUserController#create')
->name('cards.users.create');
Route::post('v1/cards/{card}/users', 'CardUserController#store')
->name('cards.users.store');
now you will get 2 more routes added:
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| | GET|HEAD | api/user | api. | Closure | api |
| | | | | | auth:api |
| | POST | v1/cards/{card}/users | cards.users.store | App\Http\Controllers\CardUserController#store | web |
| | GET|HEAD | v1/cards/{card}/users/create | cards.users.create | App\Http\Controllers\CardUserController#create | web |
| | GET|HEAD | v1/user/{user}/cards | user.cards.index | App\Http\Controllers\UserCardController#index | web |
| | POST | v1/user/{user}/cards | user.cards.store | App\Http\Controllers\UserCardController#store | web |
| | GET|HEAD | v1/user/{user}/cards/create | user.cards.create | App\Http\Controllers\UserCardController#create | web |
| | DELETE | v1/user/{user}/cards/{card} | user.cards.destroy | App\Http\Controllers\UserCardController#destroy | web |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+

Laravel best naming convention for controller method and route

I'm creating an ajax request to get item details
Here's what my controller method looks like.
class SystemItemsController extends Controller
{
function getDetails(Request $request){
$response = SystemItems::where('item_name', 'like', '%' .$name . '%')->get();
return response()->json($response,200);
}
}
and my
routing name
Route::get("/system-items/item-details","SystemItemsController#getStockDetails");
question : what would be the best naming convention for my route(item-details) and method(getStockDetails)?
follow up Q : can i do this using laravel resource?
You can use kebab-case and plural in the URI pattern, but camelCase and singular for Controller name, as that is what Laravel will look for if trying to do route–model binding.
You can use it for resouce routes, but note, for this route
Route::resource('item-details', 'ItemDetailController');
the route parameter will result in snake_case and singular
/item-details/{item_detail}
For the controller methods the conventional names are index, show, create, store, edit, update and delete. And snakeCase for custom methods.
Also you can add a route group to prefix with some uri like /system-items
Route::group(['prefix' => 'system-items'], function () {
Route::resource('item-details', 'ItemDetailController');
});
run php artisan route:list to see the result
+--------+-----------+-----------------------------------------------------+-------------------------+---------------------------------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+-----------------------------------------------------+-------------------------
| | GET|HEAD | api/v1/system-items/item-details | item-details.index | App\Http\Controllers\Api\v1\ItemDetailController#index | api |
| | POST | api/v1/system-items/item-details | item-details.store | App\Http\Controllers\Api\v1\ItemDetailController#store | api |
| | GET|HEAD | api/v1/system-items/item-details/create | item-details.create | App\Http\Controllers\Api\v1\ItemDetailController#create | api |
| | GET|HEAD | api/v1/system-items/item-details/{item_detail} | item-details.show | App\Http\Controllers\Api\v1\ItemDetailController#show | api |
| | PUT|PATCH | api/v1/system-items/item-details/{item_detail} | item-details.update | App\Http\Controllers\Api\v1\ItemDetailController#update | api |
| | DELETE | api/v1/system-items/item-details/{item_detail} | item-details.destroy | App\Http\Controllers\Api\v1\ItemDetailController#destroy | api |
| | GET|HEAD | api/v1/system-items/item-details/{item_detail}/edit | item-details.edit | App\Http\Controllers\Api\v1\ItemDetailController#edit
Of course, all of these are conventions and you can customize everything by doing it by hand and using your own conventions.

Laravel 6.0 How to use Route:resource get route same folder controller

I have question and I'm can't find a solution in document
I use command
php aritsan make:controller Backend\ProductController --resource --Model=Model\Product
So, I will need route same location file controller
I use
Route::resource('/backend/product','Backend\ProductController');
after, run a command
php artisan route:list
and this result
But, I don't need this
I think should be
+--------+-----------+----------------------------------+-----------------+------------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+----------------------------------+-----------------+------------------------------------------------------------+------------+
| | GET|HEAD | backend/product | backend.product.index | App\Http\Controllers\Backend\ProductController#index | web |
| | POST | backend/product | backend.product.store | App\Http\Controllers\Backend\ProductController#store | web |
| | GET|HEAD | backend/product/create | backend.product.create | App\Http\Controllers\Backend\ProductController#create | web |
Route name should be backend.product.index
I find a solution. but not happy.
Route::resource('/backend/user','Backend\UserController')->names([
'index' => 'backend.user.index',
'store' => 'backend.user.store',
'edit' => 'backend.user.edit',
'update' => 'backend.user.update',
'destroy' => 'backend.user.destroy',
]);
Documents resource names
The command for creating Model Controller with resource
php artisan make:controller Backend\ProductController --resource --Model=Model\Product
Change web.php and use prefix, namespace, as
Route::group(['prefix' => 'backend','namespace'=>'Backend','as'=>'backend.'], function () {
Route::resource('product','ProductController');
});
Now use
php artisan route:list
backend.product.index
backend.product.create
backend.product.show
backend.product.destroy
backend.product.update
backend.product.edit
refer Routing page in Laravel Documents for more details.
https://laravel.com/docs/5.8/routing#route-group-prefixes

Route::resource binding creates plural attribute routes (i.e. projects/{projects})

I am trying to set up a Route:resource for Series.
When I create individual get, post, patch and delete Routes it works as expected (e.g. GET series/${serie}).
However when I use Route::resource it creates plural attributes (e.g. GET series/${series}).
In the laracast that I am following it creates the singular (e.g. GET projects/${project}).
I can't figure out what I am missing.
This works:
Route::get('/series', 'SeriesController#index');
Route::get('/series/create', 'SeriesController#create');
Route::get('/series/{serie}', 'SeriesController#show');
Route::post('/series', 'SeriesController#store');
Route::get('/series/{serie}/edit', 'SeriesController#edit');
Route::patch('/series/{serie}', 'SeriesController#update');
Route::delete('/series/{serie}', 'SeriesController#destroy');
The route list is:
GET|HEAD | series | App\Http\Controllers\SeriesController#index
POST | series | App\Http\Controllers\SeriesController#store
GET|HEAD | series/create | App\Http\Controllers\SeriesController#create
GET|HEAD | series/{serie} | App\Http\Controllers\SeriesController#show
PATCH | series/{serie} | App\Http\Controllers\SeriesController#update
DELETE | series/{serie} | App\Http\Controllers\SeriesController#destroy
GET|HEAD | series/{serie}/edit | App\Http\Controllers\SeriesController#edit
This doesn't work:
Route::resource('series', 'SeriesController');
and produces this route list:
GET|HEAD | series | App\Http\Controllers\SeriesController#index
POST | series | App\Http\Controllers\SeriesController#store
GET|HEAD | series/create | App\Http\Controllers\SeriesController#create
GET|HEAD | series/{series} | App\Http\Controllers\SeriesController#show
PATCH | series/{series} | App\Http\Controllers\SeriesController#update
DELETE | series/{series} | App\Http\Controllers\SeriesController#destroy
GET|HEAD | series/{series}/edit | App\Http\Controllers\SeriesController#edit
Notice the plural form {series}. Why is this happening?
"Series" is the plural as well as the singular of the word, therefore the routes Laravel is generating are perfectly fine.
If you have a look into Laravels pluralizer helper, you can even see that "series" is explicitely listed as uncountable: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/Pluralizer.php#L49

Laravel routes prefix and ressources resulting in 404 not found

I've this Laravel routing issue. I don't really understand why my route:list tells me that an {} empty is appended to the URL? I believe this is the reason why my calls returns 404 not found.
I'd like DepartmentController to be inside my grouped body as I need the ID for other purposes. If I move ressource outside the prefix/group this scenarie works, but the other dosen't. This is my preferred way of structuring my routes, but it troubles me that / dosen't just use the prefixed URL, but it for some reason append it with {}
What am I doing wrong?
Calling URL: /department/1/edit
Result: 404 Not Found
Routes:
Route::prefix( 'department/{department_id?}' )->group( function () {
Route::resource( '/', 'DepartmentController' );
}
php artisan route:list:
| | GET|HEAD | department/{department_id?}/{} | show | App\Http\Controllers\DepartmentController#show | web |
| | PUT|PATCH | department/{department_id?}/{} | update | App\Http\Controllers\DepartmentController#update | web |
| | DELETE | department/{department_id?}/{} | destroy | App\Http\Controllers\DepartmentController#destroy | web |
| | GET|HEAD | department/{department_id?}/{}/edit | edit | App\Http\Controllers\DepartmentController#edit | web |
| | GET|HEAD | department/{department_id?}/create | create | App\Http\Controllers\DepartmentController#create | web |
| | POST | department/{department_id?} | store | App\Http\Controllers\DepartmentController#store | web |
| | GET|HEAD | department/{department_id?} | index | App\Http\Controllers\DepartmentController#index | web |
Update:
If I make a custom route like this:
Route::get( 'customedit', 'DepartmentController#editasddas' );
and request the url: /department/1/editasddas. It works as it's suppose to, but there is actually a reason why I'm using the ressource: to keep the routes as clean as possible. The ressource-routes have been implemented for that reason aswell, and I just need to implement the basic CRUD operations. Is this a bug in Laravel, or is this basically not possible? - really strange I think. It's not that complex.
I think you have this issue because how Route::resource creates subroutes itself (automatically adding a resource parameter within URLs, the parameter being {} at the end).
Also, note you are currently generating a index route with a department parameter, and that's not really useful.
Best solution for me is to move out your parameter:
Route::prefix( 'department' )->group( function () {
Route::resource( '/', 'DepartmentController' );
});
In the other hand, the department_id parameter will not be facultative. And you will need to add the parameter within each other custom routes (but that's what Route::resource does with its own routes after all).
Second one is to keep your prefix and declare each route individually. But you will need to change the default route names because department.index and department.show will have the exact same methods (GET and HEAD) and URLs (department/{department_id}).
Route::prefix('department/{department_id}')->group(function() {
Route::match(['get', 'head'], '/', 'DepartmentController#index')->name('department.index');
Route::match(['get', 'head'], '/show', 'DepartmentController#show')->name('department.show');
/* Declare all the others. */
});
The Route::resource method alone will achieve what you're looking for:
Route::resource( 'department', 'DepartmentController' );
Check the docs on this here, https://laravel.com/docs/5.8/controllers#resource-controllers

Resources