Header Ads

Header ADS

Laravel Smart coding pattern

 In advanced Laravel development, adhering to best practices and organizing code effectively is crucial. Here’s an outline of advanced coding patterns and structure across various Laravel components such as models, controllers, database queries, Blade views, and more.


1. Models

In advanced Laravel development, models should follow clean, maintainable structures. This involves using Eloquent relationships, mutators, accessors, scopes, and repositories for complex logic.


// app/Models/Product.php


namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Product extends Model

{

    use HasFactory;


    // Guarded or fillable fields to protect from mass assignment vulnerabilities

    protected $fillable = ['name', 'description', 'price', 'stock', 'category_id'];


    // Define relationships

    public function category()

    {

        return $this->belongsTo(Category::class);

    }


    // Accessor: Get formatted price

    public function getFormattedPriceAttribute()

    {

        return '৳' . number_format($this->price, 2);

    }


    // Scope: Filter products based on stock availability

    public function scopeAvailable($query)

    {

        return $query->where('stock', '>', 0);

    }


    // Mutator: Set name to always be capitalized

    public function setNameAttribute($value)

    {

        $this->attributes['name'] = ucfirst($value);

    }

}

Best Practices:

  • Use guarded or fillable to prevent mass assignment issues.
  • Accessors and mutators should handle any automatic transformation of attributes.
  • Use local scopes to encapsulate commonly used query logic.
  • Define relationships between models to simplify querying related data.


2. Controllers

Laravel encourages keeping controllers lean and moving business logic elsewhere (like services, repositories, etc.).


// app/Http/Controllers/ProductController.php


namespace App\Http\Controllers;


use App\Models\Product;

use App\Services\ProductService;

use Illuminate\Http\Request;


class ProductController extends Controller

{

    protected $productService;


    public function __construct(ProductService $productService)

    {

        $this->productService = $productService;

    }


    public function index()

    {

        $products = $this->productService->getAvailableProducts();

        return view('products.index', compact('products'));

    }


    public function show($id)

    {

        $product = $this->productService->getProductById($id);

        return view('products.show', compact('product'));

    }


    public function store(Request $request)

    {

        $validated = $request->validate([

            'name' => 'required|string|max:255',

            'price' => 'required|numeric',

        ]);


        $this->productService->createProduct($validated);

        return redirect()->route('products.index')->with('success', 'Product created successfully!');

    }

}



Best Practices:

  • Use dependency injection for services or repositories.
  • Validation logic should be in separate request classes (e.g., StoreProductRequest).
  • Controllers should only handle request flow and delegate business logic elsewhere.

3. Services

Services handle business logic and help keep controllers clean.


// app/Services/ProductService.php


namespace App\Services;


use App\Models\Product;


class ProductService

{

    public function getAvailableProducts()

    {

        return Product::available()->with('category')->get();

    }


    public function getProductById($id)

    {

        return Product::with('category')->findOrFail($id);

    }


    public function createProduct(array $data)

    {

        return Product::create($data);

    }

}


Best Practices:

  • Services should be used to encapsulate complex business logic.
  • They provide a good layer for unit testing as well.

4. Repositories

Repositories abstract the data access layer and allow for easier testing and better separation of concerns.


// app/Repositories/ProductRepository.php


namespace App\Repositories;


use App\Models\Product;


class ProductRepository

{

    public function getAll()

    {

        return Product::all();

    }


    public function find($id)

    {

        return Product::find($id);

    }


    public function create(array $data)

    {

        return Product::create($data);

    }


    public function update($id, array $data)

    {

        $product = Product::find($id);

        return $product->update($data);

    }


    public function delete($id)

    {

        return Product::destroy($id);

    }

}

Best Practices:

  • Use repositories to handle database interactions.
  • They provide flexibility for switching data sources (e.g., from a database to an API).

5. Blade Views

Use Blade templating to maintain clean and modular views.


{{-- resources/views/products/index.blade.php --}}

@extends('layouts.app')


@section('content')

<div class="container">

    <h1>Product List</h1>

    <div class="row">

        @foreach($products as $product)

            <div class="col-md-4">

                <div class="product">

                    <h2>{{ $product->name }}</h2>

                    <p>{{ $product->description }}</p>

                    <p><strong>Price:</strong> {{ $product->formatted_price }}</p>

                    <a href="{{ route('products.show', $product->id) }}" class="btn btn-primary">View Details</a>

                </div>

            </div>

        @endforeach

    </div>

</div>

@endsection



Best Practices:

  • Use Blade directives like @foreach, @include, and @section for clean templates.
  • Avoid heavy logic in views; move that to controllers, services, or models.
  • Use components for reusable parts (e.g., modals, buttons).

6. Database Queries (Eloquent & Query Builder)

Eloquent is Laravel's ORM, but the Query Builder is available for complex queries.

Eloquent Example:


$products = Product::where('price', '>', 100)->with('category')->get();


Query Builder Example:
$products = DB::table('products')
    ->join('categories', 'products.category_id', '=', 'categories.id')
    ->select('products.*', 'categories.name as category_name')
    ->where('products.price', '>', 100)
    ->get();


Best Practices:

  • Use Eloquent for most cases, but fall back on Query Builder for performance-critical or complex queries.
  • Prefer eager loading (with()) over lazy loading to reduce the number of database queries.

7. Advanced Validation (Form Requests)

Use Form Request classes to handle complex validation logic.


// app/Http/Requests/StoreProductRequest.php


namespace App\Http\Requests;


use Illuminate\Foundation\Http\FormRequest;


class StoreProductRequest extends FormRequest

{

    public function authorize()

    {

        return true;

    }


    public function rules()

    {

        return [

            'name' => 'required|string|max:255',

            'price' => 'required|numeric',

            'description' => 'nullable|string',

        ];

    }

}

In the controller:
public function store(StoreProductRequest $request)
{
    $this->productService->createProduct($request->validated());
    return redirect()->route('products.index')->with('success', 'Product created successfully!');
}

Best Practices:

  • Use Form Requests to validate incoming data instead of cluttering your controllers.
  • The authorize method is useful for access control within requests.

8. Routes

For advanced route management, leverage resource controllers and route grouping.


// routes/web.php


use App\Http\Controllers\ProductController;


Route::group(['middleware' => 'auth'], function () {

    Route::resource('products', ProductController::class);

});

Best Practices:

  • Use route grouping for applying middleware or common settings.
  • Use named routes to make route management easier.

9. Testing

Ensure you cover your logic with unit tests and feature tests.

Unit Test Example:


// tests/Unit/ProductServiceTest.php


namespace Tests\Unit;


use App\Models\Product;

use App\Services\ProductService;

use Tests\TestCase;


class ProductServiceTest extends TestCase

{

    public function test_can_create_product()

    {

        $productService = new ProductService();

        $product = $productService->createProduct([

            'name' => 'Test Product',

            'price' => 100.00,

            'description' => 'Test description'

        ]);


        $this->assertInstanceOf(Product::class, $product);

        $this->assertEquals('Test Product', $product->name);

    }

}

Best Practices:

  • Write unit tests for services, repositories, and models.
  • Write feature tests for routes, controllers, and views.



No comments

Theme images by fpm. Powered by Blogger.