Laravel best naming convention for controller method and route - laravel

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.

Related

Laravel Route not defined error on FP_route

I'm having a problem with a POST, when I try to run the page and data is loaded in the database table I'm trying to read I always get a Route [MAILFP_Tree] not defined error.
The code is triggered by a call for the route in the blade file that will visualize the page
<form action="{{route('MAILFP_Tree')}}" method="post">
the routes are the following
Route::get('FP_Tree', 'HomeController#toFP_Tree')->middleware('auth');
Route::post('FP_Tree', 'MailController#toFP_Tree')->middleware('auth')->name('MAILFP_Tree');
This is the controller created for the post method (it's the one called mailController)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use \Illuminate\Support\Facades\Mail;
use App\Mail\emailFP_TreeRow;
use DB;
use Auth;
use App\AssociationHistorical;
class MailController extends Controller
{
public function toFP_Tree(Request $request)
{
$order_number = $request->input('order_number');
$customer_name = $request->input('customer_name');
$date_order_placed = $request->input('date_order_placed');
$item_number = $request->input('item_number');
$quantity = $request->input('quantity');
$item_description = $request->input('item_description');
$passed = array($order_number, $customer_name, $date_order_placed, $item_number, $quantity, $item_description);
Mail::to(Auth::user()->email)->send(new emailFP_TreeRow($passed));
//passes data to blade
$rows = AssociationHistorical::all();
return view('FP_Tree',[
'rows'=>$rows
]);
}
}
this is the content of the homecontroller
public function toFP_Tree()
{
//passes data to blade
$rows = AssociationHistorical::all();
return view('FP_Tree',[
'rows'=>$rows
]);
}
This is my migration table
Schema::create('association_historical', function (Blueprint $table) {
$table->id();
$table->string('order_number');
$table->string('item_number');
$table->string('item_description');
$table->date('date_order_placed');
$table->string('customer_name')->nullable();
$table->string('sales_rep_email');
});
The thing is that the problem happens when there is data in the association_historical table, most likely It is related to the fact that if there is no data in the database it won't run the post method, but i thought that it would make sense to show the database table...
the strange thing is that on someone else computer this works without any problem.
This is the result from PHP artisan route:list
+--------+----------+--------------------+-----------------------------+----------------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+--------------------+-----------------------------+----------------------------------------------------------+------------+
| | GET|HEAD | / | generated::UYk0LlF0PlICNJsK | App\Http\Controllers\LoginPageController#showLogin | web |
| | POST | / | login | App\Http\Controllers\LoginPageController#doLogin | web |
| | GET|HEAD | FP_Tree | generated::98bieUMU1hfvx1TH | App\Http\Controllers\HomeController#toFP_Tree | web |
| | | | | | auth |
| | GET|HEAD | Prediction | generated::4HdessOBvQL3KmpT | App\Http\Controllers\HomeController#toPrediction | web |
| | | | | | auth |
| | GET|HEAD | PredictionsLanding | generated::Xtf7I1MCKtlOSX3Y | App\Http\Controllers\HomeController#toPredictionsLanding | web |
| | | | | | auth |
| | GET|HEAD | UserManagement | generated::aOYFVG9JOLTfGjB5 | App\Http\Controllers\HomeController#toUserManagement | web |
| | | | | | auth |
| | GET|HEAD | api/user | generated::3SA9mFdg4RMncH1a | Closure | api |
| | | | | | auth:api |
| | GET|HEAD | logout | generated::YeCPB1fIxlH8JqDe | App\Http\Controllers\HomeController#doLogout | web |
| | | | | | auth |
+--------+----------+--------------------+-----------------------------+----------------------------------------------------------+------------+
it was so simple, thanks DigitalDrifter, just had to do a php artisan route:clear

Laravel 7 Route Group return 404 on some related routes

Route::group(['prefix'=>'cart'], function (){
Route::get('', 'CartController#index')->name('cart.index');
Route::get('{id}', 'CartController#create')->name('cart.create')->middleware('auth');
Route::any('update/{id}/{qty}', 'CartController#update')->name('cart.update')->middleware('auth');
Route::any('saveorder', 'CartController#store')->name('cart.store')->middleware('auth');
Route::any('delete/{rowId}', 'CartController#destroy')->name('item.delete')->middleware('auth');
Route::any('empty', 'CartController#empty')->name('cart.empty')->middleware('auth');
});
Some of the routes still works but some of them are broken and returning 404 even that the routes exist
the broken routes are : item.delete , cart.empty , cart.store
| auth:api |
| | GET|HEAD | cart | cart.index | App\Http\Controllers\CartController#index | web |
| | GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS | cart/delete/{rowId} | item.delete | App\Http\Controllers\CartController#destroy | web |
| | | | | | auth |
| | GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS | cart/empty | cart.empty | App\Http\Controllers\CartController#empty | web |
| | | | | | auth |
| | POST | cart/saveorder | cart.store | App\Http\Controllers\CartController#store | web |
| | | | | | auth |
| | PUT | cart/update/{id}/{qty} | cart.update | App\Http\Controllers\CartController#update | web |
| | | | | | auth |
| | GET|HEAD | cart/{id} | cart.create | App\Http\Controllers\CartController#create | web |
| | | | |
if you're using a GET method with cart.empty and cart.store then they will be handled by cart.create, you should put those routes first (order matters), also its better to be explicit with the route methods instead of using Route::any
Route::prefix('cart')->group(function () {
Route::get('', 'CartController#index')->name('cart.index');
Route::any('saveorder', 'CartController#store')->name('cart.store');
Route::any('empty', 'CartController#empty')->name('cart.empty');
Route::any('delete/{rowId}', 'CartController#destroy')->name('item.delete');
Route::any('update/{id}/{qty}', 'CartController#update')->name('cart.update');
Route::get('{id}', 'CartController#create')->name('cart.create');
});
Route::group(['prefix' => 'cart', 'middleware' => ['auth']], function(){
Route::get('/', 'CartController#index')->name('cart.index');
Route::get('/{id}', 'CartController#create')->name('cart.create');
Route::any('/update/{id}/{qty}', 'CartController#update')->name('cart.update');
Route::any('/saveorder', 'CartController#store')->name('cart.store');
Route::any('/delete/{rowId}', 'CartController#destroy')->name('item.delete');
Route::any('/empty', 'CartController#empty')->name('cart.empty');
});
Route::prefix('cart')->group(function (){
Route::middleware(['auth'])->group(function(){
Route::get('{id}', 'CartController#create')->name('cart.create');
Route::put('update/{id}/{qty}', 'CartController#update')->name('cart.update');
Route::post('saveorder', 'CartController#store')->name('cart.store');
Route::delete('delete/{rowId}', 'CartController#destroy')->name('item.delete');
Route::post('empty', 'CartController#empty')->name('cart.empty');
});
Route::get('/', 'CartController#index')->name('cart.index');
});
Two things to consider. Your cart.index could potentially match URI's underneath the route. For security, please try not to use Route::any if possible. As explained in https://laravel.com/docs/7.x/routing. As #Sobir suggests, run php artisan route:list and see your actual list of routes as Laravel sees it.
If something is missing or ambiguous, you may have to reconsider some route parameters to avoid confusion. Or regroup them in different ways. Your route list will certainly grow. Anticipate on what you're planning in the future of what you are building.

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 |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+

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 not able to route to controller

Here is my controller class:
class CallrequestController extends BaseController {
public function getIndex()
{
return View::make('results');
}
}
which is saved in:
--app
--controllers
--CallrequestController.php
then I autoloaded via composer:
composer dump-autoload
then i add the route to route file:
Route::controller('getrequest','CallrequestController');
here is the registered route via php artisan routes:
+--------+-------------------------------------------------------------------+------+-------------------------------------+----------------+---------------+
| Domain | URI | Name | Action | Before Filters | After Filters |
+--------+-------------------------------------------------------------------+------+-------------------------------------+----------------+---------------+
| | GET|HEAD / | | Closure | | |
| | GET|HEAD callrequest/index/{one?}/{two?}/{three?}/{four?}/{five?} | | CallrequestController#getIndex | | |
| | GET|HEAD callrequest | | CallrequestController#getIndex | | |
| | GET|HEAD|POST|PUT|PATCH|DELETE callrequest/{_missing} | | CallrequestController#missingMethod | | |
+--------+-------------------------------------------------------------------+------+-------------------------------------+----------------+---------------+
yet its not routing to the controller, i get the default "Whoops, looks like something went wrong." error message.
what am i doing wrong?
edit also here is a sample url:
mydomainname.com/getrequest

Resources