Category : #laravel
Tags : #laravel, #laravel crud, #laravel design pattern
In the previous Laravel repository pattern tutorial, I gave an example of a service repository pattern. Now in this tutorial, we will build a complete crud application in Laravel 9 using a service repository pattern. For this repository pattern Laravel crud, we have to go a long way. No problem, we will see step by step.
I assume, you already know the Laravel repository pattern tutorial. if you do not know about it, no problem. I am here to give a complete solution for Laravel 9 repository pattern crud.
In this tutorial, I will create a 'user' crud system using a repository design pattern. There will be three fields, name, email, and password. So do not waste your time, let's start Laravel repository pattern crud:
See the Laravel 9 repository pattern crud tutorial preview image below:
User List:
User Create Page:
Show Details Page:
User Edit Page:
Step 1: Download Fresh Laravel
In this first step, we need a fresh Laravel 9 application for the Laravel 9 repository pattern crud tutorial. So download it by the below command:
composer create-project laravel/laravel example-app
Step 2: Create Migration
We are going to use the User
model. So no need to create a model and migration.
Now look at the default migration like below:
database/migrations
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};
And the model:
app/Models/User.php
<?php
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
}
Step 3: Connect database
After successfully installing the Laravel app and then configuring the database setup. We will open the ".env" file and change the database name, username, and password in the env file to create a Laravel 9 repository pattern crud.
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=Enter_Your_Database_Name
DB_USERNAME=Enter_Your_Database_Username
DB_PASSWORD=Enter_Your_Database_Password
Now run php artisan migrate
command to update the database.
php artisan migrate
Read also: Why And When To Use Interface In Laravel Application
Step 4: Create Route
Now in this, create a resource route like the one below to complete the crud application in Laravel. I am going to use a resource controller. So define the resource route like the below:
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
Route::resource('user',UserController::class);
Now run php artisan route:list
command to check the available route which we are going to use for user crud with ima. After running the command you will see the below output.
Read also: Laravel 9 CRUD Tutorial Using Query Builder
Step 5: Create Interface
In this step, we have to create an interface cause we are going to create a Laravel repository pattern system. So create and update it like the below:
App\Repository\IUserRepository.php
<?php
namespace App\Repository;
use App\Models\User;
use Illuminate\Pagination\LengthAwarePaginator;
interface IUserRepository
{
public function list() : LengthAwarePaginator;
public function findById($id) : User;
public function storeOrUpdate( $id = null, $collection = [] );
public function destroyById($object);
}
Look at that, we defined four methods inside the interface and all of the methods do different tasks. The 'list()
' method will return all the users and the 'findById()
' method will return only a single user by id and the 'storeOrUpdate()
' method will store or update the users and the 'destroyById()'
method will destroy the single user by id.
Step 6: Create Service Class
Now time to create a 'UserRepository
' class that implements the user interface and completes the task from here. So create this class and update it like the below:
App\Repository\UserRepository.php
<?php
namespace App\Repository;
use App\Models\User;
use App\Repository\IUserRepository;
use Illuminate\Support\Facades\Hash;
use Illuminate\Pagination\LengthAwarePaginator;
class UserRepository implements IUserRepository
{
protected $user = null;
public function list() : LengthAwarePaginator
{
return User::paginate(10);
}
public function findById($id) : User
{
return User::find($id);
}
public function storeOrUpdate($id = null, $data = [] )
{
if(is_null($id)) {
$user = new User;
$user->name = $data['name'];
$user->email = $data['email'];
$user->password = Hash::make('password');
$user->save();
return $user;
}
$user = User::find($id);
$user->name = $data['name'];
$user->email = $data['email'];
$user->password = Hash::make('password');
$user->save();
return $user;
}
public function destroyById($id)
{
return User::find($id)->delete();
}
}
Step 7: Create Controller
Now in this step, we have to create a UserController to define this method to create a repository pattern Laravel crud.
php artisan make:controller UserController
Now update the controller like the below:
app/Http/Controllers/UserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Repository\IUserRepository;
class UserController extends Controller
{
protected $user;
public function __construct(IUserRepository $user)
{
$this->user = $user;
}
public function index()
{
$users = $this->user->list();
return view('user.index',compact('users'));
}
public function create()
{
return view('user.create');
}
public function store(Request $request)
{
$data = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
$this->user->storeOrUpdate($id = null, $data);
return redirect()->route('user.index')->with([
'message' => 'User added successfully!',
'status' => 'success'
]);
}
public function show($id)
{
$user = $this->user->findById($id);
return view('user.show',compact('user'));
}
public function edit($id)
{
$user = $this->user->findById($id);
return view('user.edit',compact('user'));
}
public function update(Request $request, $id)
{
$data = $request->validate([
'name' => 'required',
'email' => 'required'
]);
$this->user->storeOrUpdate($id, $data);
return redirect()->route('user.index')->with([
'message' => 'User updated successfully!',
'status' => 'success'
]);
}
public function destroy($id)
{
$this->user->destroyById($id);
return redirect()->route('user.index')->with([
'message' => 'User deleted successfully!',
'status' => 'success'
]);
}
}
Step 8: Binding Service Class With Interface
Look at that, our interface, service repository, and controller are ready to go. Now we have to do one more thing. We have to bind the repository class to our interface before using the interface. If we do not bind then you will face an error like that:
Target [App\Repository\IUserRepository] is not instantiable while building [App\Http\Controllers\UserController].
So now bind it in your 'AppServiceProvider' that way:
App\Providers\AppServiceProvider.php
<?php
namespace App\Providers;
use App\Repository\UserRepository;
use App\Repository\IUserRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(IUserRepository::class, UserRepository::class);
}
public function boot()
{
}
}
Step 9: Create Views
We are almost there. Just we have to create five views files before completing Laravel repository pattern tutorial with crud.
- index.balde.php
- create.blade.php
- edit.blade.php
- show.blade.php
- app.blade.php
So create these files inside the following path and update them like below:
resources/views/user/index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card p-2 mb-2" style="font-weight: 700">Repository Design Pattern in Laravel 9 With User CRUD - Laravelia</div>
<div class="card">
<div class="card-header" style="background: gray; color:#f1f7fa; font-weight:bold;">
User List
<a href="{{ route('user.create') }}" class="btn btn-success btn-xs py-0 float-end">+ Create New</a>
</div>
@if(session('message'))
<div class="alert alert-{{ session('status') }} alert-dismissible fade show" role="alert">
<strong>{{ session('message') }}</strong>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<div class="card-body">
<table class="table-responsive" style="width: 100%">
<thead>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th>Action</th>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>{{ $loop->index + 1 }}</td>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
{{-- <td>
@if($user->image)
<img src="{{ asset('storage/images/'.$user->image) }}" style="height: 50px;width:100px;">
@else
<span>No image found!</span>
@endif
</td> --}}
<td><a href="{{ route('user.edit',$user->id) }}" class="btn btn-success btn-xs py-0">Edit</a></td>
<td><a href="{{ route('user.show',$user->id) }}" class="btn btn-secondary btn-xs py-0">Show</a></td>
<td>
<form method="POST" action="{{ route('user.destroy',$user->id) }}">
@csrf
@method('delete')
<button type="submit" class="btn btn-danger btn-xs py-0 text-white">Delete</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
<center class="mt-5">
{{ $users->links() }}
</center>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/user/edit.blade.php
@extends('layouts.app')
@push('style')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header" style="background: gray; color:#f1f7fa; font-weight:bold;">
Update User
<a href="{{ route('user.index') }}" class="btn btn-success btn-xs py-0 float-end">Back</a>
</div>
@if($errors->any())
{!! implode('', $errors->all('<div>:message</div>')) !!}
@endif
<div class="card-body">
<form class="w-px-500 p-3 p-md-3" action="{{ route('user.update',$user->id) }}" method="post" enctype="multipart/form-data">
@csrf
@method('patch')
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="name" placeholder="Name" @error('name') is-invalid @enderror value="{{ $user->name }}">
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" placeholder="Email" @error('email') is-invalid @enderror value="{{ $user->email }}">
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label"></label>
<div class="col-sm-9">
<button type="submit" class="btn btn-secondary btn-block text-danger">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/user/show.blade.php
@extends('layouts.app')
@push('style')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header" style="background: gray; color:#f1f7fa; font-weight:bold;">
User details
<a href="{{ route('user.index') }}" class="btn btn-success btn-xs py-0 float-end">Back</a>
</div>
<div class="card-body">
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="name" value="{{ $user->name }}">
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" value="{{ $user->email }}">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
resources/views/user/create.blade.php
@extends('layouts.app')
@push('style')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header" style="background: gray; color:#f1f7fa; font-weight:bold;">
Create New User
<a href="{{ route('user.index') }}" class="btn btn-success btn-xs py-0 float-end">Back</a>
</div>
@if($errors->any())
{!! implode('', $errors->all('<div>:message</div>')) !!}
@endif
<div class="card-body">
<form class="w-px-500 p-3 p-md-3" action="{{ route('user.store') }}" method="post" enctype="multipart/form-data">
@csrf
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="name" placeholder="Name" @error('name') is-invalid @enderror>
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" placeholder="Email" @error('email') is-invalid @enderror>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label">Password</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="password" placeholder="Password" @error('password') is-invalid @enderror>
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label"></label>
<div class="col-sm-9">
<button type="submit" class="btn btn-success btn-block text-white">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Now we need to create a master file. So let's create a app.blade.php file and add it to the following path:
resources/views/layouts/app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
@stack('style')
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
Laravelia
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4" style="background: #f1f7fa;">
@yield('content')
</main>
</div>
@stack('script')
</body>
</html>
Now all are set to go. Now run php artisan serve
command to start the development server and visit the following URL to check this Laravel 9 repository pattern crud tutorial.
URL
Recommended: What Is Service Container And When To Use It In Laravel
Conclusion
Now we are in conclusion. Is this ok? Now we know the repository pattern Laravel crud and we can implement the Laravel repository pattern system. So hope this Laravel repository pattern crud tutorial will help you.