👍👍👍 Repository là nơi lưu trữ logic truy vấn dữ liệu. Các lệnh truy vẫn dữ liệu vốn được viết trực tiếp ở controller sẽ được đưa vào Repository. Khi đó, Controller sẽ dùng Repository để tương tác với dữ liệu thay vì sử dụng trực tiếp. Việc truy cập dữ liệu được giấu kín trong Repository.
<?php
namespace App\Repositories\User;
interface UserInterface {
public function getAll();
public function find($id);
public function delete($id);
}
?>
<?php
namespace App\Repositories\User;
use App\Repositories\User\UserInterface as UserInterface;
use App\Models\User;
class UserRepository implements UserInterface {
public $user;
function __construct(User $user) {
$this->user = $user;
}
public function getAll() {
return $this->user->getAll();
}
public function find($id) {
return $this->user->findUser($id);
}
public function delete($id) {
return $this->user->deleteUser($id);
}
}
?>
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable {
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getAll() {
return static::all();
}
public function findUser($id) {
return static::find($id);
}
public function deleteUser($id) {
return static::find($id)->delete();
}
}
<?php
namespace App\Http\Controllers;
use App\Repositories\User\UserInterface as UserInterface;
class UserController extends Controller {
public function __construct(UserInterface $user) {
$this->user = $user;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index() {
$users = $this->user->getAll();
return view('users.index')->with(compact('users'));
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function show($id) {
$user = $this->user->find($id);
return view('users.show')->with("user",$user);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function destroy($id) {
$this->user->delete($id);
return redirect()->route('users.index')->with('success','Product deleted successfully');
}
}
?>
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::resource('users', [UserController::class]);
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::resource('posts', PostController::class);
<?php
namespace App\Repositories;
use App\Models\Post;
use App\Repositories\PostRepositoryInterface;
class PostRepository implements PostRepositoryInterface {
/**
* Get's a post by it's ID
*
* @param int
* @return collection
*/
public function get($post_id) {
return Post::find($post_id);
}
/**
* Get's all posts.
*
* @return mixed
*/
public function all() {
return Post::all();
}
/**
* Deletes a post.
*
* @param int
*/
public function delete($post_id) {
Post::destroy($post_id);
}
/**
* Updates a post.
*
* @param int
* @param array
*/
public function update($post_id, array $post_data) {
Post::find($post_id)->update($post_data);
}
}
<?php
namespace App\Repositories;
interface PostRepositoryInterface {
/**
* Get's a post by it's ID
*
* @param int
*/
public function get($post_id);
/**
* Get's all posts.
*
* @return mixed
*/
public function all();
/**
* Deletes a post.
*
* @param int
*/
public function delete($post_id);
/**
* Updates a post.
*
* @param int
* @param array
*/
public function update($post_id, array $post_data);
}
?>
<?php
namespace App\Repositories;
use App\Repositories\RepositoryInterface;
abstract class BaseRepository implements RepositoryInterface {
//model muốn tương tác
protected $model;
//khởi tạo
public function __construct() {
$this->setModel();
}
//lấy model tương ứng
abstract public function getModel();
/**
* Set model
*/
public function setModel() {
$this->model = app()->make(
$this->getModel()
);
}
public function getAll() {
return $this->model->all();
}
public function find($id) {
$result = $this->model->find($id);
return $result;
}
public function create($attributes = []) {
return $this->model->create($attributes);
}
public function update($id, $attributes = []) {
$result = $this->find($id);
if ($result) {
$result->update($attributes);
return $result;
}
return false;
}
public function delete($id) {
$result = $this->find($id);
if ($result) {
$result->delete();
return true;
}
return false;
}
}
Bước 2: Đăng kí trong app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
/**
* Register any application services.
*
* @return void
*/
public function register() {
$this->app->singleton(
App\Repositories\Product\ProductRepositoryInterface::class,
App\Repositories\Product\ProductRepository::class
);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot() {
//
}
}
Bước 3: Viết Interface và Repository cho Model tương ứng.
Bước 4: Tạo ProductController
Triển khai Repository trong Laravel
1. Design Pattern là gì?
Design Pattern là các mẫu thiết kế chuẩn, được đúc kết và tạo ra sau quá trình làm việc và nghiên cứu lâu dài của các chuyên gia.
Design Pattern là một giải pháp tổng thể, một khuôn mẫu cho các vấn đề chung trong thiết kế phần mềm.
Trong hướng đối tượng, Design Pattern cho thấy mối quan hệ và tương tác giữa các lớp hoặc các đối tượng mà không cần chỉ rõ đối tượng cụ thể.
Lợi ích của Design Pattern:
Dễ bảo trì, nâng cấp và mở rộng dự án
Hạn chế được các lỗi tiềm ẩn
Code dễ đọc, dễ hiểu và dễ phát triển
2. Repository là gì?
Repository là phần trung gian, ở giữa phần dữ liệu và phần xử lý logic.
Repository là nơi lưu trữ logic truy vấn dữ liệu. Các lệnh truy vẫn dữ liệu vốn được viết trực tiếp ở controller sẽ được đưa vào Repository. Khi đó, Controller sẽ dùng Repository để tương tác với dữ liệu thay vì sử dụng trực tiếp. Việc truy cập dữ liệu được giấu kín trong Repository.
Thông thường trong Laravel, các phương thức như find, create, update, delete,... được viết khá giống nhau, chỉ khác nhau ở tên Model (đối tượng) cần tương tác. Vì vậy, các đoạn code này nên đưa ra Repository để tiết kiệm việc viết code.
Lợi ích của Repository:
Code dễ đọc, dễ phát triển sản phẩm trong làm việc nhóm
Giảm thay đổi code khi phần mềm có thay đổi cấu trúc dữ liệu
Tránh việc lặp code
Hạn chế lỗi trong truy vấn
Dễ dàng thực hiện test
3. Ví dụ
Bước 1:
Trong thư mục apptrong ứng dụng Laravel của bạn, tạo 1 thư mục có tên là Repositories. Trong thư mục sẽ có:
RepositoryInterface: interface khuôn mẫu, khai báo các phương thức chung cho các Models.
BaseRepository: implements RepositoryInterface, triển khai các phương thức chung cho các Model
Các thư mục riêng tương ứng với các Model. (Ở đây mình ví dụ là Product). Trong thư mục này chứa:
ProductRepositoryInterface: interface chứa các phương thức riêng của Model Product.
Trong ProductController, thay vì viết trực tiếp truy vẫn, chúng ta sẽ khởi tạo controller có thuộc tính $productRepo để truy vấn dữ liệu qua nó.
Bước 2: Đăng kí trong app/Providers/AppServiceProvider.php
Khi khởi tạo controller, chúng ta sẽ gán thuộc tính $productRepo có kiểu là ProductRepositoryInterface. Tại sao không phải là ProductRepository?
Mục đích là để khi các logic làm việc với dữ liệu thay đổi hay để dễ hiểu, các bạn nghĩ đến khi database thay đổi (ví dụ chuyển từ MySQL sang Redis), các lệnh truy vấn dữ liệu sẽ thay đổi. Khi đó, ta sẽ phải tạo thêm 1 class ProductRepository khác (ví dụ RedisProductRepository). Để dễ dàng cho các thay đổi như vậy, không cần sửa lại các controller đang dùng repository cũ, ta đăng kí và sau đó chỉ cần thay đổi repository ở file app/Providers/AppServiceProvider.php.
Bước 4: Viết Interface và Repository cho Model tương ứng.
ProductRepositoryInterface
<?phpnamespaceApp\Repositories\Product;useApp\Repositories\RepositoryInterface;interfaceProductRepositoryInterfaceextendsRepositoryInterface{//ví dụ: lấy 5 sản phầm đầu tiênpublicfunctiongetProduct();}
ProductRepository
<?phpnamespaceApp\Repositories\Post;useApp\Repositories\BaseRepository;classProductRepositoryextendsBaseRepositoryimplementsProductRepositoryInterface{//lấy model tương ứngpublicfunctiongetModel() {return\App\Models\Product::class; }publicfunctiongetProduct() {return$this->model->select('product_name')->take(5)->get(); }}