Repository Pattern trong Laravel-Phần 2

repository thông qua interface
Ở trên chúng ta đã áp dụng repository cơ bản rồi. Tuy nhiên, khi join vào 1 dự án lớn có nhiều người làm việc. Việc áp dụng interface để đảm bảo code chuẩn theo thiết kế cũng như dễ dàng thay đổi, maintain dễ dàng là điều cần thiết.
Quay trở lại class EloquentRepository, Việc cần làm trước khi xây dựng class EloquentRepository đó là tạo ra 1 bản thiết kế. Đó là 1 interface mình đặt tên là RepositoryInterface
Tạo file trong thư mục App\Repositories:

<?php

namespace App\Repositories;

interface RepositoryInterface
{
    /**
     * Get all
     * @return mixed
     */
    public function getAll();

    /**
     * Get one
     * @param $id
     * @return mixed
     */
    public function find($id);

    /**
     * Create
     * @param array $attributes
     * @return mixed
     */
    public function create(array $attributes);

    /**
     * Update
     * @param $id
     * @param array $attributes
     * @return mixed
     */
    public function update($id, array $attributes);

    /**
     * Delete
     * @param $id
     * @return mixed
     */
    public function delete($id);
}

Đây là khung của EloquentRepository. Trong class EloquentRepository chúng ta sẽ implements RepositoryInterface. Chỉnh lại code trong class EloquentRepository 1 tí nào.

<?php

namespace App\Repositories;

use App\Repositories\RepositoryInterface;

abstract class EloquentRepository implements RepositoryInterface
{
    /**
     * @var \Illuminate\Database\Eloquent\Model
     */
    protected $_model;

    /**
     * EloquentRepository constructor.
     */
    public function __construct()
    {
        $this->setModel();
    }

    /**
     * get model
     * @return string
     */
    abstract public function getModel();

    /**
     * Set model
     */
    public function setModel()
    {
        $this->_model = app()->make(
            $this->getModel()
        );
    }

    /**
     * Get All
     * @return \Illuminate\Database\Eloquent\Collection|static[]
     */
    public function getAll()
    {

        return $this->_model->all();
    }

    /**
     * Get one
     * @param $id
     * @return mixed
     */
    public function find($id)
    {
        $result = $this->_model->find($id);

        return $result;
    }

    /**
     * Create
     * @param array $attributes
     * @return mixed
     */
    public function create(array $attributes)
    {

        return $this->_model->create($attributes);
    }

    /**
     * Update
     * @param $id
     * @param array $attributes
     * @return bool|mixed
     */
    public function update($id, array $attributes)
    {
        $result = $this->find($id);
        if ($result) {
            $result->update($attributes);
            return $result;
        }

        return false;
    }

    /**
     * Delete
     *
     * @param $id
     * @return bool
     */
    public function delete($id)
    {
        $result = $this->find($id);
        if ($result) {
            $result->delete();

            return true;
        }

        return false;
    }

}

Chúng ta sẽ thiết kế thêm chức năng riêng cho class PostEloquentRepository. Ví dụ ở đây mình muốn thêm 1 method lấy 5 post nhiều lượt xem nhất trong vòng 1 tháng chẳng hạn. Chúng ta sẽ tạo ra 1 bản thiết kế cho PostEloquentRepository. Mình đặt tên là PostRepositoryInterface tạo trong thư mục App\Repositories\Post

<?php
namespace App\Repositories\Post;

interface PostRepositoryInterface
{
    /**
     * Get 5 posts hot in a month the last
     * @return mixed
     */
    public function getPostHot();
}

Ở bên PostEloquentRepository chúng ta sẽ implements PostRepositoryInterface

<?php
namespace App\Repositories\Post;

use App\Repositories\EloquentRepository;
use Carbon\Carbon;
use App\Post;
class PostEloquentRepository extends EloquentRepository implements PostRepositoryInterface
{
    /**
     * get model
     * @return string
     */
    public function getModel()
    {
        return \App\Post::class;
    }

    /**
     * Get 5 posts hot in a month the last
     * @return mixed
     */
    public function getPostHot()
    {
        return $this->_model->where('created_at', '>=', Carbon::now()->subMonth())->orderBy('view', 'desc')->take(5)->get();
    }

}

Như đã nói ở trên, chúng ta sẽ làm việc thông qua interface. Mà các bạn đã biết chúng ta không thể sử dụng 1 đối tượng là interface. Do đó, chúng ta phải đăng kí với laravel để nó có thể hiểu rằng interface bạn sử dụng là của class cụ thể nào.
Các bán sẽ mở tập tin app/Providers/AppServiceProvider.php và thêm vào method register() như sau:

public function register()
{
    $this->app->singleton(
        \App\Repositories\Post\PostRepositoryInterface::class,
        \App\Repositories\Post\PostEloquentRepository::class
    );
}

Bây giờ thì ta có thể sử dụng PostRepositoryInterface khi này nó sẽ hiểu là bạn sử dụng PostEloquentRepository. Bây giờ trong PostController thay vì inject PostEloquentRepository thì bạn sẽ inject PostRepositoryInterface.

 public function __construct(PostRepositoryInterface $postRepository)
    {
        $this->postRepository = $postRepository;
    }

Contextual Binding
Đôi khi bạn sẽ có 2 class implementaion từ 1 interface, nhưng trong trường hợp này bạn lại muốn inject implementation này và trong trường hợp khác thì bạn lại muốn inject implementaion khác. Khi đó bạn cần đến Contextual Binding. Bây giờ ta có PostRepository thì implementation tương ứng của nó là PostRepositoryEloquent thì trong hàm register() ta sẽ bind như sau :

$this->app->bind(
\App\Contracts\Repositories\PostRepository::class,
\App\Repositories\PostRepositoryEloquent::class,
),
Nhưng bây giờ có thêm implementation NewRepositoryEloquent
==> 1 interface có 2 implementation thì chúng ta sẽ bind như sau :

$this->app->when(\App\Contracts\Repositories\PostRepository::class)
          ->needs(\App\Repositories\PostRepositoryEloquent::class)
          ->give(function () {
              // code
          });

$this->app->when(\App\Contracts\Repositories\PostRepository::class)
          ->needs(\App\Repositories\NewRepositoryEloquent::class)
          ->give(function () {
              // code
          });

Nguồn tham khảo:https://viblo.asia/p/repository-pattern-trong-laravel-gGJ59jPaKX2

0 Shares

Leave a Reply

avatar
  Subscribe  
Notify of