Fork me on GitHub

Welcome

This site serves as a guide for those who is using Laravel Framework by Taylor Otwell and its contributors.
Laravel : Best Practices aims to put together all the resources and best practices in using the Laravel Framework.

Laravel Framework is not strict on how and where you define your classes as long as it could be loaded by Composer. This is a double-sided blade – it’s beneficial for advanced developers, but could be confusing for beginners and for those who is trying to reverse engineer an existing codebase. The ability to place anything, anywhere is good. But there are times some methods is way better than the others, and that is what we are after. This site tried to collect all the best practices, tools and methodologies, so that it could serve a guide for beginners and existing developers alike.

This is a living document and will continue to be updated with more helpful information and examples as they become available.

Translations

Laravel: The Best Practices is currently available in the following languages. Please contribute to the project so that it could support multiple languages.

How to Contribute

Help make this website the best resource for new PHP programmers! Contribute on GitHub

Spread the Word!

Laravel Best Practices has web banner images you can use on your website. Show your support, and let new PHP developers know where to find good information!

See Banner Images

Download the Android Application

Get it in Google Play

Back to Top

Getting Started

The Ecosystem

At the very minimum, you need to know how to use Git and Composer. Though not required, it is better that you have an account on GitHub.com as it is where all the code and its dependencies are hosted.

You MUST be comfortable in using Command Line Interface (CLI), specially Unix Shells (sh, ksh, csh, tcsh, bash etc) as it is heavily used for common tasks in working with Laravel.

For local development, you’ll need to have at least Vagrant and VirtualBox installed. This is used by Homestead (a special vagrant box made for running Laravel apps). Although you can use the traditional WAMP/MAMP/XAMPP stack, those are not officially supported, thus you might have hard time down the road.

Pure “Laravel-way” frontend development might be a daunting one as it got has a long chain of technologies. You can either use Laravel Blade which is server-side templating or do client-side (browser), which at the very top of the chain is Mix, a wrapper for Webpack. Webpack has its dependencies managed through npm, all of which are packages of NodeJS.

CSS is managed either through Sass or LESS, while JavaScript can be done through Plain JavaScript, ReactJS and the more common frontend framework used with Laravel: VueJS.

For the backend stack, at the very least, you need a web server like Nginx, a php interpreter like PHP-FPM and a database like MySQL. Other optional stack components are Memcached, Redis and Beanstalkd.

While you are not required to understand them all at once, it is advantagous that you are at least familiar with these and do some reading about what they are and where they are being used. This will save you tons of confusion when reading the documentation and references in the future.

How to read this guide

This guide is divided into several sections such as each one tries to group related conventions. For example, all database-related convention is grouped in the same section. Each of the convention have the following keywords, which indicates how important it is to comply with such convention:

the above specifications is derived from RFC 2119

Back to Top

Environment

Local Environment

There are multiple ways to run Laravel in local environment as outlined below:

You are free to choose which local environment that works for you and your team as long as the following conditions are met:

Staging Environment

Staging servers is a type of server that is used to test a software, website or service in a production-similar environment before being set live. It is the role of a staging environment or staging site, to serve as a temporary hosting and testing server for any new software or feature.

Production Environment

You MUST regularly rotate your APP_KEY

APP_KEYS are set when you initialized a new Laravel application or executed the following command

php artisan key:generate 

Laravel uses the key for all encrypted cookies, including the session cookie, before handing them off to the user’s browser, and it uses it to decrypt cookies read from the browser. This prevents the client from making changes to their cookies and granting themselves admin privileges or impersonating another user in your application. Encrypted cookies are an important security feature in Laravel

From APP_KEY And You

Back to Top

Configuration

Environment Variables

You MUST put sensitive information into .env files

Use .env files to store any secure information and retrieve it via env function. There should be no instance on which you will put it inside models/controllers and commit it to Git.

Good

// .env 

API_HOST=https://example.com/api
API_USERNAME=myuser
API_PASSWORD=secret


// access the value from app/config.php file

return [
    ...
    'api_host' => env('API_HOST', 'https://defaultdomain.com')
    'api_username' => env('API_USER', 'defaultuser')
    'api_password' => env('API_USER', 'defaultpassword')
    ...
]

Bad

define('API_HOST', 'https://defaultdomain.com');
define('API_USERNAME', 'defaultuser');
define('API_PASSWORD', 'defaultpassword');

class DomainController extends Controller
{
    public function index()
    {
      $api_username   
    }

your application key MUST be set. This is the APP_KEY variable in your .env file. You can generate one via

php artisan key:generate

Application Namespace

php artisan app:name YourAppName

This makes your controllers/models etc resolve into YourAppName\Controllers and YourAppName\Models

Package Configuration

Custom or Package configuration filename MUST be in snake_case

Good

config/my_config.php

Bad

config/MyConfig.php

Config and language files indexes SHOULD be in snake-case

Good

// config/myconfig.php
return [
    'my_api' => [
        'domain' => env('API_DOMAIN'),
        'secret' => env('API_SECRET'),
    ],

Bad

// config/myconfig.php
return [
    'MyApi' => [
        'DOMAIN' => env('API_DOMAIN'),
        'SECRET' => env('API_SECRET'),
    ],

The best way to figure out if you have implemented best-practice in configuring your app, is if the codebase could be made open source at any moment without compromising any credentials

Back to Top

Naming Conventions

The following is the generally accepted naming conventions being used by Laravel Community:

Controllers

Controller name MUST start with a noun (in singular form) followed by the word “Controller”.

Good

class ArticleController extends Controller
{

Bad

class ArticlesController extends Controller
{
class wp_articlesController extends Controller
{
class Article extends Controller
{

You SHOULD Use Resource Controllers unless you have any particular reason not to do so

Good

class DomainController extends Controller
{
    public function index(){} // list domains
    public function create(){} // show create form
    public function store(Request $request){ } // handle the form POST 
    public function show($id){} // show a single domain
    public function edit($id){} // show edit page
    public function update(Request $request, $id){} // handle show edit page POST
    public function destroy($id){} // delete a domain
}

Bad

class DomainController extends Controller
{
    public function list(){} // list domains
    public function create_or_save(){} // show create form then handle save
    public function show_edit($id){} // show a single domain then show edit page
    public function delete($id){} // delete a domain
}

Models

Model names MUST be in singular form with its first letter in uppercase

Good

class Flight extends Model
{
...

Bad

class Flights extends Model
{
...
class flight extends Model
{
...

hasOne or belongsTo relationship methods MUST be in singular form

Good

class User extends Model
{
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

Bad

class User extends Model
{
    public function phones()
    {
        return $this->hasOne('App\Phone');
    }
}

Any other relationships other than above MUST be in plural form

Good

class Post extends Model
{
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }
}

Bad

class Post extends Model
{
    public function comment()
    {
        return $this->hasMany('App\Comment');
    }
}

Model properties should be in snake_case

Good

$user->created_at

Bad

$user->createdAt

Methods should be in camelCase

Good

class User extends Model
{
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

Bad

class User extends Model
{
    public function scope_popular($query)
    {
        return $query->where('votes', '>', 100);
    }

Functions

Laravel comes with a lot of useful helper functions, but you can also define your own helper functions, given the following conditions:

You SHOULD place your custom helper functions by creating a file called helper.php

Good

project_folder/app/helper.php
project_folder/app/Http/helper.php

Bad

project_folder/functions.php

You MUST use Composer’s autolading capability to load your functions

Good

// file composer.json
...
"autoload": {
    "files": [
        "app/helpers.php"
    ],
...

Bad

// file app/Http/Controllers/HomeController.php

class HomeController.php
{
    function index(){
        require_once(app_path("helpers.php"));
    }
}

You MUST check if the the function exists before defining it

Good

if (! function_exists('my_custom_helper')) {
    function my_custom_helper($key, $default = null) {
        // ...
    }
}

Bad

function my_custom_helper($key, $default = null) {
    // ...
}

Other General guides with functions

Routes

Routes should be in plural form of the resource it is trying to manipulate and SHOULD be all lower-case

Good

Route::get('/users', 'UserController@index');
Route::resource('photos', 'PhotoController');

Bad

Route::get('/user', 'UserController@index');
Route::get('/UsersList', 'UserController@index');
Route::resource('PHOTO', 'PhotoController');

Named Routes SHOULD use snake_case and dot notation

Good

Route::get('/user', 'UserController@active')->name('users.show_active');

Bad

Route::get('/user', 'UserController@active')->name('users.show-active');
Route::get('/user', 'UserController@active')->name('show-active-users');

Variables

General rule for variable is it SHOULD be in camelCase

Good

$articlesWithAuthor

Bad

$articles_with_author

Collection names SHOULD be descriptive and in plural form

Good

$activeUsers = User::active()->get()

Bad

$users = User::active()->get()
$user = User::active()->get()
$User = User::active()->get()

Single Object SHOULD be descriptive and in singular form

Good

$activeUser = User::active()->first()

Bad

$users = User::active()->first()

Views

You SHOULD use snake_case as file name of your Blade templates

Good

show_filtered.blade.php

Bad

showFiltered.blade.php
show-filtered.blade.php

Good


// $api_results is passed by controller
<ul>  
    @foreach($api_results as $result)
        <li>{{ $result->name }}</li>
    @endforeach
</ul>

Bad


@php
   $api_results = json_decode(file_get_contents("https://api.example.com"));
@endphp
<ul>
    @foreach($api_results as $result)
        <li>{{ $result->name }}</li>
    @endforeach
</ul>

Back to Top

Database Conventions

Table and Fields Naming

Table names MUST be in plural form and MUST be all lower-case

Good

class CreateFlightsTable extends Migration
{
    public function up()
    {
        Schema::create('flights', function (Blueprint $table) {

Bad

class CreateFlightsTable extends Migration
{
    public function up()
    {
        Schema::create('flight', function (Blueprint $table) {
class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('MyUsers', function (Blueprint $table) {

Pivot table names MUST be in singular model names in alphabetical order

Good

post_user
articles_user
photo_post

Bad

posts_users
user_articles
post_photos

Table column names SHOULD be in snake_case without the model name

Good

username
title
thumb_url

Bad

UserName
_title
ThumbUrl
post_title

Foreign keys MUST be singular model name with _id suffix

Good

user_id

Bad

userid
siteid
Memberid
TransactionID

Primary Keys SHOULD be “id”

Good

id

Bad

ID
pkid
guid

Database Alterations

You MUST not be changing the database schema directly, use Database Migrations instead

Good

php artisan migrate

Bad

Migration filenames MUST follow to following pattern

creation of table

yyyy_mm_dd_<timestamp>_create_<table name>_table

Good

2019_06_06_164210_create_domains_table.php

Bad

2019_06_06_164210_domains.php

Database Choice

Polyglot Persistence

Is a practice of using different data storage technologies for different kinds of data. Eloquent ORM can support multiple database for a reason, so don’t limit yourself to MySQL.

From this article, here is a sample breakdown of different databases being used by a retailer company

Sample Company

Back to Top

Design Patterns

SOLID

SOLID is five design principles intended to make software designs more understandable, flexible and maintainable.

Single responsibility principle

A class should only have a single responsibility, that is, only changes to one part of the software’s specification should be able to affect the specification of the class.

Open–closed principle

Software entities … should be open for extension, but closed for modification.

Liskov substitution principle

Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

Interface segregation principle

Many client-specific interfaces are better than one general-purpose interface.

Dependency inversion principle

One should depend upon abstractions, [not] concretions.

Repository Pattern

The idea with this pattern is to have a generic abstract way for the app to work with the data layer without being bothered what storage technology is used when saving/retrieving the data.

We suggests to check first this tutorial for in-depth understand about this design pattern.


Back to Top

Testing

Unit Testing

Methods in test classes MUST start with “test” then a camelCased name of the test

Good

class ExampleTest extends TestCase
{
    public function testBasicTest()
    {

Bad

class ExampleTest extends TestCase
{
    public function test_basic_test()
    {

Integration Tests

WIP (work in progress): this will be filled up by collected best practices once we had done enough research about the subject matter.

Acceptance Tests

WIP (work in progress): this will be filled up by collected best practices once we had done enough research about the subject matter.

Back to Top

Scalability

WIP (work in progress): this will be filled up by collected best practices once we had done enough research about the subject matter.

Scaling Up

TODO

Scaling Out

TODO

Microservices

WIP (work in progress): this will be filled up by collected best practices once we had done enough research about the subject matter.

Back to Top

Resources

People to Follow

Mentoring

PHP PaaS Providers

Other Useful Resources

Laracasts

Starter Kits

Youtube Channels

Books

Back to Top

Community

Conferences

User Groups

Back to Top