推薦:好用的 Laravel Repository 包

hiword發表於2018-07-04

什麼是Repository模式,如何使用Repository模式

這裡就不再囉嗦了,請參見以下幾個連結
如何使用 Repository 模式?
關於 Repository 的設計模式
laravel-china.org搜尋

我的使用歷程

原由

MVC在如今仍然是流行趨勢,但多數框架都只提供基礎的MVC架構。
幾年前在開發中我們經常會遇到問題Model過於臃腫,寫著寫著就會變成類似於萬能類,最後面的人就真成了接盤俠了。
很不幸我就是其中之一。後來我就一直在思考如何才能讓Model看起來清爽,功能更加單一簡潔。(當時並不知道Repository),終於開始重構。一把心酸淚。。。。。最多的是組合和Trait

使用Laravel

最開始接觸Laravel就是感覺它的文件清爽,以為是個簡單的框架,結果不小心一入坑,才發現被它的外表給欺騙了。
但卻也為此深深愛上了它,是啊,這不就是我一直追求的嗎?無限的靈活性,可替換,越研究程式碼越發現處處都是精髓。
但在Laravel中也不可避免的基礎MVC模式,上述問題仍然存在。

初期使用

一直以為我都遵循一個核心:以倉庫層為處理資料基礎,為SerivceController等提供資料供給,倉庫需要的原始資料則通過Model中獲取。這樣可以完全分離ModelController的依賴。
最開始在Laravel中使用是通過定義大量的RepositoryInterface來注入,bind,實現具體的Repository工作類。
這是理想的使用方法可替換性很強。

遇到的問題

  • 實際開發過程中Repository基本不會被替換,無數的Interface帶來的規範,也帶來了開發的麻煩。
  • 在使用Repository模式中我們不斷的注入Model,每個方法都需要直接Model來進行一次次的查詢資料集,卻失去了在外層鏈式呼叫的便捷性(這其實並不合理,但存在即有原由)。

中間的折中

後來索性在開發中我們去掉了Interface的約束,直接作用功能類來注入使用,此時簡潔性和便捷性大大的提高,如果非要替換仍然bind可以解決問題。這樣的開始一直持續很長時間。但是像連結呼叫仍然沒有解決,為些我們開發出了新的倉庫包。https://github.com/crcms/repository

再次輪迴

開始玩微服務,開始分離程式碼,當然就離不開RPC,十分慶幸我們使用了Repository模式,通過開啟對應的Rpc Repository,我們可以很快進行本地Repository切換,以Interface來約束。

便捷的Repository包

基礎示例

class TestRepository extends AbstractRepository
{
    /**
     * @var array
     */
    protected $guard = [
        'id', 'title','other'
    ];

    /**
     * @return TestModel
     */
    public function newModel(): TestModel
    {
        return app(TestModel::class);
    }

    /**
     * @param int $perPage
     * @return LengthAwarePaginator
     */
    public function paginate(AbstractMagic $magic = null, int $perPage = 15): LengthAwarePaginator
    {
        $query = $this->where('built_in', 1);

        if ($magic) {
            $query->magic($magic);
        }

        return $query->orderBy($this->getModel()->getKeyName(), 'desc')->paginate($perPage);
    }

    /**
     * @param int $name
     * @param int $title
     */
    public function updateName(string $name, string $title)
    {
        $this->getModel()->where('name', $name)->update(['title' => $title]);
    }

}

超好用的Magic方法

在多條件搜尋中,肯定會存在大量的判斷,優雅度太低,如:

if($request->input('username')) {
    $query->where('username',$username)
}

if($request->input('email')) {
    $query->where('email',$email)
}

.......

但通過QueryMagic方法我們可以輕鬆優雅解決這些問題,示例:

建立Magic

use CrCms\Repository\AbstractMagic;
use CrCms\Repository\Contracts\QueryRelate;

class TestMagic extends AbstractMagic
{
    /**
     * @param QueryRelate $queryRelate
     * @param int $id
     * @return QueryRelate
     */
    protected function byName(QueryRelate $queryRelate, string $name)
    {
        return $queryRelate->where('name', $name);
    }

    /**
     * @param QueryRelate $queryRelate
     * @param string $title
     * @return QueryRelate
     */
    protected function byTitle(QueryRelate $queryRelate, string $title)
    {
        return $queryRelate->where('title', 'like', "%{$title}%");
    }

    /**
     * @param QueryRelate $queryRelate
     * @param int $id
     * @return QueryRelate
     */
    protected function byId(QueryRelate $queryRelate, int $id)
    {
        return $queryRelate->where('id', $id);
    }
}

使用Magic(這裡只是簡單示例):

    public function paginate(array $condition, int $perPage = 15): LengthAwarePaginator
    {
        return $query->magic(new TestMagic($condition))->orderBy($this->getModel()->getKeyName(), 'desc')->paginate($perPage);
    }

更多

開發此包的原因是在這之前我並示找到我想要的(適合我的)兼具Model的靈活性以及資料倉儲的分離模式,所以為此開發了這個倉庫包。目前此包已經使用在好幾個專案中目前執行良好。
後面還打算相容TP以及Yii等使用率高的框架,暫時只支援Laravel
更多詳情,請移步github:https://github.com/crcms/repository

最後

哈哈,請原諒我著急的文字描述,希望對需要的人以及面臨和我曾經一樣困惑的人有所幫助。
原文出處:crcms-blog

相關文章