Skip to main content

Code style guide: Laravel


  • Гайд основан на
  • Соглашения принятые в уже устоявшейся кодовой базе имеют приоритет над данным гайдом


Configuration files must use kebab-case.


Configuration keys must use snake_case.

// config/pdf-generator.php
return [
'chrome_path' => env('CHROME_PATH'),

Do not use the env helper outside of configuration files. Create a configuration value from the env variable like above.

Artisan commands#

The names given to artisan commands should all be kebab-cased.

👍 # Good

php artisan delete-old-records

💩 # Bad

php artisan deleteOldRecords

A command should always give some feedback on what the result is. Minimally you should let the handle method spit out a comment at the end indicating that all went well.

// in a Command
public function handle()
// do some work

When the main function of a result is processing items, consider adding output inside of the loop, so progress can be tracked. Put the output before the actual process. If something goes wrong, this makes it easy to know which item caused the error.

At the end of the command, provide a summary on how much processing was done.

// in a Command
public function handle()
$this->comment("Start processing items...");
// do some work
$items->each(function(Item $item) {
$this->info("Processing item id `{$item-id}`...");
$this->comment("Processed {$item->count()} items.");


Public-facing urls must use kebab-case.

Prefer to use the route tuple notation when possible.

👍 # Good

Route::get('product-ratings', [ProductRatingsController::class, 'index']);

💩 # Bad

Route::get('product-ratings', ProductRatingsController@index');
<a href="{{ action([\App\Http\Controllers\ProductRatingsController::class, 'index']) }}">
Open Source

Route names must use camelCase.

👍 # Good

Route::get('product-ratings', [ProductRatingsController::class, 'index'])->name('productRatings');

💩 # Bad

Route::get('product-ratings', [ProductRatingsController::class, 'index'])->name('product-ratings');

All routes have an http verb, that's why we like to put the verb first when defining a route. It makes a group of routes very readable. Any other route options should come after it.

👍 # Good: all http verbs come first

Route::get('/', [HomeController::class, 'index'])->name('home');
Route::get('product-ratings', [ProductRatingsController::class, 'index'])->name('productRatings');

💩 # Bad: http verbs not easily scannable

Route::name('home')->get('/', [HomeController::class, 'index']);
Route::name('openSource')->get('product-ratings',[ProductRatingsController::class, 'index']);

Route parameters should use camelCase.

Route::get('news/{newsItem}', [NewsItemsController::class, 'index']);

A route url should not start with / unless the url would be an empty string.

👍 # Good

Route::get('/', [HomeController::class, 'index']);
Route::get('open-source', [OpenSourceController::class, 'index']);

💩 # Bad

Route::get('', [HomeController::class, 'index']);
Route::get('/open-source', [OpenSourceController::class, 'index']);


Controllers that control a resource must use the plural resource name.

class PostsController
    // ...

Try to keep controllers simple andTry to keep controllers simple and stick to Api Design Guide keywords (get, replace, patch, delete, search).

This is a loose guideline that doesn't need to be enforced.


View files must use camelCase.

class FavoritePostsController{
public function index() {
return view('favouritePosts');


When using multiple rules for one field in a form request, avoid using |, always use array notation. Using an array notation will make it easier to apply custom rule classes to a field.

👍 # Good

public function rules()
return [
'email' => ['required', 'email'],

💩 # Bad

public function rules()
return [
'email' => 'required|email',

All custom validation rules must use snake_case:

Validator::extend('organisation_type', function ($attribute, $value) {
return OrganisationType::isValid($value);

Blade Templates#

Indent using four spaces.

<a href="/favourite-posts">
Favourite Posts

Don't add spaces after control structures.



Policies must use camelCase.

Gate::define('editPost', function ($user, $post) {
return $user->id == $post->user_id;
@can('editPost', $post)
<a href="{{ route('posts.edit', $post) }}">

Try to name abilities using default CRUD words. One exception: replace show with view. A server shows a resource, a user views it.


Translations must be rendered with the __ function. We prefer using this over @lang in Blade views because __ can be used in both Blade views and regular PHP code. Here's an example:

<h2>{{ __('newsletter.form.title') }}</h2>
{!! __('newsletter.form.description') !!}

Naming Classes#


Generally controllers are named by the plural form of their corresponding resource and a Controller suffix. This is to avoid naming collisions with models that are often equally named.

e.g. UsersController or EventDaysController

When writing non-resourceful controllers you might come across invokable controllers that perform a single action. These can be named by the action they perform again suffixed by Controller.

e.g. PerformCleanupController


Both Eloquent resources and Fractal transformers are plural resources suffixed with Resource or Transformeraccordingly. This is to avoid naming collisions with models.

e.g. CustomersResource


Events will often be fired before or after the actual event. This should be very clear by the tense used in their name.

E.g. ApprovingLoan before the action is completed and LoanApproved after the action is completed.


Listeners will perform an action based on an incoming event. Their name should reflect that action with a Listener suffix. This might seem strange at first but will avoid naming collisions with jobs.

E.g. SendInvitationMailListener


To avoid naming collisions we'll suffix commands with Command, so they are easily distinguishable from jobs.

e.g. PublishScheduledPostsCommand

MAILABLES Again to avoid naming collisions we'll suffix mailables with Mail, as they're often used to convey an event, action or question.

e.g. AccountActivatedMail or NewEventMail


Generally domains (domain directories) should be named by the plural form without Domain suffix

e.g. Customers or Orders


Models should be named by the singular form without Model suffix

e.g. Customer

QUERIES from spatie/laravel-query-builder

Queries are named by the plural form of their corresponding resource and a Query suffix.

e.g. CustomersQuery


An action name should describe what it does and have Action suffix.

E.g. CreateCustomerAction