Cơ bản về Repository trong Laravel
Design Patterns là gì ?
Design Pattern
(mẫu thiết kế) là giải pháp chung để giải quyết các vấn đề phổ biến khi thiết kế phần mềm trong lập trình hướng đối tượng OOP. Ví dụ:
Khi gặp vấn đề, mỗi developer sẽ có những phương án khác nhau để giải quyết. Tuy
nhiên các phương án đó chưa thực sự tối ưu. Do đó, Design Pattern sinh ra để giải
quyết vấn đề này, khiến các vấn đề có tính chất tương tự được giải quyết trong một
khuôn mẫu nhất định. Các khuôn mẫu này đã được chuẩn tối ưu nhất.
Việc sử dụng Design Pattern sẽ giúp chúng ta tiết kiệm thời gian và công sức để tìm cách giải quyết cho những vấn đề đã có phương án tối ưu. Tuy nhiên nó khá trừu tượng với những coder mới tìm hiểu.
Các framework hiện nay như Laravel, Codeigniter, Spring.. đều có sử dụng những Design Patterns có sẵn.
Repository Pattern Trong Laravel
Repository Pattern là một mẫu thiết kế trong Design Pattern. Repository là lớp trung gian nằm giữa BLL (Business Logic Layer) và DAL (Data Access Layer). Mục đích của Repository là để giúp cho việc truy cập dữ liệu chặt chẽ và bảo mật hơn.
Hiểu một cách đơn giản, Repository sẽ nằm giữa lớp Model
và Controller
. Thay vì viết code xử lí trong Controller
thì ta sẽ viết trong Repository
rồi gọi trong constructor của Controller
.
Việc sử dụng Repository trong một dự án sẽ khiến Code dễ đọc hơn, hạn chế các lỗi trong việc truy vấn và lặp code.
Ví dụ: Trong phần lớn các ứng dụng Laravel, chúng ta sẽ gặp mã như sau trong Controller.
class UsersController extends Controller
{
public function index()
{
$users = User::all();
return view('users.index', [
'users' => $users
]);
}
}
Trông thì có vẻ không có vấn đề gì. Tuy nhiên nếu khách hàng đề xuất thay đổi các cấu trúc dữ liệu và thay vì trong MySQL hay PostgresSQL thì bây giờ chúng ta sẽ lưu dữ liệu ở một nơi khác, trong một công cụ mà không có Eloquent hỗ trợ thì việc viết như vậy sẽ dẫn đến tình trạng rất khó để thay đổi tất cả các Controller
. Mọi việc triển khai phải dựa trên các interface
. Trong trường hợp có sự thay đổi, bạn không cần thay đổi toàn bộ project mà chỉ cần tạo một interface. Ví dụ:
class UsersController extends Controller
{
private $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = $this->userRepository->all();
return view('users.index', [
'users' => $users
]);
}
}
Với cách viết như thế này, khi phải thay đổi cấu trúc dữ liệu thì chúng ta sẽ tạo một lớp implement UserRepositoryInterface
và chứa các logic cho phép lấy data theo một cách mới.
Cách xây dựng Repository trong Laravel
- Tạo base Repository
Tạo thư mục Repository
trong app
như sau:
-- app
---- Repository
------ Eloquent
-------- UserRepository.php
-------- BaseRepository.php
------ UserRepositoryInterface.php
------ EloquentRepositoryInterface.php
Hiểu nôm na, BaseRepository
và EloquentRepositoryInterface
là các lớp cha chứa các methods được sử dụng phổ biến trong mọi repository. Trong đó, BaseRepository
implements RepositoryInterface
là nơi triển khai các phương thức như CRUD, còn RepositoryInterface
là nơi khai báo các phương thức đó.
EloquentRepository
namespace App\Repository;
use Illuminate\Database\Eloquent\Model;
/
* Interface EloquentRepositoryInterface
* @package App\Repositories
*/
interface EloquentRepositoryInterface
{
/
* @param array $attributes
* @return Model
*/
public function create(array $attributes): Model;
/**
* @param $id
* @return Model
*/
public function find($id): ?Model;
}
...
BaseRepository.php
<?php
namespace App\Repository\Eloquent;
use App\Repository\EloquentRepositoryInterface;
use Illuminate\Database\Eloquent\Model;
class BaseRepository implements EloquentRepositoryInterface
{
/
* @var Model
*/
protected $model;
/
* BaseRepository constructor.
*
* @param Model $model
*/
public function __construct(Model $model)
{
$this->model = $model;
}
/
* @param array $attributes
*
* @return Model
*/
public function create(array $attributes): Model
{
return $this->model->create($attributes);
}
/
* @param $id
* @return Model
*/
public function find($id): ?Model
{
return $this->model->find($id);
}
...
}
2. Khai báo Service Provider
php artisan make:provider RepositoryServiceProvider
Khai báo trong hàm register()
public function register()
{
$this->app->bind(EloquentRepositoryInterface::class, BaseRepository::class);
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
Tiếp theo là khai báo Provider
mà chúng ta vừa tạo ở config/app.php
. Thêm vào 'providers'
:
App\Providers\RepositoryServiceProvider::class
3. Viết Interface và Repository tương ứng với Model.
UserRepositoryInterface.php
<?php
namespace App\Repository;
use App\Model\User;
use Illuminate\Support\Collection;
interface UserRepositoryInterface
{
// Lấy tất cả users
public function all(): Collection;
}
UserRepository.php
<?php
namespace App\Repository\Eloquent;
use App\Model\User;
use App\Repository\UserRepositoryInterface;
use Illuminate\Support\Collection;
class UserRepository extends BaseRepository implements UserRepositoryInterface
{
/
* Hàm constructor.
*
* @param User $model
*/
public function construct(User $model)
{
// Khai báo model User
parent::construct($model);
}
/
* @return Collection
*/
public function all(): Collection
{
// Lấy hết các users
return $this->model->all();
}
}
4. Viết Controller
UserController.php
class UsersController extends Controller
{
private $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = $this->userRepository->all();
return view('users.index', [
'users' => $users
]);
}
}
Tổng kết
Như vậy, chúng ta đã tìm hiểu cơ bản về Repository và thực hành. Trong trường hợp không muốn triển khai Eloquent, chúng ta thay đổi App\Repository\Eloquent\UserRepository.php
ví dụ App\Repository\Mongo\UserRepository.php
. Mọi thứ vẫn sẽ hoạt động bình thường ngay cả khi chúng ta thay đổi về phía dữ liệu.