/ / Laravel Framework / Comments (3)

Laravel framework – Repository Design Pattern cơ bản

Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về 1 Design Pattern rất hữu ích và được sử dụng rất nhiều đó chính là Repository Design Pattern.Thực ra thì các Design Pattern nó không phụ thuộc vào bạn sử dụng ngôn ngữ nào hay framework nào cả. Quy mô bài này mình sẽ giới thiệu các vấn đề sau:

  1. Design Pattern là gì?
  2. Repository Pattern là gì?
  3. Bài toán cụ thể trong ứng dụng
  4. Xây dựng Repository cơ bản trong Laravel

Design Pattern là gì?

Trước tiên chúng ta sẽ đi thoáng qua 1 chút về lý thuyết về Design Pattern là gì.
– Design Pattern là một kỹ thuật trong lập trình hướng đối tượng, nó không phải là ngôn ngữ lập trình
– Nó sẽ cung cấp cho chúng ta các “mẫu thiết kế”, giải pháp để giải quyết các vấn đề chung, thường gặp trong lập trình
– Design Pattern 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ì.
– Hiện nay hầu như các PHP Framework đều có sử dụng nhữ kiến trúc design pattern có sẵn và mỗi Framwork sẽ có những kiểu design partern riêng.
– Để có thể học Design Pattern bạn cần có nền tảng lập trình hướng đối tượng (OOP) tôt, sử dụng thành thạo interface và abstract.

Repository Pattern là gì?

Repository Design Pattern

Repository Design Pattern


– Repository Pattern là một lớp nằm giữa business logic và data source.
– Tránh việc viết lại code và giảm nguy cơ lỗi nhiều hơn.
– Nó là nơi chứa các logic truy cập dữ liệu chính vì thế business logic có thể lấy dữ liệu mà không cần biết dữ liệu được thiết kế thế nào.
– Repository Pattern giúp cho việc test code trở nên dễ dàng hơn rất nhiều.
– Dễ dàng mở rộng, nâng cấp vào bảo trì.

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

– Phiên bản Laravel tôi đang sử dung là 5.4.Để phục vụ cho bài viết mình sẽ tạo ra table posts.
– Trước tiên tôi tạo 1 Model post

php artisan make:model Post --migration

– Trong file migration posts tôi có:

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slug');
            $table->text('content');
            $table->boolean('status')->default(1);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

– Tiếp đó tôi thực hiện chạy migration:

php artisan migrate

Chú ý khi chạy migrate trên laravel 5.4 mà bị lỗi:

[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key
length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))

thì hãy vào file app/Providers/AppServiceProvider.php sửa như sau:

use Illuminate\Support\Facades\Schema;
function boot()
{
    Schema::defaultStringLength(191);
}

– Còn đây là Post Model:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    protected $fillable = [
         'name', 'slug', 'content', 'status'
    ];
}

– Tiếp theo mình tạo 1 controller Post:

php artisan make:controller PostController

– Trong controller này mình sẽ thực hiện viết hàm lấy toàn bộ danh sách bài post:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class PostController extends Controller
{    
     /**
     * Lấy danh sách post
     */
    function all()
    {
         $list = Post::all();
         return $list;
    }
}

– Thêm vào routes:

Route::get('bai-viet', [
        'uses' => 'PostController@all',
        'as' => 'homepost',
]);

– Nhìn vào đoạn code trong controller thì hoàn toàn ok đúng không nào.Vào một ngày đẹp trời khách hàng yêu cầu những chỗ lấy danh sách post thì thêm điều kiện là admin phải duyệt post (admin có thể bật tắt hiển thị các post ra trang người dùng).Ok thôi, cái này đơn giản mà chúng ta sẽ vào controller sửa thêm điều kiện cho nó là được,và hàm all của chúng ta sẽ sửa lại là:

     /**
     * Lấy danh sách post
     */
    function all()
    {
         $list = Post::where('status', '=' , 1)->get();
         return $list;  
    }

– Như vậy là xong rồi đúng không, nhưng nếu dự án của các bạn có rất nhiều nơi gọi hàm này để lấy toàn bộ danh sách bài post, chả lẽ ta lại phải tìm tất cả những chỗ đó để sửa lại? rất bất tiện phải không nào.Chính vì vậy yêu cầu đặt ra chúng ta cần xây dựng 1 lớp trung gian giữa Controller Model để xử lý dữ liệu, từ đây controller chỉ việc gọi ra từ lớp này mà không cần biết dữ liệu ở đây cần xử lý những gì.

Xây dựng Repository cơ bản trong Laravel

Trước tiên trong thư mục app các bạn tạo thêm 1 thư mục Repositories để chứa các Repository trong dự án.Trong thư mục này ta sẽ tạo Repository cho Post có tên là PostRepository:

<?php
// app/Repositories/PostRepository.php
namespace App\Repositories;
use App\Post;
class PostRepository
{
    public function all()
    {
        return Post::all();
    }
    public function find($id)
    {
        return Post::find($id);
    }
}

PostRepository có nhiệm vụ thao tác với Model, và những chỗ cần lấy dữ liệu sẽ gọi từ PostRepository này mà không gọi trực tiếp trong Model nữa,ví dụ trong PostController ta sẽ sửa lại như sau:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Repositories\PostRepository;
class PostController extends Controller
{
	protected $postRepository  = '';
	public function __construct(PostRepository $PostRepository)
	{
          $this->postRepository = $PostRepository;
	}

	 /**
     * Lấy danh sách post
     */
    function all()
    {
         $list = $this->postRepository->all();
         return $list;  
    }
}

– Ở trên mình đã dùng kỹ thuật Dependecy Injection(bạn có thể tìm hiểu thêm khái niệm này) để inject PostRepository và khởi tạo giá trị cho thuộc tính protected postRepository.
– Như vậy khi có chỉnh sửa gì ta chỉ việc vào PostRepository để chỉnh sửa, trong khi đó controller chỉ việc gọi lấy dữ liệu không cần quan trong dữ liệu trong đó xử lý thế nào, cấu trúc thế nào cả.
– Với yêu cầu trên ta sẻ sửa lại PostRepository như sau:

<?php
// app/Repositories/PostRepository.php
namespace App\Repositories;
use App\Post;
class PostRepository 
{
    public function all()
    {
        return Post::where('status', '=' , 1)->get();
    }
    public function find($id)
    {
        return Post::find($id);
    }
}

– Nếu sau này có yêu cầu sửa gì thì ta sẽ sửa lại duy nhất 1 lần trong file PostRepository , tất cả những chỗ khác gọi tới không cần quan tâm gì cả.

Kết thúc

– Qua bài này mình đã giới thiệu cho các bạn về Repository Design Pattern và xây dựng 1 Repository cơ bản trong Laravel (thực ra bạn triển khai trên ngôn ngữ nào hay PHP Framework nào cũng tương tự thôi).Tuy nhiên với cách trên nó cũng tồn tại những cái chưa được tối ưu.Thực ra nhiều CMS hay các dự án làm theo team hoặc dự án lớn họ đều xây dựng ra các lớp Repository với cấu trúc khác, nhưng trong bài này mình giới thiệu mẫu cơ bản để các bạn dễ hình dung về Design Pattern này.Mình sẽ thêm 1 bài nữa hướng dẫn Triển khai Repository với Interface trong Laravel ở bài sau nhé.



12/02/2017
Written by nobitacnt

Trong bài viết không tránh khỏi những câu từ chưa chính xác,mong nhận được sự góp ý để website hoàn thiện hơn.Nếu thấy bài viết có ích với bạn hãy like và share để ủng hộ nhé :D.

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

3 Comments

  1. xitrum2406 says:
     /  Reply

    Tại function all(), thay vì mình return $list thì mình return view (‘page’,compact(‘list’)), nhưng khi chạy thì báo lỗi : Call to a member function all() on string, Lỗi này báo ở dòng : $list = $this->postRepository->all();
    Admin có thể giải thích giúp mình ko, cám ơn ad

    • Hoàng văn Tuyền says:
       /  Reply

      bạn đã làm theo từng bước như trên chưa, kiểm tra lại PostRepository và trong controller đã inject PostRepository vào chưa

      • xitrum2406 says:
         /  Reply

        Mình đã làm theo đủ các bước, đã inject PostRepository vào controller, kiểm tra hoài mà vẫn ko biết tại sao

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
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