Repository Design Pattern in Laravel with CRUD Example

Repository Design Pattern in Laravel with CRUD Example

In this article, we'll learn how to implement repository design pattern in laravel. We will start by creating a simple products management application using laravel repository design pattern. We will not be covering the views files in this article

Step 1: Install Laravel & Connect Database

Let us run this command to create laravel project with Laravel CLI Installer.

laravel new products-management

or Composer CLI

composer create-project laravel/laravel products-management

Now, let us set up the Laravel app to connect to the database, we will do this by modifying the following details in our .env file. This file can be found in the root of our project folder.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=products_management
DB_USERNAME=username
DB_PASSWORD=password

Step 2: Create Product Controller, Model and Migration

We will create our controller, model and migration with the commands below.

php artisan make:controller ProductController -r

php artisan make:model Product -m

Now let us add some fields to our migration

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('slug');
        $table->decimal('price', 10, 2);
        $table->integer('quantity');
        $table->timestamps();
    });
}

We will run the following command to run our migration.

php artisan migrate

The next thing we will do is add the fields to the fillable property in our model app/Models/Product

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'slug',
        'price',
        'quantity'
    ];
}

Let is register our controller in routes/web.php

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

Step 3: Create the Repositories and Interfaces Folders and Classes

  1. Create app/Repositories/ProductRepository.php folder

  2. Create app/Repositories/Interfaces/ProductRepositoryInterface.php

Step 4: Add CRUD Functionalities to Repository and Interface Classes

App/Repositories/Interfaces/ProductRepositoryInterface.php

<?php
namespace App\Repositories\Interfaces;

Interface ProductRepositoryInterface{

    public function allProducts();
    public function storeProduct($data);
    public function findProduct($id);
    public function updateProduct($data, $id); 
    public function destroyProduct($id);
}

The next step is to create the methods above in our repository class

<?php

namespace App\Repositories;

use App\Repositories\Interfaces\ProductRepositoryInterface;
use App\Models\Product;

class ProductRepository implements ProductRepositoryInterface
{

    public function allProducts()
    {
        return Product::latest()->paginate(10);
    }

    public function storeProduct($data)
    {
        return Product::create($data);
    }

    public function findProduct($id)
    {
        return Product::find($id);
    }

    public function updateProduct($data, $id)
    {
        $product = Product::where('id', $id)->first();
        $product->name = $data['name'];
        $product->slug = $data['slug'];
        $product->save();
    }

    public function destroyProduct($id)
    {
        $product = Product::find($id);
        $product->delete();
    }
}

Step 5: Bind Repository In App Service Provider

Here, we will bind the ProductRepositoryInterface with ProductRepository in the app/Providers/AppServiceProvider.php file

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Repositories\Interfaces\ProductRepositoryInterface;
use App\Repositories\ProductRepository;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind(ProductRepositoryInterface::class, ProductRepository::class);
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

Step 6: Add Repository Design Pattern In ProductController

<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;
use App\Repositories\Interfaces\ProductRepositoryInterface;

class ProductController extends Controller
{
    public function __construct(private ProductRepositoryInterface $productRepository)
    {

    }
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $products =  $this->productRepository->allProducts();

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

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('products.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:255',
            'slug' => 'required|string|max:255',
            'price' => 'required|float',
            'quantity' => 'required|integer',
        ]);;

        $this->productsRepository->storeProduct($data);

        return redirect()->route('products.index')->with('message', 'Product Created Successfully');
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $product = $this->productsRepository->findProduct($id);

        return view('products.edit', compact('product'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Products $product
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'slug' => 'required|string|max:255',
            'price' => 'required|float',
            'quantity' => 'required|integer',
        ]);

        $this->productRepository->updateProduct($request->all(), $id);

        return redirect()->route('products.index')->with('message', 'Product Updated Successfully');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $this->productRepository->destroyProduct($id);
        return redirect()->route('products.index')->with('status', 'Product Delete Successfully');
    }
}