2014-11-04 30 views
6

Gần đây tôi bắt đầu nghiên cứu Laravel 4 và khả năng của nó. Tôi muốn thực hiện mô hình Repository để di chuyển mô hình logic ở đó. Và tại thời điểm này tôi phải đối mặt với một số bất tiện hoặc sự hiểu lầm về cách tổ chức nó. Câu hỏi chung tôi đã đi một cái gì đó như thế này: là nó có thể thực hiện và áp dụng mô hình này trong Laravel mà không đau đầu, và liệu nó có giá trị?Thực hiện mẫu lưu trữ với Laravel

Câu hỏi sẽ được chia thành nhiều phần, điều này gây ra sự nhầm lẫn của tôi.

1) Laravel cung cấp cách thuận tiện để liên kết mô hình dưới dạng thông số bộ điều khiển, ví dụ: tôi làm điều đó theo cách này:

// 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')); 
    } 
} 

Nếu tôi muốn sử dụng mô hình Repository, sau đó tôi không thể sử dụng phương pháp này, vì trong trường hợp này bộ điều khiển sẽ rõ ràng nhận thức được sự tồn tại của mô hình Article? Cho dù đó sẽ được chính xác để viết lại ví dụ này sử dụng mẫu Repository cách này:

// 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) Giả sử, mã của tôi ở trên với việc sử dụng các Repository là đúng. Bây giờ tôi muốn tăng lượt xem bài viết truy cập mỗi lần nó sẽ được hiển thị, tuy nhiên, tôi muốn thực hiện việc xử lý này trong Event. Tức là, mã như sau:

// 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]'); 
    } 

} 

Tại thời điểm này tôi đã bối rối một lần nữa về cách triển khai xử lý sự kiện. Tôi không thể vượt qua mô hình $article trực tiếp cho sự kiện, bởi vì, một lần nữa, nó vi phạm các nguyên tắc của OOP và người đăng ký của tôi sẽ biết về sự tồn tại của mô hình bài viết. Vì vậy, tôi không thể làm như vậy:

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

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

Mặt khác tôi không thấy bất kỳ ý nghĩa để giới thiệu vào subscriber kho ArticleRepository (hoặc tiêm nó trong contructor của thuê bao), bởi vì lần đầu tiên tôi nên tìm một bài viết, và sau đó cập nhật bộ đếm, cuối cùng, tôi sẽ nhận được thêm truy vấn (gây ra trước đó trong constructor tôi làm như vậy) để cơ sở dữ liệu:

// 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'); 
} 
... 

Hơn nữa, sau khi Event xử lý (xem ví dụ tăng đếm) , nó là cần thiết mà bộ điều khiển biết về mô hình cập nhật, bởi vì trong khung nhìn tôi muốn hiển thị các khung nhìn đã cập nhật quầy tính tiền. Nó chỉ ra rằng bằng cách nào đó tôi vẫn cần phải trả lại một mô hình mới từ Event, nhưng tôi không muốn Event đã trở thành một phương pháp phổ biến để xử lý một hành động cụ thể (cho điều này có kho) và trả về một số giá trị. Ngoài ra, bạn có thể nhận thấy rằng onShow() phương pháp cuối cùng của tôi một lần nữa trái với các quy tắc của Repository mẫu, nhưng tôi không hiểu làm thế nào để đưa logic này vào kho:

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'); 
} 

Tôi có thể bằng cách nào đó vượt qua các mô hình tìm thấy trở lại kho lưu trữ và tăng truy cập của cô ấy (nó có mâu thuẫn với cách tiếp cận này để Repository mẫu?)? Something như thế này:

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

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

Kết quả là, tôi sẽ cố gắng để xây dựng tất cả nhỏ gọn hơn:

  1. tôi sẽ phải từ chối để vượt qua mô hình trực tiếp để điều khiển và tiện nghi khác được cung cấp bởi DI , nếu tôi sẽ sử dụng mẫu Repository?

  2. Có thể sử dụng kho lưu trữ để giữ trạng thái của mô hình và vượt qua giữa các thực thể (ví dụ, từ bộ lọc đến bộ điều khiển từ bộ điều khiển đến Event và ngược lại) tránh các cuộc gọi lặp lại tục tĩu đến db và cách tiếp cận sẽ đúng (mô hình kiên trì)?

Những thứ như vậy, đây là những câu hỏi của tôi. Tôi muốn nghe câu trả lời, suy nghĩ, bình luận. Có lẽ, tôi tiếp cận không chính xác để áp dụng các mô hình? Bây giờ nó gây ra nhiều đau đầu hơn là giải quyết vấn đề lập bản đồ dữ liệu.

Ngoài ra tôi đã đọc một số bài viết về thực hiện Repository:

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

nhưng nó không giải quyết hiểu lầm tôi

Trả lời

0

Các mô hình kho đã thật ưu và chống.

Từ việc sử dụng mẫu tương đối gần đây, nó cho phép trải nghiệm thử nghiệm dễ dàng hơn nhiều - đặc biệt khi thừa kế và đa hình được thừa hưởng.

Dưới đây là phần trích dẫn của hợp đồng kho lưu trữ gần hết mà tôi sử dụng.

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); 
} 

Hợp đồng tương đối tự giải thích, save() quản lý cả việc chèn và cập nhật đối tượng (mô hình).

Từ đây tôi sẽ tạo một lớp trừu tượng triển khai tất cả chức năng cho (các) nhà cung cấp mà tôi muốn sử dụng - chẳng hạn như Eloquent hoặc Doctrine. Điều này đáng chú ý, hợp đồng này sẽ không bắt mọi thứ và tôi hiện đang trong quá trình tạo ra một triển khai riêng biệt xử lý nhiều mối quan hệ nhưng đó là một câu chuyện khác.

Để tạo các lớp lưu trữ riêng lẻ, để thực hiện điều đó, tôi tạo một hợp đồng khác cho mỗi kho lưu trữ mở rộng EntityRepositoryContract và nêu rõ chức năng nào dành riêng cho chúng. Trong trường hợp người dùng - registerUser(...)disableUser(...) v.v.

Các lớp cuối cùng sau đó sẽ mở rộng EloquentEntityRepository và triển khai hợp đồng có liên quan cho kho lưu trữ.Chữ ký lớp học cho các EloquentUserRepository sẽ có một số điều như:

class EloquentUserRepository extends EloquentEntityRepository implements UserRepositoryContract 
{ 
... 
} 

Thực hiện của riêng tôi để làm cho tên lớp ít tiết namespace Tôi đòn bẩy để bí danh từng thực hiện như sau:

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

tôi cố gắng không gộp tất cả các kho của tôi lại với nhau và thay vào đó nhóm ứng dụng của tôi theo tính năng để giữ cấu trúc thư mục của tôi ít lộn xộn hơn.

Tôi đang bỏ qua rất nhiều chi tiết nhưng tôi không muốn ném quá nhiều vào để thử nghiệm với tính kế thừa và đa hình để xem những gì bạn có thể đạt được cho luồng công việc tốt hơn với Kho lưu trữ. Với quy trình làm việc hiện tại của tôi, các bài kiểm tra của tôi có các lớp trừu tượng riêng cho hợp đồng kho cơ sở mà tất cả các kho lưu trữ thực thể thực hiện kiểm thử một cách dễ dàng sau vài rào cản đầu tiên.

Chúc bạn may mắn!

0

Nó hoạt động tốt!

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')); 
    } 
} 
Các vấn đề liên quan