To be on the same page here is naming conventions you know and used a gazillion times:
StudlyCase/PascalCase
Example: StudlyCase
camelCase
Example: camelCase
snake_case
Example: snake_case
kebab-case
Example: kebab-case
Why do we need conventions?
Imagine you’ve User
and Post
models. You want to get all posts of a user. And we've one-to-many relationship between User
and Post
models.
Without conventions
// Posts table migration
// ...
$table->foreignId('author_id')->constrained();
// ...
Now when we are to define a relationship between User
and Post
models we have to write something like this:
// User model
// ...
public function posts()
{
return $this->hasMany(Post::class, 'author_id');
}
// ...
See the difference? We have to be explicit about the foreign key name.
With conventions
// Posts table migration
// ...
$table->foreignId('user_id')->constrained();
// ...
Now when we define a relationship between User
and Post
models it takes the shape of something like this:
// User model
// ...
public function posts()
{
return $this->hasMany(Post::class);
}
// ...
By using the well-defined conventions, we can omit the extra work that the framework already doing for us.
Now the boring part is over. Let’s get to the point.
Naming conventions
Models
Use singular form of the word. Example: User
, Post
, Comment
, Tag
. For multi-word models, use PascalCase. Example: UserPost
, UserComment
, UserTag
.
Tables
Use plural form of the word. Example: users
, posts
, comments
, tags
. For multi-word table names use snake_case
.
Controllers
Use singular form of the word. Example: UserController
, PostController
; appended Controller
suffix.
Routes
Use plural form of the word. Example: users
, posts
, comments
, tags
. For multi-word routes use kebab-case
.
// get all users
Route::get('users', [UserController::class, 'index'])
->name('users.index');
// show form to create a new user
Route::get('users/create', [UserController::class, 'create'])
->name('users.create');
// create a new user in the database
Route::post('users', [UserController::class, 'store'])
->name('users.store');
// show a specific user
Route::get('users/{user}', [UserController::class, 'show'])
->name('users.show');
// show edit form for a user populated with user data
Route::get('users/{user}/edit', [UsersController::class, 'edit'])
->name('users.edit');
// update a user in the database
Route::put('users/{user}', [UserController::class, 'update'])
->name('users.update');
// delete a user from the database
Route::delete('users/{user}', [UserController::class, 'destroy'])
->name('users.destroy');
The post
routes for a specific user
will look something like this:
// get all posts for a user
Route::get('users/{user}/posts', [PostController::class, 'index'])
->name('users.posts.index');
// show form to create a new post for a user
Route::get('users/{user}/posts/create', [PostController::class, 'create'])
->name('users.posts.create');
// create a new post for a user in the database
Route::post('users/{user}/posts', [PostController::class, 'store'])
->name('users.posts.store');
// show a specific post for a user
Route::get('users/{user}/posts/{post}', [PostController::class, 'show'])
->name('users.posts.show');
// show edit form for a post for a user populated with post data
Route::get('users/{user}/posts/{post}/edit', [PostController::class, 'edit'])
->name('users.posts.edit');
// update a post for a user in the database
Route::put('users/{user}/posts/{post}', [PostController::class, 'update'])
->name('users.posts.update');
// delete a post for a user from the database
Route::delete('users/{user}/posts/{post}', [PostController::class, 'destroy'])
->name('users.posts.destroy');
If we set up routes this way and have a posts
relationship defined on the User
model like this:
// User model
// ...
public function posts()
{
return $this->hasMany(Post::class);
}
// ...
Then we can use the posts
relationship and route model binding to get the PostController
method to work like this:
// PostsController
// ...
// create a new post for a user in the database
public function store(User $user)
{
$user->posts()->create($this->validatePost());
return redirect()->route('users.posts.index', $user);
}
// ...
Laravel’s conventions make the code more expressive and declarative while also saving us from writing extra code.
Named routes
Use plural form of the word and append the action name; e.g; users.index
using dot notation in b/w.
// users.index named route
Route::get('users', [UserController::class, 'index'])
->name('users.index');
For multi-word Model/action use kebab-case
; e.g; new-car.refuel-and-ignite
.
// new-car.refuel-and-ignite named route
Route::post('new-car/refuel-and-ignite', [NewCarController::class, 'refuelAndIgnite'])
->name('new-car.refuel-and-ignite');
Views
Directory structure
Use plural form of the word and all lowercase. Example: users
, posts
, comments
, tags
. For multi-word Model/action use kebab-case
;
File name Use index.blade.php
for listing all records, create.blade.php
for creating a new record, show.blade.php
for showing a specific record, edit.blade.php
for editing a specific record.
// UserController
// ...
// show all users
public function index()
{
$users = User::all();
// this is expressive and declarative and more aligned with the
// naming conventions we've been following
return view('users.index', ['users' => $users]);
}
// ...
Relationships
Use singular/plural form w.r.t relationship and use snake_case
for multi-word Model names.
// single-word has many relationship
public function posts()
{
return $this->hasMany(Post::class);
}
// multi-word has many relationship
public function user_posts()
{
return $this->hasMany(UserPost::class);
}
// loading single-word has many relationship
$users = User::with('posts')->get();
// loading multi-word has many relationship
$users = User::with('user_posts')->get();
When we defined the relationships with these naming conventions; they are fascinating and more aligned with dot (.) notation.
If we have a tags
relationship defined on the Post
; we can load it like this:
// load all users with their posts and tags
$users = User::with('posts.tags')->get();
Miscellaneous
For interfaces, you can use directory app/Contracts
.
For implementing the interface, you can use directory app/Actions
.
For traits, you can use directory app/Concerns
.
For others artisan
commands is there to help you put things in their right place.
Conclusion
I hope you find this article helpful. If you have any questions or suggestions, please feel free to comment below.