Skip to main content

Code style guide: Laravel

Disclaimer:

  • Гайд основан на https://spatie.be/guidelines/laravel-php
  • Соглашения принятые в уже устоявшейся кодовой базе имеют приоритет над данным гайдом

Configuration

Configuration files must use kebab-case.

config/
pdf-generator.php

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

$this->comment('Finished!');
}

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->processItem($item);
});

$this->comment("Processed {$item->count()} items.");
}

Routing

Public-facing urls must use kebab-case.

https://project.ru/admin/product-ratings

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
</a>

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

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.

Views

View files must use camelCase.

resources/
views/
favouritePosts.blade.php
class FavoritePostsController{
public function index() {
return view('favouritePosts');
}
}

Validation

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
</a>

Don't add spaces after control structures.

@if($condition)
Something
@endif

Authorization

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) }}">
Edit
</a>
@endcan

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

Translations

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

CONTROLLERS

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

RESOURCES (AND TRANSFORMERS)

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

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

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

COMMANDS

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

DOMAINS

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

e.g. Customers or Orders

MODELS

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

ACTIONS

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

E.g. CreateCustomerAction