2014-11-04 116 views
6

最近我開始研究Laravel 4及其功能。我想實現Repository模式以在那裏移動模型邏輯。在這一點上,我面臨着一些如何組織它的不便或誤解。一般問題我有這樣的事情:是否有可能實現和應用這種模式在Laravel沒有頭痛,並且它是否值得使用Laravel實現庫模式

這個問題會被分成幾個部分,這引起了我的困惑。

1)Laravel提供了將模型綁定爲控制器參數的方便方式,例如,我做這種方式:

// routes.php 
Route::bind('article', function($slug) 
{ 
    return Article::where('slug', $slug)->first(); 
}); 

Route::get('articles/{article}', '[email protected]'); 

// controllers/ArticlesController.php 
class ArticlesController extends BaseController { 

    public function getArticle(Article $article) 
    { 
     return View::make('article.show', compact('article')); 
    } 
} 

如果我想使用Repository模式,那麼我不能使用這種方法,因爲在這種情況下,控制器將清楚地瞭解車型Article存在? 無論將是正確的重新寫該示例中使用Repository模式這樣

// routes.php 
Route::get('articles/{slug}', '[email protected]'); 

// controllers/ArticlesController.php 
class ArticlesController extends BaseController { 

    private $article; 

    public function __construct(ArticleRepository $article) { 
     $this->article = $article; 
    } 

    public function getArticle($slug) 
    { 
     $article = $this->article->findBySlug($slug); 

     return View::make('article.show', compact('article')); 
    } 
} 

2)假設,我的代碼與上面使用的Repository是正確的。現在,我想在每次顯示文章視圖計數器時增加文章視圖,但是,我想在Event中進行此處理。也就是說,代碼如下:

// routes.php 
Route::get('articles/{slug}', '[email protected]'); 

// controllers/ArticlesController.php 
class ArticlesController extends BaseController { 

    private $article; 

    public function __construct(ArticleRepository $article) { 
     $this->article = $article; 
    } 

    public function getArticle($slug) 
    { 
     $article = $this->article->findBySlug($slug); 
     Events::fire('article.shown'); 

     return View::make('articles.single', compact('article')); 
    } 
} 

// some event subscriber 
class ArticleSubscriber { 

    public function onShown() 
    { 
     // why implementation is missed described bellow 
    } 

    public function subscribe($events) 
    { 
     $events->listen('article.shown', '[email protected]'); 
    } 

} 

在這一點上我再次對如何實現事件處理感到困惑。我無法直接將$article模型傳遞給事件,因爲它再次違反了OOP的原則,我的訂閱者將知道文章模型的存在。所以,我不能這樣做:

// controllers/ArticlesController.php 
... 
\Events::fire('article.shown', $article); 
... 

// some event subscriber 
... 
public function onShown(Article $article) 
{ 
    $article->increment('views'); 
} 
... 

在另一方面,我沒有看到任何意義,引入subscriberArticleRepository(或用戶的構造器注入的話),因爲首先我應該找一個文章,然後更新計數器,最終,我會得到額外的查詢(在構造函數之前,因爲我這樣做)到數據庫:

// controllers/ArticlesController.php 
... 
Events::fire('article.shown', $slug); 
... 

// some event subscriber 
... 
private $article; 

public function __construct(ArticleRepository $articleRepository) 
{ 
    $this->article = $articleRepository; 
} 

public function onShown($slug) 
{ 
    $article = $this->articleRepository->findBySlug($slug); 
    $article->increment('views'); 
} 
... 

此外,處理的Event後(即增加的觀看次數) ,控制器必須知道更新的模型,因爲在視圖中我想顯示更新的視圖計數器。事實證明,我仍然需要從Event返回一個新的模型,但我不想Event已成爲處理特定操作(爲此有存儲庫),並返回一些價值的常見方法。此外,您可能會注意到我的最後onShow()方法再次違背Repository模式的規則,但我不知道如何把這個邏輯到倉庫:

public function onShown($slug) 
{ 
    $article = $this->articleRepository->findBySlug($slug); 
    // INCORRECT! because the Event shouldn't know that the model is able to implement Eloquent 
    // $article->increment('views'); 
} 

我可以以某種方式通過發現模型回到倉庫並增加她的櫃檯(這與Repository模式的方法相矛盾嗎?)?事情是這樣的:

public function onShown($slug) 
{ 
    $article = $this->articleRepository->findBySlug($slug); 
    $this->articleRepository->updateViews($article); 
} 

// ArticleRepository.php 
... 
public function updateViews(Article $article) { 
    $article->increment('views'); 
} 
... 

結果,我會盡量制定所有更緊湊:

  1. 我不得不拒絕直接傳遞模型,由DI提供的控制器和其他設施如果我將使用Repository模式?

  2. 是否可以使用存儲庫來存放模型的狀態,並通過它的實體之間(例如,從過濾器控制器從控制器到Event和背面)避免淫穢重複調用數據庫,是這方法將是正確的(模型持久性)?

這樣的事情,這些是我的問題。我想聽聽答案,想法和意見。也許,我應用模式的方法不正確?現在它比解決數據映射問題更令人頭疼。

此外,我讀過有關倉庫實現的一些文章:

  1. http://heera.it/laravel-repository-pattern#.VFaKu8lIRLe
  2. http://vegibit.com/laravel-repository-pattern

,但它並沒有解決我的誤解

回答

0

Repository模式有它的優點和缺點。

從我比較最近通過它允許一個更容易的測試經驗的格局 - 尤其是在繼承和多態的利用。

下面是一個近乎包羅萬象的信息庫我使用合同的摘錄。

interface EntityRepository 
{ 
    /** 
    * @param $id 
    * @return array 
    */ 
    public function getById($id); 

    /** 
    * @return array 
    */ 
    public function getAll(); 

    /** 
    * @param array $attr 
    * @return array 
    */ 
    public function save(array $attr); 

    /** 
    * @param $id 
    */ 
    public function delete($id); 

    /** 
    * Checks if a record with the given values exists 
    * @param array $attr 
    * @return bool 
    */ 
    public function exists(array $attr); 

    /** 
    * Checks if any records with any of these values exists and returns true or false 
    * @param array $attr 
    * @return bool 
    */ 
    public function unique(array $attr); 
} 

該合同是相對言自明,save()同時管理插入和更新實體(型號)。

在這裏,我將創建一個實現所有功能,因爲我要使用的供應商(S)的抽象類 - 如口才或學說。

值得一提的,這個合同不會抓住每一個事情,我目前在建立一個獨立的執行,處理多對多的關係,但這是另一個故事的過程。

要創建我個人倉庫類,這樣做,我創建一個擴展EntityRepositoryContract,並指出哪些功能是獨家他們每個庫另一份合同。在用戶的情況下 - registerUser(...)disableUser(...)等等等等

最後的班會再延長EloquentEntityRepository和實施信息庫中的相關合同。對於EloquentUserRepository類簽名將一些事情,如:

class EloquentUserRepository extends EloquentEntityRepository implements UserRepositoryContract 
{ 
... 
} 

在我自己的實現,使類的名字更簡潔一些我利用名稱空間別名,像這樣每個實現:

use Repo\Eloquent\UserRepo; //For the Eloquent implementation 
use Repo\Doctrine\UserRepo; //For the Doctrine implementation 

我儘量不到一堆我所有的存儲庫一起,而不是按功能我的應用程序,以保持我的目錄結構更簡潔。

我跳過了對很多細節,但我不想拋出太多所以用繼承和多態實驗,看看有什麼可以實現與庫一個更好的工作流程。

從我目前的工作流程,我的測試中都有自己的抽象類專門爲所有的實體倉庫實施使得前幾個障礙後測試輕而易舉基礎信息庫的合同。

祝你好運!

0

它工作正常!

api.php

Route::get('/articles/{article}', '[email protected]')->middleware('can:get,article'); 

ArticleController.php

class ArticleController extends BaseController { 

    protected $repo; 

    public function __construct(ArticleRepository $repository) { 

     $this->repo = $repository; 
    } 

    public function getArticle(int $id) 
    { 
     $articleRepo = $this->repo->find($id); 
     return View::make('article.show', compact('articleRepo')); 
    } 
}