Back to Homepage

20 Laravel Best Practices for Writing Clean Code

6 min read

Tags:

20 Laravel Best Practices for Writing Clean Code

In the realm of PHP frameworks, Laravel is a powerhouse that offers clean syntax, a wealth of features, and strong community support. However, its flexibility can also be a pitfall if best practices are not followed. A detailed guide to 20 essential best practices for writing clean, maintainable, and efficient Laravel code is provided in this article, which includes both what to do and what not to do.

Laravel Best Practices

1. Follow PSR Standards

Why:

Consistency is key in a collaborative environment, and PSR standards ensure that.

Do:

Use tools like PHP_CodeSniffer to enforce PSR-1, PSR-2, and PSR-4 standards.

# Install PHP_CodeSniffer
composer global require "squizlabs/php_codesniffer=*"

Don't:

Avoid disabling these rules unless there's a compelling reason to do so.

2. Leverage Dependency Injection

Why:

Dependency Injection (DI) enhances testability and adheres to SOLID principles.

Do:

Inject dependencies through constructors or methods.

public function __construct(User $user) {
    $this->user = $user;
}

Don't:

Refrain from using the new keyword within constructors to instantiate dependencies.

3. Validate Data Rigorously

Why:

Proper data validation is critical for data integrity and security.

Do:

Deploy Laravel's Request Validation or custom Form Request classes for complex scenarios.

public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

Don't:

Never skip validation, particularly in update methods where data integrity is crucial.

4. Master Eloquent ORM and Relationships

Why:

Eloquent keeps database interactions intuitive and makes your code more readable.

Do:

Use Eloquent relationships to minimize redundant code and SQL queries.

public function posts()
{
    return $this->hasMany('App\Post');
}

Don't:

Avoid using raw SQL queries unless absolutely necessary.

5. Stick to RESTful Resource Controllers

Why:

RESTful APIs are easier to consume and understand, promoting a better structure.

Do:

Use the php artisan make:controller command to generate resource controllers.

php artisan make:controller PostController --resource

Don't:

Steer clear of non-RESTful endpoints; they can make your API unpredictable.

6. Utilize Configuration and Language Files

Why:

Centralized configuration and language files make your application scalable and easy to manage.

Do:

Use the config() and trans() helper functions for retrieving values.

$timeout = config('session.lifetime');

Don't:

Hardcoding configurations directly in your methods is a no-no.

7. Implement Middleware for Filtering

Why:

Middleware adds an extra layer of security and functionality.

Do:

Create custom middleware for functionalities like logging, authentication, and more.

php artisan make:middleware CheckAge

Don't:

Avoid placing middleware logic directly in your controllers.

8. Follow the DRY Principle

Why:

The DRY (Don't Repeat Yourself) principle makes your codebase smaller and easier to manage.

Do:

Reuse code by creating helper functions or traits.

function calculateVAT($price) {
    return $price * 0.2;
}

Don't:

Refrain from copy-pasting blocks of code across different parts of your application.

9. Use Policy-Based Authorization

Why:

It centralizes authorization logic, making it easier to manage.

Do:

Create policies with php artisan make:policy and define your methods

public function update(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

Don't:

Avoid scattering authorization checks throughout your controllers and views.

10. Write Automated Tests

Why:

Automated tests ensure code integrity and make refactoring safer.

Do:

Utilize Laravel's built-in PHPUnit support for unit and feature tests.

public function testBasicTest()
{
    $response = $this->get('/');
    $response->assertStatus(200);
}

Don't:

Avoid deploying code that lacks adequate test coverage, especially for critical parts of your application.

11. Use Policy-Based Authorization

Why:

Centralizes authorization logic, making it easier to manage.

Do:

Create policies with php artisan make:policy and define your methods.

public function update(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

Don't:

Avoid scattering authorization logic throughout your controllers and views.

12. Leverage Dependency Inversion

Why:

High-level modules should not depend on low-level modules; both should depend on abstractions.

Do:

Inject interfaces rather than concrete classes.

public function __construct(OrderRepositoryInterface $orderRepository)
{
    $this->orderRepository = $orderRepository;
}

Don't:

Avoid tightly coupling your classes by instantiating concrete classes within them.

13. Use Database Transactions

Why:

Database transactions ensure data integrity by encapsulating multiple database operations.

Do:

Use the DB::transaction method for atomic operations.

DB::transaction(function () {
    DB::table('users')->update(['votes' => 1]);
    DB::table('posts')->delete();
}, 5);

Don't:

Don't use separate database queries outside of a transaction when data integrity is crucial.

14. Apply Lazy Eager Loading

Why:

Eager loading prevents the "N+1" query problem but is sometimes known only at runtime.

Do:

Use the load or loadMissing methods when needed.

$users = App\User::all();
$users->load('orders', 'roles');

Don't:

Avoid lazy loading in loops, which can lead to performance issues.

15. Implement the Repository Pattern

Why:

It abstracts the database layer, making the application more maintainable and testable.

Do:

Create a repository interface and a concrete implementation.

interface UserRepository
{
    public function all();
}

Don't:

Avoid directly using Eloquent models in controllers for complex queries; use repositories instead.

16. Use Query Scopes

Why:

Query scopes allow you to reuse query logic.

Do:

Define query scope methods in your Eloquent models.

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

Don't:

Avoid using the same query logic in multiple places without using scopes.

17. Utilize DTOs (Data Transfer Objects)

Why:

DTOs validate complex data structures and create objects based on specific business rules.

Do:

Create DTO classes to hold your validated data.

class OrderData {
    public string $customerName;
    public string $customerEmail;
    public array $items;
}

Don't:

Avoid passing arrays or unvalidated objects when a DTO could encapsulate the data better.

18. Make Use of API Resources

Why:

API Resources give you better control over your JSON output.

Do:

Use Laravel's API Resources to transform models into JSON.

return new UserResource(User::find($id));

Don't:

Avoid manually constructing API responses in controllers; use API Resources.

19. Adopt Event-Driven Architecture

Why:

Events and listeners promote decoupling, making the application easier to maintain and test.

Do:

Use Laravel's built-in events and listeners for actions like sending emails, logging, etc.

event(new OrderShipped($order));

Don't:

Avoid placing event-triggering logic directly in controllers where it can be encapsulated in events.

20. Extend Laravel's Core Using Macros

Why:

Macros allow you to add functionalities to Laravel's built-in components.

Do:

Use the macro method to extend Laravel’s core classes

Collection::macro('uppercase', function() {
    return $this->map(function($value) {
        return strtoupper($value);
    });
});

Don't:

Don't overuse macros to the point where the code becomes hard to follow or debug.

Conclusion

Adapting to Laravel Best Practices requires discipline, experience, and a deep understanding of Laravel Best Practices. Following these 20 guidelines will help you create code that's not just functional but also clean, maintainable, and efficient.

Follow @LaravelSage on X → Follow @LaravelSage on Facebook →
Aniket Singh

Aniket Singh

View All Articles

Full-stack developer with a knack for Merging creativity with technical expertise for standout solutions.

Related Articles

Top Laravel Packages for Building Powerful Applications

Top Laravel Packages for Building Powerful Applications

Are you ready to take your Laravel skills to the next level and build extraordinary applications? Look no further! In this blog post, we will unveil a treasure trove of top packages that will revolutionize your development process.

MarkdownX:  Markdown Editor by DevDojo

MarkdownX: Markdown Editor by DevDojo

It's a lightweight markup language used by developers, writers, and content creators for formatting text for various purposes, such as documentation, blog posts.

Subscribe for 20+ new Laravel tutorials every week

You can unsubscribe at any time. You'll also get -20% off my courses!

© 2024

 

Laravel Sage

   |    Privacy Policy