Laravel CRUD Using Repository Design Pattern

Hello Artisans, today I'll show you how to make a simple CRUD application using Repository Design Pattern. The repository design pattern is one of the most used patterns because it's very efficient for avoiding repeated codes. So let's see how we can easily make a CRUD using a repository design patterns in our Laravel application.

Note: Tested on Laravel 9.19

Table of Contents

  1. Create and Setup Repository
  2. Create and Setup Controller
  3. Define Routes
  4. Create and Setup View
  5. Output

Create and Setup Repository

At first, we'll create a repository class called UserRepository.php where we'll write our all database logics so that we can use the same query everywhere.

app/UserRepository.php
<?php

namespace App;

use App\Models\User;

class UserRepository
{

    public function index()
    {
        return User::latest()->paginate(15);
    }

    public function store($data)
    {
        return User::create($data);
    }

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

    public function update($data, $id)
    {
        $user = $this->find($id);
        return $user->update($data);
    }

    public function destroy($id): int
    {
        return User::destroy($id);
    }

}

Create and Setup Controller

Then, we'll create a controller called UserController.php where we'll write our logic or insert the data. So, fire the below command in terminal.

php artisan make:controller UserController -r

It'll create a file under app\Http\Controllers called UserController.php. Now open the file and replace with below codes.

app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use App\UserRepository;
use Illuminate\Http\Request;

class UserController extends Controller
{
    protected $userRepository;
    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }
    public function index(): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Contracts\Foundation\Application
    {
        try {
            $data       = [
                'users' => $this->userRepository->index(),
            ];
            return view('users.index', $data);
        } catch (\Exception $e) {
            return back()->with(['error', $e->getMessage()]);
        }
    }
    public function store(Request $request): \Illuminate\Http\RedirectResponse
    {
        try {
            $request->validate([
                'name'      => 'required',
                'email'     => 'required|unique:users,email',
                'password'  => 'required|confirmed',
            ]);
            $data = $request->all();
            $data['password'] = bcrypt($data['password']);
            $this->userRepository->store($data);

            return back()->with(['success' => 'User Created Successfully']);
        } catch (\Exception $e) {
            return back()->with(['error' => $e->getMessage()]);
        }
    }
    public function edit($id,Request $request): \Illuminate\Contracts\View\View|\Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Contracts\Foundation\Application
    {
        try {
            $data = [
                'users' => $this->userRepository->index(),
                'edit'  => $this->userRepository->find($id),
            ];
            return view('users.index', $data);
        } catch (\Exception $e) {
            return back()->with(['error' => $e->getMessage()]);
        }
    }
    public function update(Request $request, $id): \Illuminate\Http\RedirectResponse
    {
        try {
            $request->validate([
                'name'      => 'required',
                'email'     => 'required|unique:users,email,'.$id
            ]);
            $data = $request->all();
            $data['password'] = bcrypt($data['password']);
            $this->userRepository->update($data,$id);

            return redirect()->route('users.index')->with(['success' => 'User Updated Successfully']);
        } catch (\Exception $e) {
            return back()->with(['error' => $e->getMessage()]);
        }
    }

    public function destroy($id): \Illuminate\Http\RedirectResponse
    {
        try {
            $this->userRepository->destroy($id);
            return redirect()->route('users.index')->with(['success' => 'User Deleted Successfully']);
        } catch (\Exception $e) {
            return back()->with(['error' => $e->getMessage()]);
        }
    }
}

Define Routes

Now, we need to create a route so that when a user selects a language, it'll be redirected to our controller. So put this below route in web.php

routes/web.php
Route::resource('users', \App\Http\Controllers\UserController::class);

Create and Setup View

Now we'll create 3 blade files named 

  1. index.blade.php
  2. form.blade.php
  3. table.blade.php

Now open the files and replace with below codes with particular blade files.

resources/views/users/form.blade.php
<div class="col-12 col-md-12 col-lg-4">
    <div class="card">
        @php
            $route = isset($edit) ? route('users.update',$edit->id) : route('users.store');
        @endphp
        <form method="post" class="needs-validation" enctype="multipart/form-data"
              action="{{ $route }}">@csrf
            @isset($edit)
                @method('put')
            @endisset
            <div class="card-header">
                <h4>{{ isset($edit) ? __('Edit User') : __('Add User') }}</h4>
            </div>
            <div class="card-body">
                <div class="row">
                    <div class="form-group col-12">
                        <label for="name">{{ __('Name') }} <strong>*</strong></label>
                        <input type="text" name="name" id="name" class="form-control"
                               value="{{ old('name') ? : (isset($edit) ? $edit->name : '') }}">
                        <span class="text-danger">{{ $errors->first('name') }}</span>
                    </div>
                    <div class="form-group col-12">
                        <label for="email">{{ __('Email') }} <strong>*</strong></label>
                        <input type="text" name="email" id="email" class="form-control"
                               value="{{ old('email') ? : (isset($edit) ? $edit->email : '') }}">
                        <span class="text-danger">{{ $errors->first('email') }}</span>
                    </div>
                    <div class="form-group col-12">
                        <label for="password">{{ __('Password') }} <strong>*</strong></label>
                        <input type="password" name="password" id="password" class="form-control">
                        <span class="text-danger">{{ $errors->first('password') }}</span>
                    </div>
                    <div class="form-group col-12">
                        <label for="password_confirmation">{{ __('Confirm Password') }} <strong>*</strong></label>
                        <input type="password" name="password_confirmation" id="password_confirmation" class="form-control">
                        <span class="text-danger">{{ $errors->first('password_confirmation') }}</span>
                    </div>
                </div>
            </div>
            <div class="card-footer text-right">
                <button class="btn btn-primary">{{ __('Save Changes') }}</button>
            </div>
        </form>
    </div>
</div>
resources/views/users/index.blade.php
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">

    <!-- jQuery library -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js"></script>

    <!-- Popper JS -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>

    <!-- Latest compiled JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="section-body">
    <div class="container-fluid">
        <div class="row mt-sm-4">
            <div class="col-md-12">
                @if(session()->has('success'))
                    <div class="alert alert-success alert-dismissible fade show" role="alert">
                        <strong>Success!</strong> {{ session()->get('success') }}
                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                @elseif(session()->has('error'))
                    <div class="alert alert-danger alert-dismissible fade show" role="alert">
                        <strong>Error!</strong> {{ session()->get('error') }}
                        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                @endif
            </div>
            @include('users.form')
            @include('users.table')
        </div>
    </div>
</div>
</body>
</html>
resources/views/users/table.blade.php
<div class="col-12 col-md-12 col-lg-8">
    <div class="row">
        <div class="col-md-12">
            <div class="card">
                <div class="card-header">
                    <h4>{{ __('Users') }}</h4>
                </div>
                <div class="card-body p-0">
                    <div class="table-responsive table-invoice">
                        <table class="table table-striped">
                            <tr>
                                <th>#</th>
                                <th>{{ __('Name') }}</th>
                                <th>{{ __('Email') }}</th>
                                <th>{{ __('Created At') }}</th>
                                <th>{{ __('Action') }}</th>
                            </tr>
                            @foreach($users as $key=> $user)
                                <tr>
                                    <td>{{ $key 1 }}</td>
                                    <td>{{ $user->name }}</td>
                                    <td>{{ $user->email }}</td>
                                    <td>{{ \Carbon\Carbon::parse($user->created_at)->format('Y-m-d H:i:s') }}</td>
                                    <td>
                                        <a href="{{ route('users.edit', $user->id) }}"
                                           class="btn btn-primary">{{ __('Edit') }}</a>
                                        <form action="{{ route('users.destroy', $user->id) }}" method="post"
                                              class="d-inline" onsubmit="return confirm('{{__('Are You Sure')}}?')">
                                            @csrf
                                            @method('DELETE')
                                            <button type="submit" class="btn btn-danger">{{ __('Delete') }}</button>
                                        </form>
                                    </td>
                                </tr>
                            @endforeach
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
    @if($users->nextPageUrl())
        <div class="card-footer text-right">
            {{ $users->links('vendor.pagination.bootstrap-5') }}
        </div>
    @endif
</div>

Output

And finally, we're ready with our setup. It's time to check our output. Now go to http://127.0.0.1:8000/users, If everything goes well (hope so) we can see the below output.

That's it for today. I hope you've enjoyed this tutorial. You can also download this tutorial from GitHub. Thanks for reading. ๐Ÿ™‚