Niedawno zacząłem studiować Laravel 4
i jego możliwości. Chcę zaimplementować wzór repozytorium, aby przenieść tam logikę modelu. I w tym momencie spotkałem się z wieloma niedogodnościami lub niezrozumieniem, jak je zorganizować. Ogólne pytanie Mam coś takiego: Czy można wdrożyć i zastosować ten wzór w Laravel
bez bólu głowy i czy jest to warte?Implementacja wzorca repozytoryjnego z Laravelem
Pytanie zostanie podzielone na kilka części, które spowodowały moje zamieszanie.
1) Laravel zapewnia wygodny sposób wiązania modelu jako parametru kontrolera, np. Robię to w ten sposób:
// 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'));
}
}
Jeśli chcę użyć deseniu Repository
, to nie mogę użyć tego podejścia, ponieważ w tym przypadku regulator jasno zdawać sobie sprawę z istnienia modeli Article
? czy będzie to poprawne ponownie napisać ten przykład używając repozytorium wzorzec ten sposób:
// 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) Załóżmy, że mój kod powyżej, z wykorzystaniem Repository
jest poprawna. Teraz chcę zwiększać licznik wyświetleń artykułu za każdym razem, gdy zostanie on wyświetlony, jednak chcę wykonać to przetwarzanie w Event
. Oznacza to, że kod jest następujący:
// 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]');
}
}
W tym momencie ponownie zastanawiałem się, jak zaimplementować przetwarzanie zdarzeń. Nie mogę przekazać modelu $article
bezpośrednio na wydarzenie, ponieważ znowu narusza zasady OOP i mój subskrybent będzie wiedział o istnieniu modelu artykułu. Tak więc, nie mogę zrobić:
// controllers/ArticlesController.php
...
\Events::fire('article.shown', $article);
...
// some event subscriber
...
public function onShown(Article $article)
{
$article->increment('views');
}
...
Z drugiej strony nie widzę żadnego sensu wprowadzać do subscriber
repozytorium ArticleRepository
(lub wstrzyknąć go w contructor abonenta), ponieważ pierwszy powinien się znaleźć artykuł, a następnie zaktualizować licznik, w końcu, ja dostać dodatkowe zapytania (spowodować poprzednio w konstruktorze zrobić to samo) do bazy danych:
// 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');
}
...
Ponadto, po Event
obsługiwane (liczba oznacza wzrost wyświetleń) , konieczne jest, aby kontroler wiedział o zaktualizowanym modelu, ponieważ w widoku chcę wyświetlić zaktualizowane widoki licznik. Okazuje się, że jakoś nadal muszę zwrócić nowy model z Event
, ale nie chciałbym, aby Event
stał się popularną metodą przetwarzania określonej akcji (dla tego istnieje repozytorium) i zwraca jakąś wartość. Ponadto, można zauważyć, że mój ostatni onShow()
metoda ponownie sprzeczne z zasadami Repository
wzór, ale nie rozumiem, jak umieścić tę logikę do repozytorium:
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');
}
Mogę jakoś przekazać znaleziony modelu wróć do repozytorium i zwiększ jej licznik (czy jest to sprzeczne z tym podejściem do wzoru Repository
?)? coś takiego:
public function onShown($slug)
{
$article = $this->articleRepository->findBySlug($slug);
$this->articleRepository->updateViews($article);
}
// ArticleRepository.php
...
public function updateViews(Article $article) {
$article->increment('views');
}
...
W rezultacie, postaram się sformułować wszystko bardziej kompaktowe:
będę musiał odmówić modele przechodzą bezpośrednio do kontrolera i innych udogodnień przewidzianych przez DI , jeśli użyję wzoru
Repository
?Czy to możliwe, aby korzystać z repozytorium dla utrzymania stanu modelu i przekazać je pomiędzy podmiotami (np z filtra do kontrolera z kontrolera do
Event
iz powrotem) unikając obscenicznych ponawianych wezwań db i jest to podejście będzie poprawne (trwałość modelu)?
Takie rzeczy, to są moje pytania. Chciałbym usłyszeć odpowiedzi, myśli, komentarze. Może, niewłaściwe podejście do zastosowania wzoru? Teraz powoduje więcej bólów głowy niż rozwiązuje problem mapowania danych.
Również czytałem kilka artykułów na temat repozytorium realizacji:
- http://heera.it/laravel-repository-pattern#.VFaKu8lIRLe
- http://vegibit.com/laravel-repository-pattern
ale to nie rozwiąże mój nieporozumienie