/ / Laravel Framework / Comment (0)

Laravel Framework – Repository Design Pattern với Interface

Trong bài trước mình có hướng dẫn các bạn xây dựng 1 Repository Design Pattern cơ bản trong Laravel Framework.Với cách trên chắc các bạn đã hiểu quy trình để xây dựng lên 1 Repository rồi phải không,thực ra nó là 1 mẫu thiết kế không có gì khó cả nhưng nó hoàn toàn đáp ứng được các yêu cầu thay đổi về điều kiện truy vấn hay thay đổi cấu trúc dữ liệu.Khi sử dụng Repository theo cấu trúc đó thì nó sẽ có những lợi ích sau:

  • Tách biệt lớp business logic và data source
  • Giúp bạn tái sử dụng mã lệnh và dễ dàng mở rộng, nâng cấp vào bảo trì
  • Giảm thiểu nguy cơ lỗi

– Nhưng trong thực tế vẫn có những thay đổi mà Repository Design Pattern cơ bản đó không giải quyết được.Trong những hệ thống CMS hoặc những bộ core cho những website lớn nhiều module những người Team leader hoặc người viết core họ luôn đặt ra những yêu cầu xa hơn 1 chút và việc cần phải thay đổi sang 1 mẫu thiết kế mới là điều tất yếu.Chúng ta hãy cùng tới bài toán cụ thể sau đây nhé.

Bài toán cụ thể trong ứng dụng

– Ví dụ tôi đang làm 1 hệ thống cho phép thành viên viết bài post của họ lên website,ví dụ như table posts trong bài trước.
– Mọi thứ đều tốt đẹp khi đang sử dụng mẫu thiết kế Repository trên.Một thời gian sau hệ thống của tôi có quá nhiều thao tác liên quan tới việc thêm,sửa xóa dữ liệu, cần độ chịu tải cao,mà website của tôi lại không cần các giàng buộc giữ liệu giữa các table hoặc không cần sử dụng Transaction,chính vì vậy khách hàng yêu cầu chuyển đổi sang dùng CSDL NoSQL MongoDB.Toi rồi, lúc này hệ thống của ta đang sử dụng mẫu Repository trên Eloquent ,chả lẽ lúc này vào tất cả các Repository thay đổi lại hết sao? thôi đành phải vậy, cứ coi như bạn đã vào hết các Repository thay đổi lại hết để có thể sử dụng thao tác tới CSDL MongoDB đi.
– Bỗng dưng 1 thời gian sau,website phát triển mạnh khách hàng cần thêm các tính năng cộng tiền cho người viết bài, các thành viên có thể chuyển tiền cho nhau và rút tiền…cần thực hiện nhiều Transaction và lại muốn quay trở lại Mysql.Hình như khách hàng này đang muốn troll mình thì phải :D.Lúc này lại quay lại sửa hết Repository sao?
– Ở trên chỉ là 1 ví dụ cụ thể thôi, trong thực tế có nhiều khách hàng hoặc những yêu cầu thay đổi thực sự ta không thể lường trước được.
– Yêu cầu đặt ra ở đây chúng ta cần xây dựng lại Repository Design Pattern để khi thay đổi sang 1 CSDL khác thì việc đó cũng sẽ thực hiện rất nhanh, hoặc muốn quay trờ về CSDL thì chỉ việc sửa trong 1 nốt nhạc.

Xây dựng Repository Design Pattern với Interface trong Laravel

– Chú ý đây là phần khá trừu tượng loằng ngoằng và hơi khó hiểu đối với những bạn chưa quen thiết lập các Interface Abstract.
– Để xây dựng 1 mẫu Design Pattern thì thường chúng ta sẽ mất khá nhiều thời gian ban đầu nhưng nó sẽ có rất nhiều tác dụng cho cả hệ thống sau này.Để xây dựng được mẫu này các bạn cần nắm vững lập trình hướng đối tượng (OOP) và cách sử dụng Abstract Interface
– Trước tiên ta sẽ chỉnh sửa lại cấu trúc thư mục như sau.

Cấu trúc thư mục Repositories

Cấu trúc thư mục Repositories

Cấu trúc thư mục Repositories

  • Repositories: là thư mục chưa toàn bộ Repository của hệ thống
  • Repositories/Eloquent: là thư mục chưa toàn bộ Repository sử dụng Eloquent
  • Repositories/MongoDB: là thư mục chưa toàn bộ Repository sử dụng MongoDB,tất nhiên khi triển khai thư mục này thì bạn phải biết MongoDB hoặc tích hợp ORM hỗ trợ cho việc truy vấn MongoDB nhé, trong bài viết này mình sẽ chỉ trình bày về Eloquent

– Trước tiên ta xây dựng file BaseRepositoryInterface.php:

<?php
namespace App\Repositories;
/**
 * Interface CoreRepository
 * @package App\Repositories
 */
interface BaseRepositoryInterface
{
    /**
     * @param  int $id
     * @return $model
     */
    public function find($id);

    /**
     * Return a collection of all elements of the resource
     */
    public function all();

    /**
     * Create a resource
     * @param  $data
     * @return $model
     */
    public function create($data);

    /**
     * Update a resource
     * @param  $model
     * @param  array $data
     * @return $model
     */
    public function update($model, $data);
    ......

File này là 1 interface xây dựng lên các hàm mà hay được sử dụng để EloquentBaseRepository MongoDBBaseRepository implements vào.Tất nhiên khi xây dựng hệ thống thế này thì chúng ta cần phải đưa ra 1 khuân mẫu các phương thức chung để bắt các lớp Base Repository phải implements theo,không cần biết trong Base Repository xử lý thế nào nhưng cần có những phương thức chung như thế.
– Trong file EloquentBaseRepository ta xây dựng implements từ interface BaseRepositoryInterface:

<?php

namespace App\Repositories\Eloquent;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use App\Repositories\BaseRepositoryInterface;

/**
 * Class EloquentBaseRepository
 */
abstract class EloquentBaseRepository implements BaseRepositoryInterface
{
     /**
     * @var \Illuminate\Database\Eloquent\Model An instance of the Eloquent Model
     */
    protected $model;

    /**
     * @param Model $model
     */
    public function __construct()
    {
        $this->getModel();
    }
    
    /**
     * @get Model
     */
    abstract function setModel();
    
    /**
     * @set Model
     */
    private function getModel()
    {
    	$model = $this->setModel();
    	$this->model = app()->make($model);
    }
    
    /**
     * @inheritdoc
     */
    public function find($id)
    {
       
        return $this->model->find($id);
    }

    /**
     * @inheritdoc
     */
    public function all()
    { 
        return $this->model->all();
    }

    /**
     * @inheritdoc
     */
    public function create($data)
    {
        return $this->model->create($data);
    }

    /**
     * @inheritdoc
     */
    public function update($model, $data)
    {
        $model->update($data);

        return $model;
    }

Đây là 1 abstract implements từ BaseRepositoryInterface lên nó phải viết lại tất cả các phương thức từ Interface đó.Tất cả các Reposity khác sử dụng Eloquent đều phải extends từ Class này.Trong đây có 2 điều chú ý:

  1. protected $model: đây là biến sẽ lưu 1 instance Eloquent Model
  2. abstract function setModel(): Ở đây ta sẽ trả về 1 Class Model tương ứng muốn sử dụng, lát xem trong EloquentPostRepository triển khai phương thức này sẽ rõ nó trả về gì

– Ok như vậy cũng tạm ổn khi xây dựng xong phần Base Repository rồi, chúng ta quay trở lại với bảng posts như bài trước, lúc này chúng ta sẽ triển khai 1 Interface PostRepositoryInterface.php như sau:

<?php
namespace App\Repositories;
interface PostRepositoryInterface
{
    /**
     * Lấy danh sách các post đã active
     * @return object
     */
    public function allActive();
}

– Mục đích của mình đó là các Repository post sử dụng Eloquent hay MongoDB đều kế thừa từ Interface này và phải viết lại hàm allActive để lấy ra các posts đã được kích hoạt cho phép hiển thị.
– Tiếp theo ta sẽ triển khai EloquentPostRepository.php như sau:

<?php
namespace App\Repositories\Eloquent;
use Illuminate\Database\Eloquent\Builder;
use App\Repositories\Eloquent\EloquentBaseRepository;
use App\Repositories\PostRepositoryInterface;
use App\Post;
class EloquentPostRepository extends EloquentBaseRepository implements PostRepositoryInterface
{
     /**
      * Khai báo Model
      */
      public function setModel()
      {
		return Post::class;
      }
	
    /**
     * Lấy danh sách các post đã active
     * @return object
     */
    public function allActive()
    {
        return $this->model->where('status', 1)->get();
    }
}

– Lớp này kế thừa từ Abstract EloquentBaseRepository lên nó sẽ viết lại hàm setModel,và nó lại implements từ PostRepositoryInterface lên nó cần viết lại hàm allActive để lấy ra các post đã active theo Eloquent.
– Lúc này chúng ta sẽ nhờ vào Service Container trong Laravel để có thể binding một interface vào một đối tượng implement nó,ta vào file App\Providers\AppServiceProvider.php khai báo như sau:

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    	$this->app->bind(
    			'App\Repositories\PostRepositoryInterface',
    			'App\Repositories\Eloquent\EloquentPostRepository'
    	);
    }

Ở trên chúng ta đang binding PostRepositoryInterface với implement là EloquentPostRepository
– Tiếp theo triển trai trong PostController như sau:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;

use App\Repositories\PostRepositoryInterface;

class PostController extends Controller
{
    protected $postRepository  = '';
    public function __construct(PostRepositoryInterface $PostRepositoryInterface)
    {
         $this->postRepository = $PostRepositoryInterface;
    }
 
     /**
     * Lấy danh sách post
     */
    function all()
    {
         $list = $this->postRepository->allActive();
         return $list; 
    }
}

Ở trên chúng ta chỉ cần inject PostRepositoryInterface vào để sử dụng mà không cần thực hiện inject EloquentPostRepository.Như vậy khi có thay đổi muốn sử dụng sang MongoDB thì chúng ta chỉ việc sửa duy nhất trong phần binding AppServiceProvider,ví dụ:

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    	$this->app->bind(
    			'App\Repositories\PostRepositoryInterface',
    			'App\Repositories\MongoDB\MongoDBPostRepository'
    	);
    }

– Ok như vậy là xong, chỉ cần sửa trong 1 nốt nhạc phải không nào.

Kêt thúc

– Qua bài này mình đã giới thiệu cho các bạn cách xây dựng Repository Design Pattern với Interface trong Laravel.Với cách triển khai có vẻ khá mất công nhưng nó sẽ giúp ích bạn rất nhiều.Chúc các bạn có thể triển khai mô hình Repository theo cấu trúc của riêng mình và cảm thấy dễ hiểu nhất.



13/02/2017
Written by admin

Hiện do a Tuyền (nguyên adminsite hocphp.info) không còn thời gian để phát triển site, nên do có cơ duyên và được a tin tưởng để cho mình tiếp tục phát triển. Hi vọng mọi người cùng nhau phát triển và chia sẽ nhiều hơn nữa, ngoài ra mình cũng cố gắng chia sẽ các seri về web cũng như các ngôn ngữ khác chất nhất có thể. có gì thiếu sót hi vọng mọi người bỏ qua.

Bài viết chùng chuyên mục

Gửi bình luận

Giới thiệu

Mình tạo ra blog này với mong muốn chia sẻ và học hỏi kinh nghiệm trong quá trình thiết kế website. Website đang trong quá trình phát triển chân thành cảm ơn mọi sự góp ý của các bạn để làm cho website ngày càng hoàn thiên.

DMCA.com Protection Status
Liên hệ
Theo dõi qua Email

Tổng hợp các bài viết về

Hoc php - CodeIgniter Framework - Laravel Framework - PHP va MYSQL